@thetechfossil/auth2 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -0
- package/dist/index.components.d.ts +62 -0
- package/dist/index.components.js +1757 -0
- package/dist/index.components.js.map +1 -0
- package/dist/index.components.mjs +1747 -0
- package/dist/index.components.mjs.map +1 -0
- package/dist/index.d.ts +228 -0
- package/dist/index.js +1853 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1844 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.next.d.ts +232 -0
- package/dist/index.next.js +2093 -0
- package/dist/index.next.js.map +1 -0
- package/dist/index.next.mjs +2078 -0
- package/dist/index.next.mjs.map +1 -0
- package/dist/index.next.server.d.ts +142 -0
- package/dist/index.next.server.js +442 -0
- package/dist/index.next.server.js.map +1 -0
- package/dist/index.next.server.mjs +433 -0
- package/dist/index.next.server.mjs.map +1 -0
- package/dist/index.node.d.ts +133 -0
- package/dist/index.node.js +381 -0
- package/dist/index.node.js.map +1 -0
- package/dist/index.node.mjs +373 -0
- package/dist/index.node.mjs.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,2093 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var axios = require('axios');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
10
|
+
|
|
11
|
+
// src/core/http-client.ts
|
|
12
|
+
var HttpClient = class {
|
|
13
|
+
constructor(baseUrl, defaultHeaders = {}) {
|
|
14
|
+
this.csrfToken = null;
|
|
15
|
+
this.axiosInstance = axios__default.default.create({
|
|
16
|
+
baseURL: baseUrl.replace(/\/$/, ""),
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
...defaultHeaders
|
|
20
|
+
},
|
|
21
|
+
withCredentials: true,
|
|
22
|
+
// Include cookies for CSRF
|
|
23
|
+
timeout: 3e4
|
|
24
|
+
// 30 second timeout
|
|
25
|
+
});
|
|
26
|
+
this.axiosInstance.interceptors.request.use(
|
|
27
|
+
(config) => {
|
|
28
|
+
if (this.csrfToken && ["post", "put", "delete", "patch"].includes(config.method?.toLowerCase() || "")) {
|
|
29
|
+
config.headers["x-csrf-token"] = this.csrfToken;
|
|
30
|
+
}
|
|
31
|
+
return config;
|
|
32
|
+
},
|
|
33
|
+
(error) => Promise.reject(error)
|
|
34
|
+
);
|
|
35
|
+
this.axiosInstance.interceptors.response.use(
|
|
36
|
+
(response) => response,
|
|
37
|
+
async (error) => {
|
|
38
|
+
const originalRequest = error.config;
|
|
39
|
+
if (error.response?.status === 403 && !originalRequest._retry) {
|
|
40
|
+
originalRequest._retry = true;
|
|
41
|
+
try {
|
|
42
|
+
await this.refreshCsrfToken();
|
|
43
|
+
if (originalRequest.headers) {
|
|
44
|
+
originalRequest.headers["x-csrf-token"] = this.csrfToken;
|
|
45
|
+
}
|
|
46
|
+
return this.axiosInstance(originalRequest);
|
|
47
|
+
} catch (refreshError) {
|
|
48
|
+
return Promise.reject(refreshError);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return Promise.reject(error);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
async get(endpoint, headers) {
|
|
56
|
+
const response = await this.axiosInstance.get(endpoint, { headers });
|
|
57
|
+
return response.data;
|
|
58
|
+
}
|
|
59
|
+
async post(endpoint, data, headers) {
|
|
60
|
+
const response = await this.axiosInstance.post(endpoint, data, { headers });
|
|
61
|
+
return response.data;
|
|
62
|
+
}
|
|
63
|
+
async put(endpoint, data, headers) {
|
|
64
|
+
const response = await this.axiosInstance.put(endpoint, data, { headers });
|
|
65
|
+
return response.data;
|
|
66
|
+
}
|
|
67
|
+
async delete(endpoint, headers) {
|
|
68
|
+
const response = await this.axiosInstance.delete(endpoint, { headers });
|
|
69
|
+
return response.data;
|
|
70
|
+
}
|
|
71
|
+
setAuthToken(token) {
|
|
72
|
+
this.axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
73
|
+
}
|
|
74
|
+
removeAuthToken() {
|
|
75
|
+
delete this.axiosInstance.defaults.headers.common["Authorization"];
|
|
76
|
+
}
|
|
77
|
+
setCsrfToken(token) {
|
|
78
|
+
this.csrfToken = token;
|
|
79
|
+
}
|
|
80
|
+
getCsrfToken() {
|
|
81
|
+
return this.csrfToken;
|
|
82
|
+
}
|
|
83
|
+
removeCsrfToken() {
|
|
84
|
+
this.csrfToken = null;
|
|
85
|
+
}
|
|
86
|
+
async refreshCsrfToken() {
|
|
87
|
+
try {
|
|
88
|
+
const response = await this.axiosInstance.get("/api/v1/auth/csrf-token");
|
|
89
|
+
this.csrfToken = response.data.csrfToken;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error("Failed to refresh CSRF token:", error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/core/auth-service.ts
|
|
98
|
+
var AuthService = class {
|
|
99
|
+
constructor(config) {
|
|
100
|
+
this.token = null;
|
|
101
|
+
this.config = {
|
|
102
|
+
localStorageKey: "auth_token",
|
|
103
|
+
csrfEnabled: true,
|
|
104
|
+
...config
|
|
105
|
+
};
|
|
106
|
+
this.httpClient = new HttpClient(this.config.baseUrl);
|
|
107
|
+
this.loadTokenFromStorage();
|
|
108
|
+
if (this.config.csrfEnabled && typeof window !== "undefined") {
|
|
109
|
+
this.refreshCsrfToken();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
loadTokenFromStorage() {
|
|
113
|
+
if (typeof window !== "undefined" && this.config.localStorageKey) {
|
|
114
|
+
try {
|
|
115
|
+
const token = localStorage.getItem(this.config.localStorageKey);
|
|
116
|
+
if (token) {
|
|
117
|
+
this.token = token;
|
|
118
|
+
this.httpClient.setAuthToken(token);
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.warn("Failed to load token from storage:", error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
saveTokenToStorage(token) {
|
|
126
|
+
if (typeof window !== "undefined" && this.config.localStorageKey) {
|
|
127
|
+
try {
|
|
128
|
+
localStorage.setItem(this.config.localStorageKey, token);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.warn("Failed to save token to storage:", error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
removeTokenFromStorage() {
|
|
135
|
+
if (typeof window !== "undefined" && this.config.localStorageKey) {
|
|
136
|
+
try {
|
|
137
|
+
localStorage.removeItem(this.config.localStorageKey);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.warn("Failed to remove token from storage:", error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
isAuthenticated() {
|
|
144
|
+
return !!this.token;
|
|
145
|
+
}
|
|
146
|
+
getToken() {
|
|
147
|
+
return this.token;
|
|
148
|
+
}
|
|
149
|
+
getCurrentUser() {
|
|
150
|
+
if (!this.token)
|
|
151
|
+
return null;
|
|
152
|
+
try {
|
|
153
|
+
const payload = JSON.parse(atob(this.token.split(".")[1]));
|
|
154
|
+
return payload.user || null;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error("Failed to parse user from token:", error);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// CSRF Token Management
|
|
161
|
+
async refreshCsrfToken() {
|
|
162
|
+
if (!this.config.csrfEnabled)
|
|
163
|
+
return;
|
|
164
|
+
try {
|
|
165
|
+
const response = await this.httpClient.get("/api/v1/auth/csrf-token");
|
|
166
|
+
if (response.csrfToken) {
|
|
167
|
+
this.httpClient.setCsrfToken(response.csrfToken);
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error("Failed to get CSRF token:", error);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
getCsrfToken() {
|
|
174
|
+
return this.httpClient.getCsrfToken();
|
|
175
|
+
}
|
|
176
|
+
// OAuth Methods
|
|
177
|
+
loginWithOAuth(provider) {
|
|
178
|
+
if (typeof window === "undefined") {
|
|
179
|
+
throw new Error("OAuth login is only available in browser environments");
|
|
180
|
+
}
|
|
181
|
+
const oauthUrl = `${this.config.baseUrl}/api/v1/auth/oauth/${provider}`;
|
|
182
|
+
window.location.href = oauthUrl;
|
|
183
|
+
}
|
|
184
|
+
linkOAuthProvider(provider) {
|
|
185
|
+
if (typeof window === "undefined") {
|
|
186
|
+
throw new Error("OAuth linking is only available in browser environments");
|
|
187
|
+
}
|
|
188
|
+
if (!this.token) {
|
|
189
|
+
throw new Error("Must be authenticated to link OAuth provider");
|
|
190
|
+
}
|
|
191
|
+
const linkUrl = `${this.config.baseUrl}/api/v1/auth/oauth/${provider}/link`;
|
|
192
|
+
window.location.href = linkUrl;
|
|
193
|
+
}
|
|
194
|
+
async unlinkOAuthProvider(provider) {
|
|
195
|
+
if (!this.token) {
|
|
196
|
+
throw new Error("Not authenticated");
|
|
197
|
+
}
|
|
198
|
+
const response = await this.httpClient.delete(
|
|
199
|
+
`/api/v1/auth/oauth/${provider}/unlink`
|
|
200
|
+
);
|
|
201
|
+
return response;
|
|
202
|
+
}
|
|
203
|
+
// Standard Auth Methods
|
|
204
|
+
async login(data) {
|
|
205
|
+
const response = await this.httpClient.post("/api/v1/auth/login", data);
|
|
206
|
+
if (response.success && response.token) {
|
|
207
|
+
this.token = response.token;
|
|
208
|
+
this.httpClient.setAuthToken(response.token);
|
|
209
|
+
this.saveTokenToStorage(response.token);
|
|
210
|
+
return response;
|
|
211
|
+
}
|
|
212
|
+
if (response.success && response.message === "OTP sent to your email.") {
|
|
213
|
+
return response;
|
|
214
|
+
}
|
|
215
|
+
if (response.success && response.message === "OTP verified successfully." && response.token) {
|
|
216
|
+
this.token = response.token;
|
|
217
|
+
this.httpClient.setAuthToken(response.token);
|
|
218
|
+
this.saveTokenToStorage(response.token);
|
|
219
|
+
return response;
|
|
220
|
+
}
|
|
221
|
+
throw new Error(response.message || "Login failed");
|
|
222
|
+
}
|
|
223
|
+
async register(data) {
|
|
224
|
+
const registerData = { ...data };
|
|
225
|
+
if (!registerData.frontendBaseUrl && typeof window !== "undefined") {
|
|
226
|
+
registerData.frontendBaseUrl = process.env.FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.REACT_APP_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_APP_URL || window.location.origin;
|
|
227
|
+
}
|
|
228
|
+
const response = await this.httpClient.post("/api/v1/auth/register", registerData);
|
|
229
|
+
if (response.success && response.message === "Registration data saved. Verification email sent. Please check your inbox.") {
|
|
230
|
+
return response;
|
|
231
|
+
}
|
|
232
|
+
throw new Error(response.message || "Registration failed");
|
|
233
|
+
}
|
|
234
|
+
async verify(data) {
|
|
235
|
+
const response = await this.httpClient.post("/api/v1/auth/verify", data);
|
|
236
|
+
if (response.success && response.token) {
|
|
237
|
+
this.token = response.token;
|
|
238
|
+
this.httpClient.setAuthToken(response.token);
|
|
239
|
+
this.saveTokenToStorage(response.token);
|
|
240
|
+
}
|
|
241
|
+
return response;
|
|
242
|
+
}
|
|
243
|
+
async verifyEmailToken(token) {
|
|
244
|
+
const response = await this.httpClient.get(`/api/v1/auth/verify-email?token=${token}`);
|
|
245
|
+
if (response.success && response.token) {
|
|
246
|
+
this.token = response.token;
|
|
247
|
+
this.httpClient.setAuthToken(response.token);
|
|
248
|
+
this.saveTokenToStorage(response.token);
|
|
249
|
+
}
|
|
250
|
+
return response;
|
|
251
|
+
}
|
|
252
|
+
async logout() {
|
|
253
|
+
this.token = null;
|
|
254
|
+
this.httpClient.removeAuthToken();
|
|
255
|
+
this.httpClient.removeCsrfToken();
|
|
256
|
+
this.removeTokenFromStorage();
|
|
257
|
+
}
|
|
258
|
+
async getProfile() {
|
|
259
|
+
if (!this.token) {
|
|
260
|
+
throw new Error("Not authenticated");
|
|
261
|
+
}
|
|
262
|
+
const response = await this.httpClient.get("/api/v1/user/me");
|
|
263
|
+
return response.user;
|
|
264
|
+
}
|
|
265
|
+
async updateProfile(data) {
|
|
266
|
+
if (!this.token) {
|
|
267
|
+
throw new Error("Not authenticated");
|
|
268
|
+
}
|
|
269
|
+
const response = await this.httpClient.post("/api/v1/user/update/user", data);
|
|
270
|
+
if (response.success && response.token) {
|
|
271
|
+
this.token = response.token;
|
|
272
|
+
this.httpClient.setAuthToken(response.token);
|
|
273
|
+
this.saveTokenToStorage(response.token);
|
|
274
|
+
}
|
|
275
|
+
return response;
|
|
276
|
+
}
|
|
277
|
+
async getAllUsers() {
|
|
278
|
+
if (!this.token) {
|
|
279
|
+
throw new Error("Not authenticated");
|
|
280
|
+
}
|
|
281
|
+
const response = await this.httpClient.get("/api/v1/user/all");
|
|
282
|
+
return response.users;
|
|
283
|
+
}
|
|
284
|
+
async getUserById(id) {
|
|
285
|
+
const response = await this.httpClient.get(`/api/v1/user/${id}`);
|
|
286
|
+
return response.user;
|
|
287
|
+
}
|
|
288
|
+
async forgotPassword(email) {
|
|
289
|
+
if (typeof window !== "undefined") {
|
|
290
|
+
process.env.FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.REACT_APP_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_APP_URL || window.location.origin;
|
|
291
|
+
}
|
|
292
|
+
const response = await this.httpClient.post("/api/v1/auth/forgot-password", { email });
|
|
293
|
+
return response;
|
|
294
|
+
}
|
|
295
|
+
async resetPassword(token, password) {
|
|
296
|
+
const response = await this.httpClient.post("/api/v1/auth/reset-password", { token, password });
|
|
297
|
+
return response;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var useAuth = (config) => {
|
|
301
|
+
const [authService] = react.useState(() => new AuthService(config));
|
|
302
|
+
const [user, setUser] = react.useState(null);
|
|
303
|
+
const [isAuthenticated, setIsAuthenticated] = react.useState(false);
|
|
304
|
+
const [loading, setLoading] = react.useState(true);
|
|
305
|
+
const checkAuthStatus = react.useCallback(() => {
|
|
306
|
+
const authenticated = authService.isAuthenticated();
|
|
307
|
+
setIsAuthenticated(authenticated);
|
|
308
|
+
if (authenticated) {
|
|
309
|
+
const currentUser = authService.getCurrentUser();
|
|
310
|
+
setUser(currentUser);
|
|
311
|
+
} else {
|
|
312
|
+
setUser(null);
|
|
313
|
+
}
|
|
314
|
+
setLoading(false);
|
|
315
|
+
}, [authService]);
|
|
316
|
+
react.useEffect(() => {
|
|
317
|
+
checkAuthStatus();
|
|
318
|
+
}, [checkAuthStatus]);
|
|
319
|
+
const register = react.useCallback(async (data) => {
|
|
320
|
+
setLoading(true);
|
|
321
|
+
try {
|
|
322
|
+
const registerData = { ...data };
|
|
323
|
+
if (!registerData.frontendBaseUrl && typeof window !== "undefined") {
|
|
324
|
+
registerData.frontendBaseUrl = process.env.REACT_APP_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_APP_URL || window.location.origin;
|
|
325
|
+
}
|
|
326
|
+
const response = await authService.register(registerData);
|
|
327
|
+
return response;
|
|
328
|
+
} finally {
|
|
329
|
+
setLoading(false);
|
|
330
|
+
}
|
|
331
|
+
}, [authService]);
|
|
332
|
+
const login = react.useCallback(async (data) => {
|
|
333
|
+
setLoading(true);
|
|
334
|
+
try {
|
|
335
|
+
const response = await authService.login(data);
|
|
336
|
+
if (response.success && response.user) {
|
|
337
|
+
setUser(response.user);
|
|
338
|
+
setIsAuthenticated(true);
|
|
339
|
+
}
|
|
340
|
+
return response;
|
|
341
|
+
} finally {
|
|
342
|
+
setLoading(false);
|
|
343
|
+
}
|
|
344
|
+
}, [authService]);
|
|
345
|
+
const verify = react.useCallback(async (data) => {
|
|
346
|
+
setLoading(true);
|
|
347
|
+
try {
|
|
348
|
+
const response = await authService.verify(data);
|
|
349
|
+
if (response.success && response.user) {
|
|
350
|
+
setUser(response.user);
|
|
351
|
+
setIsAuthenticated(true);
|
|
352
|
+
}
|
|
353
|
+
return response;
|
|
354
|
+
} finally {
|
|
355
|
+
setLoading(false);
|
|
356
|
+
}
|
|
357
|
+
}, [authService]);
|
|
358
|
+
const verifyEmailToken = react.useCallback(async (token) => {
|
|
359
|
+
setLoading(true);
|
|
360
|
+
try {
|
|
361
|
+
const response = await authService.verifyEmailToken(token);
|
|
362
|
+
if (response.success && response.user) {
|
|
363
|
+
setUser(response.user);
|
|
364
|
+
setIsAuthenticated(true);
|
|
365
|
+
}
|
|
366
|
+
return response;
|
|
367
|
+
} finally {
|
|
368
|
+
setLoading(false);
|
|
369
|
+
}
|
|
370
|
+
}, [authService]);
|
|
371
|
+
const logout = react.useCallback(async () => {
|
|
372
|
+
setLoading(true);
|
|
373
|
+
try {
|
|
374
|
+
await authService.logout();
|
|
375
|
+
setUser(null);
|
|
376
|
+
setIsAuthenticated(false);
|
|
377
|
+
} finally {
|
|
378
|
+
setLoading(false);
|
|
379
|
+
}
|
|
380
|
+
}, [authService]);
|
|
381
|
+
const updateProfile = react.useCallback(async (data) => {
|
|
382
|
+
setLoading(true);
|
|
383
|
+
try {
|
|
384
|
+
const response = await authService.updateProfile(data);
|
|
385
|
+
if (response.success && response.user) {
|
|
386
|
+
setUser(response.user);
|
|
387
|
+
}
|
|
388
|
+
return response;
|
|
389
|
+
} finally {
|
|
390
|
+
setLoading(false);
|
|
391
|
+
}
|
|
392
|
+
}, [authService]);
|
|
393
|
+
const getProfile = react.useCallback(async () => {
|
|
394
|
+
setLoading(true);
|
|
395
|
+
try {
|
|
396
|
+
const userData = await authService.getProfile();
|
|
397
|
+
setUser(userData);
|
|
398
|
+
return userData;
|
|
399
|
+
} finally {
|
|
400
|
+
setLoading(false);
|
|
401
|
+
}
|
|
402
|
+
}, [authService]);
|
|
403
|
+
const getAllUsers = react.useCallback(async () => {
|
|
404
|
+
setLoading(true);
|
|
405
|
+
try {
|
|
406
|
+
return await authService.getAllUsers();
|
|
407
|
+
} finally {
|
|
408
|
+
setLoading(false);
|
|
409
|
+
}
|
|
410
|
+
}, [authService]);
|
|
411
|
+
const getUserById = react.useCallback(async (id) => {
|
|
412
|
+
setLoading(true);
|
|
413
|
+
try {
|
|
414
|
+
return await authService.getUserById(id);
|
|
415
|
+
} finally {
|
|
416
|
+
setLoading(false);
|
|
417
|
+
}
|
|
418
|
+
}, [authService]);
|
|
419
|
+
return {
|
|
420
|
+
user,
|
|
421
|
+
isAuthenticated,
|
|
422
|
+
loading,
|
|
423
|
+
register,
|
|
424
|
+
login,
|
|
425
|
+
verify,
|
|
426
|
+
verifyEmailToken,
|
|
427
|
+
logout,
|
|
428
|
+
updateProfile,
|
|
429
|
+
getProfile,
|
|
430
|
+
getAllUsers,
|
|
431
|
+
getUserById
|
|
432
|
+
};
|
|
433
|
+
};
|
|
434
|
+
var LoginForm = ({
|
|
435
|
+
onSuccess,
|
|
436
|
+
onLoginSuccess,
|
|
437
|
+
onRegisterClick,
|
|
438
|
+
showRegisterLink = true,
|
|
439
|
+
config,
|
|
440
|
+
oauthProviders = ["google", "github"],
|
|
441
|
+
showOAuthButtons = true
|
|
442
|
+
}) => {
|
|
443
|
+
const [email, setEmail] = react.useState("");
|
|
444
|
+
const [password, setPassword] = react.useState("");
|
|
445
|
+
const [usePassword, setUsePassword] = react.useState(false);
|
|
446
|
+
const [showPassword, setShowPassword] = react.useState(false);
|
|
447
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
448
|
+
const [error, setError] = react.useState(null);
|
|
449
|
+
const [rememberMe, setRememberMe] = react.useState(false);
|
|
450
|
+
const { login } = useAuth({
|
|
451
|
+
baseUrl: config?.baseUrl || (typeof window !== "undefined" ? window.location.origin : "http://localhost:7000")
|
|
452
|
+
});
|
|
453
|
+
const handleSubmit = async (e) => {
|
|
454
|
+
e.preventDefault();
|
|
455
|
+
setIsLoading(true);
|
|
456
|
+
setError(null);
|
|
457
|
+
try {
|
|
458
|
+
let response;
|
|
459
|
+
if (usePassword) {
|
|
460
|
+
response = await login({ email, password });
|
|
461
|
+
} else {
|
|
462
|
+
response = await login({ email });
|
|
463
|
+
}
|
|
464
|
+
if (response.success) {
|
|
465
|
+
onSuccess?.(response);
|
|
466
|
+
if (onLoginSuccess) {
|
|
467
|
+
if (response.message === "OTP sent to your email.") {
|
|
468
|
+
onLoginSuccess(email, true);
|
|
469
|
+
} else if (response.token) {
|
|
470
|
+
onLoginSuccess(email, false);
|
|
471
|
+
} else {
|
|
472
|
+
onLoginSuccess(email, true);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
setError(response.message || "Login failed");
|
|
477
|
+
}
|
|
478
|
+
} catch (err) {
|
|
479
|
+
setError(err instanceof Error ? err.message : "An unknown error occurred");
|
|
480
|
+
} finally {
|
|
481
|
+
setIsLoading(false);
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
const toggleAuthMethod = () => {
|
|
485
|
+
setUsePassword(!usePassword);
|
|
486
|
+
setError(null);
|
|
487
|
+
};
|
|
488
|
+
const togglePasswordVisibility = () => {
|
|
489
|
+
setShowPassword(!showPassword);
|
|
490
|
+
};
|
|
491
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
492
|
+
maxWidth: "400px",
|
|
493
|
+
margin: "0 auto",
|
|
494
|
+
padding: "30px",
|
|
495
|
+
borderRadius: "12px",
|
|
496
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.1)",
|
|
497
|
+
backgroundColor: "#ffffff",
|
|
498
|
+
border: "1px solid #eaeaea"
|
|
499
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: {
|
|
500
|
+
display: "flex",
|
|
501
|
+
flexDirection: "column"
|
|
502
|
+
}, children: [
|
|
503
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
|
|
504
|
+
textAlign: "center",
|
|
505
|
+
marginBottom: "24px",
|
|
506
|
+
color: "#1f2937",
|
|
507
|
+
fontSize: "24px",
|
|
508
|
+
fontWeight: 600
|
|
509
|
+
}, children: usePassword ? "Login with Password" : "Login with OTP" }),
|
|
510
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
511
|
+
padding: "12px 16px",
|
|
512
|
+
marginBottom: "20px",
|
|
513
|
+
backgroundColor: "#f8d7da",
|
|
514
|
+
color: "#721c24",
|
|
515
|
+
border: "1px solid #f5c6cb",
|
|
516
|
+
borderRadius: "8px",
|
|
517
|
+
fontSize: "14px",
|
|
518
|
+
fontWeight: 500
|
|
519
|
+
}, children: error }),
|
|
520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
521
|
+
marginBottom: "20px"
|
|
522
|
+
}, children: [
|
|
523
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", style: {
|
|
524
|
+
display: "block",
|
|
525
|
+
marginBottom: "8px",
|
|
526
|
+
fontWeight: 500,
|
|
527
|
+
color: "#374151",
|
|
528
|
+
fontSize: "14px"
|
|
529
|
+
}, children: "Email:" }),
|
|
530
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
531
|
+
"input",
|
|
532
|
+
{
|
|
533
|
+
id: "email",
|
|
534
|
+
type: "email",
|
|
535
|
+
value: email,
|
|
536
|
+
onChange: (e) => setEmail(e.target.value),
|
|
537
|
+
required: true,
|
|
538
|
+
disabled: isLoading,
|
|
539
|
+
style: {
|
|
540
|
+
width: "100%",
|
|
541
|
+
padding: "12px 16px",
|
|
542
|
+
border: "1px solid #ddd",
|
|
543
|
+
borderRadius: "8px",
|
|
544
|
+
fontSize: "16px",
|
|
545
|
+
boxSizing: "border-box",
|
|
546
|
+
color: "#111827",
|
|
547
|
+
transition: "all 0.2s ease",
|
|
548
|
+
backgroundColor: "#ffffff"
|
|
549
|
+
},
|
|
550
|
+
placeholder: "Enter your email"
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
] }),
|
|
554
|
+
usePassword && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
555
|
+
marginBottom: "20px",
|
|
556
|
+
position: "relative"
|
|
557
|
+
}, children: [
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "login-password", style: {
|
|
559
|
+
display: "block",
|
|
560
|
+
marginBottom: "8px",
|
|
561
|
+
fontWeight: 500,
|
|
562
|
+
color: "#555",
|
|
563
|
+
fontSize: "14px"
|
|
564
|
+
}, children: "Password:" }),
|
|
565
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
566
|
+
"input",
|
|
567
|
+
{
|
|
568
|
+
id: "login-password",
|
|
569
|
+
type: showPassword ? "text" : "password",
|
|
570
|
+
value: password,
|
|
571
|
+
onChange: (e) => setPassword(e.target.value),
|
|
572
|
+
required: true,
|
|
573
|
+
disabled: isLoading,
|
|
574
|
+
style: {
|
|
575
|
+
width: "100%",
|
|
576
|
+
padding: "12px 16px",
|
|
577
|
+
border: "1px solid #ddd",
|
|
578
|
+
borderRadius: "8px",
|
|
579
|
+
fontSize: "16px",
|
|
580
|
+
boxSizing: "border-box",
|
|
581
|
+
color: "#333",
|
|
582
|
+
transition: "all 0.2s ease",
|
|
583
|
+
backgroundColor: "#fafafa"
|
|
584
|
+
},
|
|
585
|
+
placeholder: "Enter your password"
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
589
|
+
"button",
|
|
590
|
+
{
|
|
591
|
+
type: "button",
|
|
592
|
+
onClick: togglePasswordVisibility,
|
|
593
|
+
disabled: isLoading,
|
|
594
|
+
style: {
|
|
595
|
+
position: "absolute",
|
|
596
|
+
right: "12px",
|
|
597
|
+
top: "38px",
|
|
598
|
+
background: "none",
|
|
599
|
+
border: "none",
|
|
600
|
+
cursor: "pointer",
|
|
601
|
+
color: "#666",
|
|
602
|
+
fontSize: "14px"
|
|
603
|
+
},
|
|
604
|
+
children: showPassword ? "Hide" : "Show"
|
|
605
|
+
}
|
|
606
|
+
)
|
|
607
|
+
] }),
|
|
608
|
+
usePassword && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
609
|
+
display: "flex",
|
|
610
|
+
alignItems: "center",
|
|
611
|
+
marginBottom: "16px",
|
|
612
|
+
marginTop: "8px"
|
|
613
|
+
}, children: [
|
|
614
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
615
|
+
"input",
|
|
616
|
+
{
|
|
617
|
+
type: "checkbox",
|
|
618
|
+
id: "remember-me",
|
|
619
|
+
checked: rememberMe,
|
|
620
|
+
onChange: (e) => setRememberMe(e.target.checked),
|
|
621
|
+
disabled: isLoading,
|
|
622
|
+
style: {
|
|
623
|
+
marginRight: "8px",
|
|
624
|
+
cursor: "pointer",
|
|
625
|
+
width: "16px",
|
|
626
|
+
height: "16px"
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
),
|
|
630
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
631
|
+
"label",
|
|
632
|
+
{
|
|
633
|
+
htmlFor: "remember-me",
|
|
634
|
+
style: {
|
|
635
|
+
fontSize: "14px",
|
|
636
|
+
color: "#666",
|
|
637
|
+
cursor: "pointer",
|
|
638
|
+
userSelect: "none"
|
|
639
|
+
},
|
|
640
|
+
children: "Remember me"
|
|
641
|
+
}
|
|
642
|
+
)
|
|
643
|
+
] }),
|
|
644
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
645
|
+
"button",
|
|
646
|
+
{
|
|
647
|
+
type: "submit",
|
|
648
|
+
disabled: isLoading,
|
|
649
|
+
style: {
|
|
650
|
+
padding: "14px",
|
|
651
|
+
backgroundColor: "#007bff",
|
|
652
|
+
color: "white",
|
|
653
|
+
border: "none",
|
|
654
|
+
borderRadius: "8px",
|
|
655
|
+
fontSize: "16px",
|
|
656
|
+
fontWeight: 600,
|
|
657
|
+
cursor: "pointer",
|
|
658
|
+
transition: "all 0.2s ease",
|
|
659
|
+
marginTop: "8px"
|
|
660
|
+
},
|
|
661
|
+
children: isLoading ? usePassword ? "Logging in..." : "Sending OTP..." : usePassword ? "Login" : "Send OTP"
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
665
|
+
textAlign: "center",
|
|
666
|
+
marginTop: "20px",
|
|
667
|
+
paddingTop: "20px",
|
|
668
|
+
borderTop: "1px solid #eee"
|
|
669
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
670
|
+
"button",
|
|
671
|
+
{
|
|
672
|
+
type: "button",
|
|
673
|
+
onClick: toggleAuthMethod,
|
|
674
|
+
disabled: isLoading,
|
|
675
|
+
style: {
|
|
676
|
+
background: "none",
|
|
677
|
+
border: "none",
|
|
678
|
+
color: "#007bff",
|
|
679
|
+
textDecoration: "none",
|
|
680
|
+
cursor: "pointer",
|
|
681
|
+
fontSize: "14px",
|
|
682
|
+
fontWeight: 600,
|
|
683
|
+
padding: "0",
|
|
684
|
+
transition: "color 0.2s ease"
|
|
685
|
+
},
|
|
686
|
+
children: usePassword ? "Login with OTP instead" : "Login with password instead"
|
|
687
|
+
}
|
|
688
|
+
) }),
|
|
689
|
+
showOAuthButtons && oauthProviders.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
690
|
+
marginTop: "20px",
|
|
691
|
+
paddingTop: "20px",
|
|
692
|
+
borderTop: "1px solid #eee"
|
|
693
|
+
}, children: [
|
|
694
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
695
|
+
position: "relative",
|
|
696
|
+
marginBottom: "16px"
|
|
697
|
+
}, children: [
|
|
698
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
699
|
+
position: "absolute",
|
|
700
|
+
top: "50%",
|
|
701
|
+
left: 0,
|
|
702
|
+
right: 0,
|
|
703
|
+
height: "1px",
|
|
704
|
+
backgroundColor: "#eee"
|
|
705
|
+
} }),
|
|
706
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
707
|
+
position: "relative",
|
|
708
|
+
textAlign: "center"
|
|
709
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
|
|
710
|
+
backgroundColor: "#ffffff",
|
|
711
|
+
padding: "0 12px",
|
|
712
|
+
color: "#666",
|
|
713
|
+
fontSize: "14px"
|
|
714
|
+
}, children: "Or continue with" }) })
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
717
|
+
display: "grid",
|
|
718
|
+
gridTemplateColumns: oauthProviders.length === 1 ? "1fr" : "repeat(2, 1fr)",
|
|
719
|
+
gap: "12px"
|
|
720
|
+
}, children: [
|
|
721
|
+
oauthProviders.includes("google") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
722
|
+
"a",
|
|
723
|
+
{
|
|
724
|
+
href: `${config?.baseUrl || "http://localhost:7000"}/api/v1/auth/oauth/google`,
|
|
725
|
+
style: {
|
|
726
|
+
display: "flex",
|
|
727
|
+
alignItems: "center",
|
|
728
|
+
justifyContent: "center",
|
|
729
|
+
gap: "8px",
|
|
730
|
+
padding: "10px 16px",
|
|
731
|
+
backgroundColor: "#ffffff",
|
|
732
|
+
border: "1px solid #ddd",
|
|
733
|
+
borderRadius: "8px",
|
|
734
|
+
color: "#333",
|
|
735
|
+
textDecoration: "none",
|
|
736
|
+
fontSize: "14px",
|
|
737
|
+
fontWeight: 500,
|
|
738
|
+
cursor: "pointer",
|
|
739
|
+
transition: "all 0.2s ease"
|
|
740
|
+
},
|
|
741
|
+
onMouseEnter: (e) => {
|
|
742
|
+
e.currentTarget.style.backgroundColor = "#f8f8f8";
|
|
743
|
+
e.currentTarget.style.borderColor = "#007bff";
|
|
744
|
+
},
|
|
745
|
+
onMouseLeave: (e) => {
|
|
746
|
+
e.currentTarget.style.backgroundColor = "#ffffff";
|
|
747
|
+
e.currentTarget.style.borderColor = "#ddd";
|
|
748
|
+
},
|
|
749
|
+
children: [
|
|
750
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { style: { width: "18px", height: "18px" }, viewBox: "0 0 24 24", children: [
|
|
751
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
752
|
+
"path",
|
|
753
|
+
{
|
|
754
|
+
fill: "#4285F4",
|
|
755
|
+
d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
756
|
+
}
|
|
757
|
+
),
|
|
758
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
759
|
+
"path",
|
|
760
|
+
{
|
|
761
|
+
fill: "#34A853",
|
|
762
|
+
d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
763
|
+
}
|
|
764
|
+
),
|
|
765
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
766
|
+
"path",
|
|
767
|
+
{
|
|
768
|
+
fill: "#FBBC05",
|
|
769
|
+
d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
770
|
+
}
|
|
771
|
+
),
|
|
772
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
773
|
+
"path",
|
|
774
|
+
{
|
|
775
|
+
fill: "#EA4335",
|
|
776
|
+
d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
777
|
+
}
|
|
778
|
+
)
|
|
779
|
+
] }),
|
|
780
|
+
"Google"
|
|
781
|
+
]
|
|
782
|
+
}
|
|
783
|
+
),
|
|
784
|
+
oauthProviders.includes("github") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
785
|
+
"a",
|
|
786
|
+
{
|
|
787
|
+
href: `${config?.baseUrl || "http://localhost:7000"}/api/v1/auth/oauth/github`,
|
|
788
|
+
style: {
|
|
789
|
+
display: "flex",
|
|
790
|
+
alignItems: "center",
|
|
791
|
+
justifyContent: "center",
|
|
792
|
+
gap: "8px",
|
|
793
|
+
padding: "10px 16px",
|
|
794
|
+
backgroundColor: "#24292e",
|
|
795
|
+
border: "1px solid #24292e",
|
|
796
|
+
borderRadius: "8px",
|
|
797
|
+
color: "#ffffff",
|
|
798
|
+
textDecoration: "none",
|
|
799
|
+
fontSize: "14px",
|
|
800
|
+
fontWeight: 500,
|
|
801
|
+
cursor: "pointer",
|
|
802
|
+
transition: "all 0.2s ease"
|
|
803
|
+
},
|
|
804
|
+
onMouseEnter: (e) => {
|
|
805
|
+
e.currentTarget.style.backgroundColor = "#1b1f23";
|
|
806
|
+
e.currentTarget.style.borderColor = "#1b1f23";
|
|
807
|
+
},
|
|
808
|
+
onMouseLeave: (e) => {
|
|
809
|
+
e.currentTarget.style.backgroundColor = "#24292e";
|
|
810
|
+
e.currentTarget.style.borderColor = "#24292e";
|
|
811
|
+
},
|
|
812
|
+
children: [
|
|
813
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { style: { width: "18px", height: "18px" }, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" }) }),
|
|
814
|
+
"GitHub"
|
|
815
|
+
]
|
|
816
|
+
}
|
|
817
|
+
)
|
|
818
|
+
] })
|
|
819
|
+
] }),
|
|
820
|
+
showRegisterLink && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
821
|
+
textAlign: "center",
|
|
822
|
+
marginTop: "20px",
|
|
823
|
+
paddingTop: "20px",
|
|
824
|
+
borderTop: "1px solid #eee"
|
|
825
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("p", { style: {
|
|
826
|
+
color: "#666",
|
|
827
|
+
fontSize: "14px"
|
|
828
|
+
}, children: [
|
|
829
|
+
"Don't have an account?",
|
|
830
|
+
" ",
|
|
831
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
832
|
+
"button",
|
|
833
|
+
{
|
|
834
|
+
type: "button",
|
|
835
|
+
onClick: onRegisterClick,
|
|
836
|
+
disabled: isLoading,
|
|
837
|
+
style: {
|
|
838
|
+
background: "none",
|
|
839
|
+
border: "none",
|
|
840
|
+
color: "#007bff",
|
|
841
|
+
textDecoration: "none",
|
|
842
|
+
cursor: "pointer",
|
|
843
|
+
fontSize: "14px",
|
|
844
|
+
fontWeight: 600,
|
|
845
|
+
padding: "0",
|
|
846
|
+
transition: "color 0.2s ease"
|
|
847
|
+
},
|
|
848
|
+
children: "Register"
|
|
849
|
+
}
|
|
850
|
+
)
|
|
851
|
+
] }) })
|
|
852
|
+
] }) });
|
|
853
|
+
};
|
|
854
|
+
var RegisterForm = ({
|
|
855
|
+
onRegisterSuccess,
|
|
856
|
+
onLoginClick,
|
|
857
|
+
showLoginLink = true,
|
|
858
|
+
authConfig,
|
|
859
|
+
oauthProviders = ["google", "github"],
|
|
860
|
+
showOAuthButtons = true
|
|
861
|
+
}) => {
|
|
862
|
+
const [name, setName] = react.useState("");
|
|
863
|
+
const [email, setEmail] = react.useState("");
|
|
864
|
+
const [password, setPassword] = react.useState("");
|
|
865
|
+
const [confirmPassword, setConfirmPassword] = react.useState("");
|
|
866
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
867
|
+
const [error, setError] = react.useState(null);
|
|
868
|
+
react.useState(false);
|
|
869
|
+
react.useState(false);
|
|
870
|
+
const getPasswordStrength = (pwd) => {
|
|
871
|
+
if (!pwd)
|
|
872
|
+
return { strength: "weak", score: 0, label: "" };
|
|
873
|
+
let score = 0;
|
|
874
|
+
if (pwd.length >= 6)
|
|
875
|
+
score++;
|
|
876
|
+
if (pwd.length >= 8)
|
|
877
|
+
score++;
|
|
878
|
+
if (/[a-z]/.test(pwd) && /[A-Z]/.test(pwd))
|
|
879
|
+
score++;
|
|
880
|
+
if (/\d/.test(pwd))
|
|
881
|
+
score++;
|
|
882
|
+
if (/[^a-zA-Z\d]/.test(pwd))
|
|
883
|
+
score++;
|
|
884
|
+
if (score <= 2)
|
|
885
|
+
return { strength: "weak", score, label: "Weak" };
|
|
886
|
+
if (score <= 3)
|
|
887
|
+
return { strength: "medium", score, label: "Medium" };
|
|
888
|
+
return { strength: "strong", score, label: "Strong" };
|
|
889
|
+
};
|
|
890
|
+
getPasswordStrength(password);
|
|
891
|
+
const config = authConfig || {
|
|
892
|
+
baseUrl: typeof window !== "undefined" ? process.env.NEXT_PUBLIC_AUTH_API_URL || window.location.origin : "http://localhost:7000"
|
|
893
|
+
};
|
|
894
|
+
const { register } = useAuth(config);
|
|
895
|
+
const handleSubmit = async (e) => {
|
|
896
|
+
e.preventDefault();
|
|
897
|
+
setIsLoading(true);
|
|
898
|
+
setError(null);
|
|
899
|
+
if (password !== confirmPassword) {
|
|
900
|
+
setError("Passwords do not match");
|
|
901
|
+
setIsLoading(false);
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
if (password.length < 6) {
|
|
905
|
+
setError("Password must be at least 6 characters long");
|
|
906
|
+
setIsLoading(false);
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
try {
|
|
910
|
+
const registerData = {
|
|
911
|
+
name,
|
|
912
|
+
email,
|
|
913
|
+
password,
|
|
914
|
+
frontendBaseUrl: typeof window !== "undefined" ? process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.REACT_APP_FRONTEND_BASE_URL || window.location.origin : void 0
|
|
915
|
+
};
|
|
916
|
+
const response = await register(registerData);
|
|
917
|
+
if (response.success) {
|
|
918
|
+
onRegisterSuccess?.();
|
|
919
|
+
} else {
|
|
920
|
+
setError(response.message || "Registration failed");
|
|
921
|
+
}
|
|
922
|
+
} catch (err) {
|
|
923
|
+
setError(err instanceof Error ? err.message : "An unknown error occurred");
|
|
924
|
+
} finally {
|
|
925
|
+
setIsLoading(false);
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
929
|
+
maxWidth: "400px",
|
|
930
|
+
margin: "0 auto",
|
|
931
|
+
padding: "30px",
|
|
932
|
+
borderRadius: "12px",
|
|
933
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.1)",
|
|
934
|
+
backgroundColor: "#ffffff",
|
|
935
|
+
border: "1px solid #eaeaea"
|
|
936
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: {
|
|
937
|
+
display: "flex",
|
|
938
|
+
flexDirection: "column"
|
|
939
|
+
}, children: [
|
|
940
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
|
|
941
|
+
textAlign: "center",
|
|
942
|
+
marginBottom: "24px",
|
|
943
|
+
color: "#1f2937",
|
|
944
|
+
fontSize: "24px",
|
|
945
|
+
fontWeight: 600
|
|
946
|
+
}, children: "Register" }),
|
|
947
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
948
|
+
padding: "12px 16px",
|
|
949
|
+
marginBottom: "20px",
|
|
950
|
+
backgroundColor: "#f8d7da",
|
|
951
|
+
color: "#721c24",
|
|
952
|
+
border: "1px solid #f5c6cb",
|
|
953
|
+
borderRadius: "8px",
|
|
954
|
+
fontSize: "14px",
|
|
955
|
+
fontWeight: 500
|
|
956
|
+
}, children: error }),
|
|
957
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
958
|
+
marginBottom: "20px"
|
|
959
|
+
}, children: [
|
|
960
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "name", style: {
|
|
961
|
+
display: "block",
|
|
962
|
+
marginBottom: "8px",
|
|
963
|
+
fontWeight: 500,
|
|
964
|
+
color: "#374151",
|
|
965
|
+
fontSize: "14px"
|
|
966
|
+
}, children: "Name:" }),
|
|
967
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
968
|
+
"input",
|
|
969
|
+
{
|
|
970
|
+
id: "name",
|
|
971
|
+
type: "text",
|
|
972
|
+
value: name,
|
|
973
|
+
onChange: (e) => setName(e.target.value),
|
|
974
|
+
required: true,
|
|
975
|
+
disabled: isLoading,
|
|
976
|
+
style: {
|
|
977
|
+
width: "100%",
|
|
978
|
+
padding: "12px 16px",
|
|
979
|
+
border: "1px solid #ddd",
|
|
980
|
+
borderRadius: "8px",
|
|
981
|
+
fontSize: "16px",
|
|
982
|
+
boxSizing: "border-box",
|
|
983
|
+
color: "#111827",
|
|
984
|
+
transition: "all 0.2s ease",
|
|
985
|
+
backgroundColor: "#ffffff"
|
|
986
|
+
},
|
|
987
|
+
placeholder: "Enter your name"
|
|
988
|
+
}
|
|
989
|
+
)
|
|
990
|
+
] }),
|
|
991
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
992
|
+
marginBottom: "20px"
|
|
993
|
+
}, children: [
|
|
994
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "register-email", style: {
|
|
995
|
+
display: "block",
|
|
996
|
+
marginBottom: "8px",
|
|
997
|
+
fontWeight: 500,
|
|
998
|
+
color: "#555",
|
|
999
|
+
fontSize: "14px"
|
|
1000
|
+
}, children: "Email:" }),
|
|
1001
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1002
|
+
"input",
|
|
1003
|
+
{
|
|
1004
|
+
id: "register-email",
|
|
1005
|
+
type: "email",
|
|
1006
|
+
value: email,
|
|
1007
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1008
|
+
required: true,
|
|
1009
|
+
disabled: isLoading,
|
|
1010
|
+
style: {
|
|
1011
|
+
width: "100%",
|
|
1012
|
+
padding: "12px 16px",
|
|
1013
|
+
border: "1px solid #ddd",
|
|
1014
|
+
borderRadius: "8px",
|
|
1015
|
+
fontSize: "16px",
|
|
1016
|
+
boxSizing: "border-box",
|
|
1017
|
+
color: "#333",
|
|
1018
|
+
transition: "all 0.2s ease",
|
|
1019
|
+
backgroundColor: "#fafafa"
|
|
1020
|
+
},
|
|
1021
|
+
placeholder: "Enter your email"
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
] }),
|
|
1025
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1026
|
+
marginBottom: "20px"
|
|
1027
|
+
}, children: [
|
|
1028
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "password", style: {
|
|
1029
|
+
display: "block",
|
|
1030
|
+
marginBottom: "8px",
|
|
1031
|
+
fontWeight: 500,
|
|
1032
|
+
color: "#555",
|
|
1033
|
+
fontSize: "14px"
|
|
1034
|
+
}, children: "Password:" }),
|
|
1035
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1036
|
+
"input",
|
|
1037
|
+
{
|
|
1038
|
+
id: "password",
|
|
1039
|
+
type: "password",
|
|
1040
|
+
value: password,
|
|
1041
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1042
|
+
required: true,
|
|
1043
|
+
disabled: isLoading,
|
|
1044
|
+
style: {
|
|
1045
|
+
width: "100%",
|
|
1046
|
+
padding: "12px 16px",
|
|
1047
|
+
border: "1px solid #ddd",
|
|
1048
|
+
borderRadius: "8px",
|
|
1049
|
+
fontSize: "16px",
|
|
1050
|
+
boxSizing: "border-box",
|
|
1051
|
+
color: "#333",
|
|
1052
|
+
transition: "all 0.2s ease",
|
|
1053
|
+
backgroundColor: "#fafafa"
|
|
1054
|
+
},
|
|
1055
|
+
placeholder: "Enter your password",
|
|
1056
|
+
minLength: 6
|
|
1057
|
+
}
|
|
1058
|
+
)
|
|
1059
|
+
] }),
|
|
1060
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1061
|
+
marginBottom: "20px"
|
|
1062
|
+
}, children: [
|
|
1063
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirm-password", style: {
|
|
1064
|
+
display: "block",
|
|
1065
|
+
marginBottom: "8px",
|
|
1066
|
+
fontWeight: 500,
|
|
1067
|
+
color: "#555",
|
|
1068
|
+
fontSize: "14px"
|
|
1069
|
+
}, children: "Confirm Password:" }),
|
|
1070
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1071
|
+
"input",
|
|
1072
|
+
{
|
|
1073
|
+
id: "confirm-password",
|
|
1074
|
+
type: "password",
|
|
1075
|
+
value: confirmPassword,
|
|
1076
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
1077
|
+
required: true,
|
|
1078
|
+
disabled: isLoading,
|
|
1079
|
+
style: {
|
|
1080
|
+
width: "100%",
|
|
1081
|
+
padding: "12px 16px",
|
|
1082
|
+
border: "1px solid #ddd",
|
|
1083
|
+
borderRadius: "8px",
|
|
1084
|
+
fontSize: "16px",
|
|
1085
|
+
boxSizing: "border-box",
|
|
1086
|
+
color: "#333",
|
|
1087
|
+
transition: "all 0.2s ease",
|
|
1088
|
+
backgroundColor: "#fafafa"
|
|
1089
|
+
},
|
|
1090
|
+
placeholder: "Confirm your password"
|
|
1091
|
+
}
|
|
1092
|
+
)
|
|
1093
|
+
] }),
|
|
1094
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
+
"button",
|
|
1096
|
+
{
|
|
1097
|
+
type: "submit",
|
|
1098
|
+
disabled: isLoading,
|
|
1099
|
+
style: {
|
|
1100
|
+
padding: "14px",
|
|
1101
|
+
backgroundColor: "#007bff",
|
|
1102
|
+
color: "white",
|
|
1103
|
+
border: "none",
|
|
1104
|
+
borderRadius: "8px",
|
|
1105
|
+
fontSize: "16px",
|
|
1106
|
+
fontWeight: 600,
|
|
1107
|
+
cursor: "pointer",
|
|
1108
|
+
transition: "all 0.2s ease",
|
|
1109
|
+
marginTop: "8px"
|
|
1110
|
+
},
|
|
1111
|
+
children: isLoading ? "Registering..." : "Register"
|
|
1112
|
+
}
|
|
1113
|
+
),
|
|
1114
|
+
showOAuthButtons && oauthProviders.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1115
|
+
marginTop: "20px",
|
|
1116
|
+
paddingTop: "20px",
|
|
1117
|
+
borderTop: "1px solid #eee"
|
|
1118
|
+
}, children: [
|
|
1119
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1120
|
+
position: "relative",
|
|
1121
|
+
marginBottom: "16px"
|
|
1122
|
+
}, children: [
|
|
1123
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1124
|
+
position: "absolute",
|
|
1125
|
+
top: "50%",
|
|
1126
|
+
left: 0,
|
|
1127
|
+
right: 0,
|
|
1128
|
+
height: "1px",
|
|
1129
|
+
backgroundColor: "#eee"
|
|
1130
|
+
} }),
|
|
1131
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1132
|
+
position: "relative",
|
|
1133
|
+
textAlign: "center"
|
|
1134
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
|
|
1135
|
+
backgroundColor: "#ffffff",
|
|
1136
|
+
padding: "0 12px",
|
|
1137
|
+
color: "#666",
|
|
1138
|
+
fontSize: "14px"
|
|
1139
|
+
}, children: "Or continue with" }) })
|
|
1140
|
+
] }),
|
|
1141
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1142
|
+
display: "grid",
|
|
1143
|
+
gridTemplateColumns: oauthProviders.length === 1 ? "1fr" : "repeat(2, 1fr)",
|
|
1144
|
+
gap: "12px"
|
|
1145
|
+
}, children: [
|
|
1146
|
+
oauthProviders.includes("google") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1147
|
+
"a",
|
|
1148
|
+
{
|
|
1149
|
+
href: `${config.baseUrl}/api/v1/auth/oauth/google`,
|
|
1150
|
+
style: {
|
|
1151
|
+
display: "flex",
|
|
1152
|
+
alignItems: "center",
|
|
1153
|
+
justifyContent: "center",
|
|
1154
|
+
gap: "8px",
|
|
1155
|
+
padding: "10px 16px",
|
|
1156
|
+
backgroundColor: "#ffffff",
|
|
1157
|
+
border: "1px solid #ddd",
|
|
1158
|
+
borderRadius: "8px",
|
|
1159
|
+
color: "#333",
|
|
1160
|
+
textDecoration: "none",
|
|
1161
|
+
fontSize: "14px",
|
|
1162
|
+
fontWeight: 500,
|
|
1163
|
+
cursor: "pointer",
|
|
1164
|
+
transition: "all 0.2s ease"
|
|
1165
|
+
},
|
|
1166
|
+
onMouseEnter: (e) => {
|
|
1167
|
+
e.currentTarget.style.backgroundColor = "#f8f8f8";
|
|
1168
|
+
e.currentTarget.style.borderColor = "#007bff";
|
|
1169
|
+
},
|
|
1170
|
+
onMouseLeave: (e) => {
|
|
1171
|
+
e.currentTarget.style.backgroundColor = "#ffffff";
|
|
1172
|
+
e.currentTarget.style.borderColor = "#ddd";
|
|
1173
|
+
},
|
|
1174
|
+
children: [
|
|
1175
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { style: { width: "18px", height: "18px" }, viewBox: "0 0 24 24", children: [
|
|
1176
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1177
|
+
"path",
|
|
1178
|
+
{
|
|
1179
|
+
fill: "#4285F4",
|
|
1180
|
+
d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
1181
|
+
}
|
|
1182
|
+
),
|
|
1183
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1184
|
+
"path",
|
|
1185
|
+
{
|
|
1186
|
+
fill: "#34A853",
|
|
1187
|
+
d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
1188
|
+
}
|
|
1189
|
+
),
|
|
1190
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1191
|
+
"path",
|
|
1192
|
+
{
|
|
1193
|
+
fill: "#FBBC05",
|
|
1194
|
+
d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
1195
|
+
}
|
|
1196
|
+
),
|
|
1197
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1198
|
+
"path",
|
|
1199
|
+
{
|
|
1200
|
+
fill: "#EA4335",
|
|
1201
|
+
d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
1202
|
+
}
|
|
1203
|
+
)
|
|
1204
|
+
] }),
|
|
1205
|
+
"Google"
|
|
1206
|
+
]
|
|
1207
|
+
}
|
|
1208
|
+
),
|
|
1209
|
+
oauthProviders.includes("github") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1210
|
+
"a",
|
|
1211
|
+
{
|
|
1212
|
+
href: `${config.baseUrl}/api/v1/auth/oauth/github`,
|
|
1213
|
+
style: {
|
|
1214
|
+
display: "flex",
|
|
1215
|
+
alignItems: "center",
|
|
1216
|
+
justifyContent: "center",
|
|
1217
|
+
gap: "8px",
|
|
1218
|
+
padding: "10px 16px",
|
|
1219
|
+
backgroundColor: "#24292e",
|
|
1220
|
+
border: "1px solid #24292e",
|
|
1221
|
+
borderRadius: "8px",
|
|
1222
|
+
color: "#ffffff",
|
|
1223
|
+
textDecoration: "none",
|
|
1224
|
+
fontSize: "14px",
|
|
1225
|
+
fontWeight: 500,
|
|
1226
|
+
cursor: "pointer",
|
|
1227
|
+
transition: "all 0.2s ease"
|
|
1228
|
+
},
|
|
1229
|
+
onMouseEnter: (e) => {
|
|
1230
|
+
e.currentTarget.style.backgroundColor = "#1b1f23";
|
|
1231
|
+
e.currentTarget.style.borderColor = "#1b1f23";
|
|
1232
|
+
},
|
|
1233
|
+
onMouseLeave: (e) => {
|
|
1234
|
+
e.currentTarget.style.backgroundColor = "#24292e";
|
|
1235
|
+
e.currentTarget.style.borderColor = "#24292e";
|
|
1236
|
+
},
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { style: { width: "18px", height: "18px" }, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" }) }),
|
|
1239
|
+
"GitHub"
|
|
1240
|
+
]
|
|
1241
|
+
}
|
|
1242
|
+
)
|
|
1243
|
+
] })
|
|
1244
|
+
] }),
|
|
1245
|
+
showLoginLink && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1246
|
+
textAlign: "center",
|
|
1247
|
+
marginTop: "20px",
|
|
1248
|
+
paddingTop: "20px",
|
|
1249
|
+
borderTop: "1px solid #eee"
|
|
1250
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("p", { style: {
|
|
1251
|
+
color: "#666",
|
|
1252
|
+
fontSize: "14px"
|
|
1253
|
+
}, children: [
|
|
1254
|
+
"Already have an account?",
|
|
1255
|
+
" ",
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1257
|
+
"button",
|
|
1258
|
+
{
|
|
1259
|
+
type: "button",
|
|
1260
|
+
onClick: onLoginClick,
|
|
1261
|
+
disabled: isLoading,
|
|
1262
|
+
style: {
|
|
1263
|
+
background: "none",
|
|
1264
|
+
border: "none",
|
|
1265
|
+
color: "#007bff",
|
|
1266
|
+
textDecoration: "none",
|
|
1267
|
+
cursor: "pointer",
|
|
1268
|
+
fontSize: "14px",
|
|
1269
|
+
fontWeight: 600,
|
|
1270
|
+
padding: "0",
|
|
1271
|
+
transition: "color 0.2s ease"
|
|
1272
|
+
},
|
|
1273
|
+
children: "Login"
|
|
1274
|
+
}
|
|
1275
|
+
)
|
|
1276
|
+
] }) })
|
|
1277
|
+
] }) });
|
|
1278
|
+
};
|
|
1279
|
+
var OtpForm = ({
|
|
1280
|
+
email,
|
|
1281
|
+
onVerifySuccess,
|
|
1282
|
+
onBackToLogin
|
|
1283
|
+
}) => {
|
|
1284
|
+
const [otp, setOtp] = react.useState("");
|
|
1285
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
1286
|
+
const [error, setError] = react.useState(null);
|
|
1287
|
+
const [resendCooldown, setResendCooldown] = react.useState(0);
|
|
1288
|
+
const [resendLoading, setResendLoading] = react.useState(false);
|
|
1289
|
+
const { verify, login } = useAuth({
|
|
1290
|
+
baseUrl: typeof window !== "undefined" ? window.location.origin : "http://localhost:7000"
|
|
1291
|
+
});
|
|
1292
|
+
const handleSubmit = async (e) => {
|
|
1293
|
+
e.preventDefault();
|
|
1294
|
+
setIsLoading(true);
|
|
1295
|
+
setError(null);
|
|
1296
|
+
if (!/^\d{6}$/.test(otp)) {
|
|
1297
|
+
setError("Please enter a valid 6-digit OTP");
|
|
1298
|
+
setIsLoading(false);
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
try {
|
|
1302
|
+
const response = await verify({ email, otp });
|
|
1303
|
+
if (response.success) {
|
|
1304
|
+
onVerifySuccess?.();
|
|
1305
|
+
} else {
|
|
1306
|
+
setError(response.message || "Verification failed");
|
|
1307
|
+
}
|
|
1308
|
+
} catch (err) {
|
|
1309
|
+
setError(err instanceof Error ? err.message : "An unknown error occurred");
|
|
1310
|
+
} finally {
|
|
1311
|
+
setIsLoading(false);
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
const handleOtpChange = (e) => {
|
|
1315
|
+
const value = e.target.value;
|
|
1316
|
+
if (/^\d{0,6}$/.test(value)) {
|
|
1317
|
+
setOtp(value);
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
const handleResendOtp = async () => {
|
|
1321
|
+
if (resendCooldown > 0 || resendLoading)
|
|
1322
|
+
return;
|
|
1323
|
+
setResendLoading(true);
|
|
1324
|
+
setError(null);
|
|
1325
|
+
try {
|
|
1326
|
+
const response = await login({ email });
|
|
1327
|
+
if (response.success) {
|
|
1328
|
+
setResendCooldown(60);
|
|
1329
|
+
const interval = setInterval(() => {
|
|
1330
|
+
setResendCooldown((prev) => {
|
|
1331
|
+
if (prev <= 1) {
|
|
1332
|
+
clearInterval(interval);
|
|
1333
|
+
return 0;
|
|
1334
|
+
}
|
|
1335
|
+
return prev - 1;
|
|
1336
|
+
});
|
|
1337
|
+
}, 1e3);
|
|
1338
|
+
} else {
|
|
1339
|
+
setError(response.message || "Failed to resend OTP");
|
|
1340
|
+
}
|
|
1341
|
+
} catch (err) {
|
|
1342
|
+
setError(err instanceof Error ? err.message : "Failed to resend OTP");
|
|
1343
|
+
} finally {
|
|
1344
|
+
setResendLoading(false);
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1348
|
+
maxWidth: "400px",
|
|
1349
|
+
margin: "0 auto",
|
|
1350
|
+
padding: "30px",
|
|
1351
|
+
borderRadius: "12px",
|
|
1352
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.1)",
|
|
1353
|
+
backgroundColor: "#ffffff",
|
|
1354
|
+
border: "1px solid #eaeaea"
|
|
1355
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: {
|
|
1356
|
+
display: "flex",
|
|
1357
|
+
flexDirection: "column"
|
|
1358
|
+
}, children: [
|
|
1359
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
|
|
1360
|
+
textAlign: "center",
|
|
1361
|
+
marginBottom: "24px",
|
|
1362
|
+
color: "#1f2937",
|
|
1363
|
+
fontSize: "24px",
|
|
1364
|
+
fontWeight: 600
|
|
1365
|
+
}, children: "Verify OTP" }),
|
|
1366
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { style: {
|
|
1367
|
+
textAlign: "center",
|
|
1368
|
+
marginBottom: "24px",
|
|
1369
|
+
color: "#4b5563",
|
|
1370
|
+
fontSize: "14px"
|
|
1371
|
+
}, children: [
|
|
1372
|
+
"Enter the 6-digit code sent to ",
|
|
1373
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { style: { color: "#111827" }, children: email })
|
|
1374
|
+
] }),
|
|
1375
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1376
|
+
padding: "12px 16px",
|
|
1377
|
+
marginBottom: "20px",
|
|
1378
|
+
backgroundColor: "#f8d7da",
|
|
1379
|
+
color: "#721c24",
|
|
1380
|
+
border: "1px solid #f5c6cb",
|
|
1381
|
+
borderRadius: "8px",
|
|
1382
|
+
fontSize: "14px",
|
|
1383
|
+
fontWeight: 500
|
|
1384
|
+
}, children: error }),
|
|
1385
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1386
|
+
marginBottom: "20px"
|
|
1387
|
+
}, children: [
|
|
1388
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "otp", style: {
|
|
1389
|
+
display: "block",
|
|
1390
|
+
marginBottom: "8px",
|
|
1391
|
+
fontWeight: 500,
|
|
1392
|
+
color: "#374151",
|
|
1393
|
+
fontSize: "14px"
|
|
1394
|
+
}, children: "OTP Code:" }),
|
|
1395
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1396
|
+
"input",
|
|
1397
|
+
{
|
|
1398
|
+
id: "otp",
|
|
1399
|
+
type: "text",
|
|
1400
|
+
value: otp,
|
|
1401
|
+
onChange: handleOtpChange,
|
|
1402
|
+
required: true,
|
|
1403
|
+
disabled: isLoading,
|
|
1404
|
+
style: {
|
|
1405
|
+
width: "100%",
|
|
1406
|
+
padding: "12px 16px",
|
|
1407
|
+
border: "1px solid #ddd",
|
|
1408
|
+
borderRadius: "8px",
|
|
1409
|
+
fontSize: "20px",
|
|
1410
|
+
boxSizing: "border-box",
|
|
1411
|
+
color: "#111827",
|
|
1412
|
+
transition: "all 0.2s ease",
|
|
1413
|
+
backgroundColor: "#ffffff",
|
|
1414
|
+
textAlign: "center",
|
|
1415
|
+
letterSpacing: "5px"
|
|
1416
|
+
},
|
|
1417
|
+
maxLength: 6,
|
|
1418
|
+
placeholder: "123456",
|
|
1419
|
+
autoFocus: true
|
|
1420
|
+
}
|
|
1421
|
+
)
|
|
1422
|
+
] }),
|
|
1423
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1424
|
+
"button",
|
|
1425
|
+
{
|
|
1426
|
+
type: "submit",
|
|
1427
|
+
disabled: isLoading || otp.length !== 6,
|
|
1428
|
+
style: {
|
|
1429
|
+
padding: "14px",
|
|
1430
|
+
backgroundColor: "#007bff",
|
|
1431
|
+
color: "white",
|
|
1432
|
+
border: "none",
|
|
1433
|
+
borderRadius: "8px",
|
|
1434
|
+
fontSize: "16px",
|
|
1435
|
+
fontWeight: 600,
|
|
1436
|
+
cursor: "pointer",
|
|
1437
|
+
transition: "all 0.2s ease",
|
|
1438
|
+
marginTop: "8px"
|
|
1439
|
+
},
|
|
1440
|
+
children: isLoading ? "Verifying..." : "Verify OTP"
|
|
1441
|
+
}
|
|
1442
|
+
),
|
|
1443
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1444
|
+
textAlign: "center",
|
|
1445
|
+
marginTop: "20px",
|
|
1446
|
+
paddingTop: "20px",
|
|
1447
|
+
borderTop: "1px solid #eee"
|
|
1448
|
+
}, children: [
|
|
1449
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1450
|
+
"button",
|
|
1451
|
+
{
|
|
1452
|
+
type: "button",
|
|
1453
|
+
onClick: handleResendOtp,
|
|
1454
|
+
disabled: isLoading || resendLoading || resendCooldown > 0,
|
|
1455
|
+
style: {
|
|
1456
|
+
background: "none",
|
|
1457
|
+
border: "none",
|
|
1458
|
+
color: resendCooldown > 0 ? "#999" : "#007bff",
|
|
1459
|
+
textDecoration: "none",
|
|
1460
|
+
cursor: resendCooldown > 0 ? "not-allowed" : "pointer",
|
|
1461
|
+
fontSize: "14px",
|
|
1462
|
+
fontWeight: 600,
|
|
1463
|
+
padding: "0",
|
|
1464
|
+
marginBottom: "12px",
|
|
1465
|
+
transition: "color 0.2s ease",
|
|
1466
|
+
display: "block",
|
|
1467
|
+
width: "100%"
|
|
1468
|
+
},
|
|
1469
|
+
children: resendLoading ? "Sending..." : resendCooldown > 0 ? `Resend OTP in ${resendCooldown}s` : "Resend OTP"
|
|
1470
|
+
}
|
|
1471
|
+
),
|
|
1472
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1473
|
+
"button",
|
|
1474
|
+
{
|
|
1475
|
+
type: "button",
|
|
1476
|
+
onClick: onBackToLogin,
|
|
1477
|
+
disabled: isLoading,
|
|
1478
|
+
style: {
|
|
1479
|
+
background: "none",
|
|
1480
|
+
border: "none",
|
|
1481
|
+
color: "#007bff",
|
|
1482
|
+
textDecoration: "none",
|
|
1483
|
+
cursor: "pointer",
|
|
1484
|
+
fontSize: "14px",
|
|
1485
|
+
fontWeight: 600,
|
|
1486
|
+
padding: "0",
|
|
1487
|
+
transition: "color 0.2s ease"
|
|
1488
|
+
},
|
|
1489
|
+
children: "Back to Login"
|
|
1490
|
+
}
|
|
1491
|
+
)
|
|
1492
|
+
] })
|
|
1493
|
+
] }) });
|
|
1494
|
+
};
|
|
1495
|
+
var AuthFlow = ({
|
|
1496
|
+
onAuthComplete,
|
|
1497
|
+
initialStep = "login",
|
|
1498
|
+
showTitle = true
|
|
1499
|
+
}) => {
|
|
1500
|
+
const [step, setStep] = react.useState(initialStep);
|
|
1501
|
+
const [email, setEmail] = react.useState("");
|
|
1502
|
+
const [message, setMessage] = react.useState(null);
|
|
1503
|
+
const handleLoginSuccess = (email2, needsOtpVerification) => {
|
|
1504
|
+
setEmail(email2);
|
|
1505
|
+
if (needsOtpVerification) {
|
|
1506
|
+
setStep("otp");
|
|
1507
|
+
setMessage(null);
|
|
1508
|
+
} else {
|
|
1509
|
+
setMessage(null);
|
|
1510
|
+
onAuthComplete?.();
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
const handleRegisterSuccess = () => {
|
|
1514
|
+
setMessage("Registration successful! Please check your email for verification.");
|
|
1515
|
+
setTimeout(() => {
|
|
1516
|
+
setStep("login");
|
|
1517
|
+
setMessage(null);
|
|
1518
|
+
}, 3e3);
|
|
1519
|
+
};
|
|
1520
|
+
const handleVerifySuccess = () => {
|
|
1521
|
+
setMessage(null);
|
|
1522
|
+
onAuthComplete?.();
|
|
1523
|
+
};
|
|
1524
|
+
const handleBackToLogin = () => {
|
|
1525
|
+
setStep("login");
|
|
1526
|
+
setMessage(null);
|
|
1527
|
+
};
|
|
1528
|
+
const renderCurrentStep = () => {
|
|
1529
|
+
switch (step) {
|
|
1530
|
+
case "login":
|
|
1531
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1532
|
+
showTitle && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
|
|
1533
|
+
textAlign: "center",
|
|
1534
|
+
marginBottom: "24px",
|
|
1535
|
+
color: "#333",
|
|
1536
|
+
fontSize: "32px",
|
|
1537
|
+
fontWeight: 700
|
|
1538
|
+
}, children: "Welcome Back" }),
|
|
1539
|
+
message && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1540
|
+
padding: "12px 16px",
|
|
1541
|
+
marginBottom: "20px",
|
|
1542
|
+
backgroundColor: "#d4edda",
|
|
1543
|
+
color: "#155724",
|
|
1544
|
+
border: "1px solid #c3e6cb",
|
|
1545
|
+
borderRadius: "8px",
|
|
1546
|
+
fontSize: "14px",
|
|
1547
|
+
fontWeight: 500
|
|
1548
|
+
}, children: message }),
|
|
1549
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1550
|
+
LoginForm,
|
|
1551
|
+
{
|
|
1552
|
+
onLoginSuccess: handleLoginSuccess,
|
|
1553
|
+
onRegisterClick: () => setStep("register"),
|
|
1554
|
+
showRegisterLink: true
|
|
1555
|
+
}
|
|
1556
|
+
)
|
|
1557
|
+
] });
|
|
1558
|
+
case "register":
|
|
1559
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1560
|
+
showTitle && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
|
|
1561
|
+
textAlign: "center",
|
|
1562
|
+
marginBottom: "24px",
|
|
1563
|
+
color: "#333",
|
|
1564
|
+
fontSize: "32px",
|
|
1565
|
+
fontWeight: 700
|
|
1566
|
+
}, children: "Create Account" }),
|
|
1567
|
+
message && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1568
|
+
padding: "12px 16px",
|
|
1569
|
+
marginBottom: "20px",
|
|
1570
|
+
backgroundColor: "#d4edda",
|
|
1571
|
+
color: "#155724",
|
|
1572
|
+
border: "1px solid #c3e6cb",
|
|
1573
|
+
borderRadius: "8px",
|
|
1574
|
+
fontSize: "14px",
|
|
1575
|
+
fontWeight: 500
|
|
1576
|
+
}, children: message }),
|
|
1577
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1578
|
+
RegisterForm,
|
|
1579
|
+
{
|
|
1580
|
+
onRegisterSuccess: handleRegisterSuccess,
|
|
1581
|
+
onLoginClick: () => setStep("login"),
|
|
1582
|
+
showLoginLink: true
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
] });
|
|
1586
|
+
case "otp":
|
|
1587
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1588
|
+
showTitle && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
|
|
1589
|
+
textAlign: "center",
|
|
1590
|
+
marginBottom: "24px",
|
|
1591
|
+
color: "#333",
|
|
1592
|
+
fontSize: "32px",
|
|
1593
|
+
fontWeight: 700
|
|
1594
|
+
}, children: "Verify Your Email" }),
|
|
1595
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1596
|
+
OtpForm,
|
|
1597
|
+
{
|
|
1598
|
+
email,
|
|
1599
|
+
onVerifySuccess: handleVerifySuccess,
|
|
1600
|
+
onBackToLogin: handleBackToLogin
|
|
1601
|
+
}
|
|
1602
|
+
)
|
|
1603
|
+
] });
|
|
1604
|
+
default:
|
|
1605
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1606
|
+
showTitle && /* @__PURE__ */ jsxRuntime.jsx("h1", { style: {
|
|
1607
|
+
textAlign: "center",
|
|
1608
|
+
marginBottom: "24px",
|
|
1609
|
+
color: "#333",
|
|
1610
|
+
fontSize: "32px",
|
|
1611
|
+
fontWeight: 700
|
|
1612
|
+
}, children: "Welcome Back" }),
|
|
1613
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1614
|
+
LoginForm,
|
|
1615
|
+
{
|
|
1616
|
+
onLoginSuccess: handleLoginSuccess,
|
|
1617
|
+
onRegisterClick: () => setStep("register"),
|
|
1618
|
+
showRegisterLink: true
|
|
1619
|
+
}
|
|
1620
|
+
)
|
|
1621
|
+
] });
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1625
|
+
minHeight: "300px",
|
|
1626
|
+
display: "flex",
|
|
1627
|
+
alignItems: "center",
|
|
1628
|
+
justifyContent: "center"
|
|
1629
|
+
}, children: renderCurrentStep() });
|
|
1630
|
+
};
|
|
1631
|
+
var EmailVerificationPage = ({
|
|
1632
|
+
token,
|
|
1633
|
+
onVerificationSuccess,
|
|
1634
|
+
onVerificationError,
|
|
1635
|
+
baseUrl
|
|
1636
|
+
}) => {
|
|
1637
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
1638
|
+
const [message, setMessage] = react.useState("");
|
|
1639
|
+
const [isSuccess, setIsSuccess] = react.useState(false);
|
|
1640
|
+
const { verifyEmailToken } = useAuth({
|
|
1641
|
+
baseUrl: baseUrl || (typeof window !== "undefined" ? window.location.origin : "http://localhost:7000")
|
|
1642
|
+
});
|
|
1643
|
+
react.useEffect(() => {
|
|
1644
|
+
const verifyEmail = async () => {
|
|
1645
|
+
if (!token) {
|
|
1646
|
+
setIsLoading(false);
|
|
1647
|
+
setMessage("Invalid verification token");
|
|
1648
|
+
setIsSuccess(false);
|
|
1649
|
+
onVerificationError?.("Invalid verification token");
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
try {
|
|
1653
|
+
const response = await verifyEmailToken(token);
|
|
1654
|
+
if (response.success) {
|
|
1655
|
+
setIsLoading(false);
|
|
1656
|
+
setMessage(response.message || "Email verified successfully!");
|
|
1657
|
+
setIsSuccess(true);
|
|
1658
|
+
onVerificationSuccess?.();
|
|
1659
|
+
} else {
|
|
1660
|
+
setIsLoading(false);
|
|
1661
|
+
setMessage(response.message || "Email verification failed");
|
|
1662
|
+
setIsSuccess(false);
|
|
1663
|
+
onVerificationError?.(response.message || "Email verification failed");
|
|
1664
|
+
}
|
|
1665
|
+
} catch (err) {
|
|
1666
|
+
setIsLoading(false);
|
|
1667
|
+
const errorMessage = err instanceof Error ? err.message : "An unknown error occurred";
|
|
1668
|
+
setMessage(errorMessage);
|
|
1669
|
+
setIsSuccess(false);
|
|
1670
|
+
onVerificationError?.(errorMessage);
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
verifyEmail();
|
|
1674
|
+
}, [token, verifyEmailToken, onVerificationSuccess, onVerificationError]);
|
|
1675
|
+
if (isLoading) {
|
|
1676
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1677
|
+
maxWidth: "500px",
|
|
1678
|
+
margin: "0 auto",
|
|
1679
|
+
padding: "30px",
|
|
1680
|
+
borderRadius: "12px",
|
|
1681
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.1)",
|
|
1682
|
+
backgroundColor: "#ffffff",
|
|
1683
|
+
textAlign: "center",
|
|
1684
|
+
border: "1px solid #eaeaea"
|
|
1685
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1686
|
+
padding: "20px"
|
|
1687
|
+
}, children: [
|
|
1688
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { color: "black" }, children: "Verifying your email..." }),
|
|
1689
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1690
|
+
border: "4px solid #f3f3f3",
|
|
1691
|
+
borderTop: "4px solid #007bff",
|
|
1692
|
+
borderRadius: "50%",
|
|
1693
|
+
width: "40px",
|
|
1694
|
+
height: "40px",
|
|
1695
|
+
animation: "spin 2s linear infinite",
|
|
1696
|
+
margin: "20px auto"
|
|
1697
|
+
} })
|
|
1698
|
+
] }) });
|
|
1699
|
+
}
|
|
1700
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1701
|
+
maxWidth: "500px",
|
|
1702
|
+
margin: "0 auto",
|
|
1703
|
+
padding: "30px",
|
|
1704
|
+
borderRadius: "12px",
|
|
1705
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.1)",
|
|
1706
|
+
backgroundColor: "#ffffff",
|
|
1707
|
+
textAlign: "center",
|
|
1708
|
+
border: "1px solid #eaeaea"
|
|
1709
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1710
|
+
padding: "20px"
|
|
1711
|
+
}, children: [
|
|
1712
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { style: { color: "black" }, children: "Email Verification" }),
|
|
1713
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
1714
|
+
padding: "16px 20px",
|
|
1715
|
+
margin: "24px 0",
|
|
1716
|
+
borderRadius: "8px",
|
|
1717
|
+
fontSize: "15px",
|
|
1718
|
+
fontWeight: 500,
|
|
1719
|
+
backgroundColor: isSuccess ? "#d4edda" : "#f8d7da",
|
|
1720
|
+
color: isSuccess ? "#155724" : "#721c24",
|
|
1721
|
+
border: isSuccess ? "1px solid #c3e6cb" : "1px solid #f5c6cb"
|
|
1722
|
+
}, children: message }),
|
|
1723
|
+
isSuccess && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
|
|
1724
|
+
marginTop: "24px"
|
|
1725
|
+
}, children: [
|
|
1726
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "black" }, children: "Your email has been successfully verified!" }),
|
|
1727
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1728
|
+
"button",
|
|
1729
|
+
{
|
|
1730
|
+
onClick: () => window.location.href = "/login",
|
|
1731
|
+
style: {
|
|
1732
|
+
padding: "12px 24px",
|
|
1733
|
+
backgroundColor: "#007bff",
|
|
1734
|
+
color: "white",
|
|
1735
|
+
border: "none",
|
|
1736
|
+
borderRadius: "8px",
|
|
1737
|
+
fontSize: "16px",
|
|
1738
|
+
fontWeight: 600,
|
|
1739
|
+
cursor: "pointer",
|
|
1740
|
+
transition: "all 0.2s ease"
|
|
1741
|
+
},
|
|
1742
|
+
children: "Go to Login"
|
|
1743
|
+
}
|
|
1744
|
+
)
|
|
1745
|
+
] })
|
|
1746
|
+
] }) });
|
|
1747
|
+
};
|
|
1748
|
+
var isServer = typeof window === "undefined";
|
|
1749
|
+
var useNextAuth = (config) => {
|
|
1750
|
+
const [authService] = react.useState(() => {
|
|
1751
|
+
const service = new AuthService(config);
|
|
1752
|
+
if (isServer && config.token) {
|
|
1753
|
+
service["token"] = config.token;
|
|
1754
|
+
service["httpClient"].setAuthToken(config.token);
|
|
1755
|
+
}
|
|
1756
|
+
return service;
|
|
1757
|
+
});
|
|
1758
|
+
const [user, setUser] = react.useState(null);
|
|
1759
|
+
const [isAuthenticated, setIsAuthenticated] = react.useState(false);
|
|
1760
|
+
const [loading, setLoading] = react.useState(true);
|
|
1761
|
+
const checkAuthStatus = react.useCallback(() => {
|
|
1762
|
+
if (isServer) {
|
|
1763
|
+
const token = config.token || authService.getToken();
|
|
1764
|
+
const authenticated = !!token;
|
|
1765
|
+
setIsAuthenticated(authenticated);
|
|
1766
|
+
if (authenticated && token) {
|
|
1767
|
+
try {
|
|
1768
|
+
const payload = JSON.parse(atob(token.split(".")[1]));
|
|
1769
|
+
setUser(payload.user || null);
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
console.error("Failed to parse user from token:", error);
|
|
1772
|
+
setUser(null);
|
|
1773
|
+
}
|
|
1774
|
+
} else {
|
|
1775
|
+
setUser(null);
|
|
1776
|
+
}
|
|
1777
|
+
} else {
|
|
1778
|
+
const authenticated = authService.isAuthenticated();
|
|
1779
|
+
setIsAuthenticated(authenticated);
|
|
1780
|
+
if (authenticated) {
|
|
1781
|
+
const currentUser = authService.getCurrentUser();
|
|
1782
|
+
setUser(currentUser);
|
|
1783
|
+
} else {
|
|
1784
|
+
setUser(null);
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
setLoading(false);
|
|
1788
|
+
}, [authService, config.token]);
|
|
1789
|
+
react.useEffect(() => {
|
|
1790
|
+
checkAuthStatus();
|
|
1791
|
+
}, [checkAuthStatus]);
|
|
1792
|
+
const register = react.useCallback(async (data) => {
|
|
1793
|
+
setLoading(true);
|
|
1794
|
+
try {
|
|
1795
|
+
const registerData = { ...data };
|
|
1796
|
+
if (!registerData.frontendBaseUrl && typeof window !== "undefined") {
|
|
1797
|
+
registerData.frontendBaseUrl = process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_APP_URL || process.env.REACT_APP_FRONTEND_BASE_URL || window.location.origin;
|
|
1798
|
+
}
|
|
1799
|
+
const response = await authService.register(registerData);
|
|
1800
|
+
return response;
|
|
1801
|
+
} finally {
|
|
1802
|
+
setLoading(false);
|
|
1803
|
+
}
|
|
1804
|
+
}, [authService]);
|
|
1805
|
+
const login = react.useCallback(async (data) => {
|
|
1806
|
+
setLoading(true);
|
|
1807
|
+
try {
|
|
1808
|
+
const response = await authService.login(data);
|
|
1809
|
+
return response;
|
|
1810
|
+
} finally {
|
|
1811
|
+
setLoading(false);
|
|
1812
|
+
}
|
|
1813
|
+
}, [authService]);
|
|
1814
|
+
const verify = react.useCallback(async (data) => {
|
|
1815
|
+
setLoading(true);
|
|
1816
|
+
try {
|
|
1817
|
+
const response = await authService.verify(data);
|
|
1818
|
+
if (response.success && response.user) {
|
|
1819
|
+
setUser(response.user);
|
|
1820
|
+
setIsAuthenticated(true);
|
|
1821
|
+
}
|
|
1822
|
+
return response;
|
|
1823
|
+
} finally {
|
|
1824
|
+
setLoading(false);
|
|
1825
|
+
}
|
|
1826
|
+
}, [authService]);
|
|
1827
|
+
const verifyEmailToken = react.useCallback(async (token) => {
|
|
1828
|
+
setLoading(true);
|
|
1829
|
+
try {
|
|
1830
|
+
const response = await authService.verifyEmailToken(token);
|
|
1831
|
+
if (response.success && response.user) {
|
|
1832
|
+
setUser(response.user);
|
|
1833
|
+
setIsAuthenticated(true);
|
|
1834
|
+
}
|
|
1835
|
+
return response;
|
|
1836
|
+
} finally {
|
|
1837
|
+
setLoading(false);
|
|
1838
|
+
}
|
|
1839
|
+
}, [authService]);
|
|
1840
|
+
const logout = react.useCallback(async () => {
|
|
1841
|
+
setLoading(true);
|
|
1842
|
+
try {
|
|
1843
|
+
await authService.logout();
|
|
1844
|
+
setUser(null);
|
|
1845
|
+
setIsAuthenticated(false);
|
|
1846
|
+
} finally {
|
|
1847
|
+
setLoading(false);
|
|
1848
|
+
}
|
|
1849
|
+
}, [authService]);
|
|
1850
|
+
const updateProfile = react.useCallback(async (data) => {
|
|
1851
|
+
setLoading(true);
|
|
1852
|
+
try {
|
|
1853
|
+
const response = await authService.updateProfile(data);
|
|
1854
|
+
if (response.success && response.user) {
|
|
1855
|
+
setUser(response.user);
|
|
1856
|
+
}
|
|
1857
|
+
return response;
|
|
1858
|
+
} finally {
|
|
1859
|
+
setLoading(false);
|
|
1860
|
+
}
|
|
1861
|
+
}, [authService]);
|
|
1862
|
+
const getProfile = react.useCallback(async () => {
|
|
1863
|
+
setLoading(true);
|
|
1864
|
+
try {
|
|
1865
|
+
const userData = await authService.getProfile();
|
|
1866
|
+
setUser(userData);
|
|
1867
|
+
return userData;
|
|
1868
|
+
} finally {
|
|
1869
|
+
setLoading(false);
|
|
1870
|
+
}
|
|
1871
|
+
}, [authService]);
|
|
1872
|
+
const getAllUsers = react.useCallback(async () => {
|
|
1873
|
+
setLoading(true);
|
|
1874
|
+
try {
|
|
1875
|
+
return await authService.getAllUsers();
|
|
1876
|
+
} finally {
|
|
1877
|
+
setLoading(false);
|
|
1878
|
+
}
|
|
1879
|
+
}, [authService]);
|
|
1880
|
+
const getUserById = react.useCallback(async (id) => {
|
|
1881
|
+
setLoading(true);
|
|
1882
|
+
try {
|
|
1883
|
+
return await authService.getUserById(id);
|
|
1884
|
+
} finally {
|
|
1885
|
+
setLoading(false);
|
|
1886
|
+
}
|
|
1887
|
+
}, [authService]);
|
|
1888
|
+
const forgotPassword = react.useCallback(async (email) => {
|
|
1889
|
+
setLoading(true);
|
|
1890
|
+
try {
|
|
1891
|
+
const response = await authService.forgotPassword(email);
|
|
1892
|
+
return response;
|
|
1893
|
+
} finally {
|
|
1894
|
+
setLoading(false);
|
|
1895
|
+
}
|
|
1896
|
+
}, [authService]);
|
|
1897
|
+
const resetPassword = react.useCallback(async (token, password) => {
|
|
1898
|
+
setLoading(true);
|
|
1899
|
+
try {
|
|
1900
|
+
const response = await authService.resetPassword(token, password);
|
|
1901
|
+
return response;
|
|
1902
|
+
} finally {
|
|
1903
|
+
setLoading(false);
|
|
1904
|
+
}
|
|
1905
|
+
}, [authService]);
|
|
1906
|
+
const setToken = react.useCallback((token) => {
|
|
1907
|
+
authService["token"] = token;
|
|
1908
|
+
authService["httpClient"].setAuthToken(token);
|
|
1909
|
+
setIsAuthenticated(true);
|
|
1910
|
+
try {
|
|
1911
|
+
const payload = JSON.parse(atob(token.split(".")[1]));
|
|
1912
|
+
setUser(payload.user || null);
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
console.error("Failed to parse user from token:", error);
|
|
1915
|
+
setUser(null);
|
|
1916
|
+
}
|
|
1917
|
+
}, [authService]);
|
|
1918
|
+
const clearToken = react.useCallback(() => {
|
|
1919
|
+
authService["token"] = null;
|
|
1920
|
+
authService["httpClient"].removeAuthToken();
|
|
1921
|
+
setIsAuthenticated(false);
|
|
1922
|
+
setUser(null);
|
|
1923
|
+
}, [authService]);
|
|
1924
|
+
return {
|
|
1925
|
+
user,
|
|
1926
|
+
isAuthenticated,
|
|
1927
|
+
loading,
|
|
1928
|
+
register,
|
|
1929
|
+
login,
|
|
1930
|
+
verify,
|
|
1931
|
+
verifyEmailToken,
|
|
1932
|
+
logout,
|
|
1933
|
+
updateProfile,
|
|
1934
|
+
getProfile,
|
|
1935
|
+
getAllUsers,
|
|
1936
|
+
getUserById,
|
|
1937
|
+
forgotPassword,
|
|
1938
|
+
resetPassword,
|
|
1939
|
+
setToken,
|
|
1940
|
+
clearToken
|
|
1941
|
+
};
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// src/node/auth-client.ts
|
|
1945
|
+
var AuthClient = class extends AuthService {
|
|
1946
|
+
constructor(config) {
|
|
1947
|
+
super(config);
|
|
1948
|
+
}
|
|
1949
|
+
// Override methods that require browser-specific features
|
|
1950
|
+
// For Node.js, token persistence must be handled manually
|
|
1951
|
+
async register(data) {
|
|
1952
|
+
const registerData = { ...data };
|
|
1953
|
+
if (!registerData.frontendBaseUrl) {
|
|
1954
|
+
registerData.frontendBaseUrl = process.env.FRONTEND_BASE_URL || process.env.NEXT_PUBLIC_FRONTEND_BASE_URL || process.env.REACT_APP_FRONTEND_BASE_URL;
|
|
1955
|
+
}
|
|
1956
|
+
const response = await this["httpClient"].post("/api/v1/auth/register", registerData);
|
|
1957
|
+
if (response.success && response.message === "Registration data saved. Verification email sent. Please check your inbox.") {
|
|
1958
|
+
return response;
|
|
1959
|
+
}
|
|
1960
|
+
throw new Error(response.message || "Registration failed");
|
|
1961
|
+
}
|
|
1962
|
+
async login(data) {
|
|
1963
|
+
const response = await this["httpClient"].post("/api/v1/auth/login", data);
|
|
1964
|
+
if (response.success && response.token) {
|
|
1965
|
+
this["token"] = response.token;
|
|
1966
|
+
this["httpClient"].setAuthToken(response.token);
|
|
1967
|
+
return response;
|
|
1968
|
+
}
|
|
1969
|
+
if (response.success && response.message === "OTP sent to your email.") {
|
|
1970
|
+
return response;
|
|
1971
|
+
}
|
|
1972
|
+
if (response.success && response.message === "OTP verified successfully." && response.token) {
|
|
1973
|
+
this["token"] = response.token;
|
|
1974
|
+
this["httpClient"].setAuthToken(response.token);
|
|
1975
|
+
return response;
|
|
1976
|
+
}
|
|
1977
|
+
throw new Error(response.message || "Login failed");
|
|
1978
|
+
}
|
|
1979
|
+
async verify(data) {
|
|
1980
|
+
const response = await this["httpClient"].post("/api/v1/auth/verify", data);
|
|
1981
|
+
if (response.success && response.token) {
|
|
1982
|
+
this["token"] = response.token;
|
|
1983
|
+
this["httpClient"].setAuthToken(response.token);
|
|
1984
|
+
}
|
|
1985
|
+
return response;
|
|
1986
|
+
}
|
|
1987
|
+
async logout() {
|
|
1988
|
+
this["token"] = null;
|
|
1989
|
+
this["httpClient"].removeAuthToken();
|
|
1990
|
+
}
|
|
1991
|
+
async getProfile() {
|
|
1992
|
+
if (!this["token"]) {
|
|
1993
|
+
throw new Error("Not authenticated");
|
|
1994
|
+
}
|
|
1995
|
+
const response = await this["httpClient"].get("/api/v1/user/me");
|
|
1996
|
+
return response.user;
|
|
1997
|
+
}
|
|
1998
|
+
async getUserById(id) {
|
|
1999
|
+
const response = await this["httpClient"].get(`/api/v1/user/${id}`);
|
|
2000
|
+
return response.user;
|
|
2001
|
+
}
|
|
2002
|
+
async updateProfile(data) {
|
|
2003
|
+
if (!this["token"]) {
|
|
2004
|
+
throw new Error("Not authenticated");
|
|
2005
|
+
}
|
|
2006
|
+
const response = await this["httpClient"].post("/api/v1/user/update/name", data);
|
|
2007
|
+
if (response.success && response.token) {
|
|
2008
|
+
this["token"] = response.token;
|
|
2009
|
+
this["httpClient"].setAuthToken(response.token);
|
|
2010
|
+
}
|
|
2011
|
+
return response;
|
|
2012
|
+
}
|
|
2013
|
+
async getAllUsers() {
|
|
2014
|
+
if (!this["token"]) {
|
|
2015
|
+
throw new Error("Not authenticated");
|
|
2016
|
+
}
|
|
2017
|
+
const response = await this["httpClient"].get("/api/v1/user/all");
|
|
2018
|
+
return response.users;
|
|
2019
|
+
}
|
|
2020
|
+
};
|
|
2021
|
+
|
|
2022
|
+
// src/nextjs/server-auth.ts
|
|
2023
|
+
var NextServerAuth = class extends AuthClient {
|
|
2024
|
+
constructor(config) {
|
|
2025
|
+
super(config);
|
|
2026
|
+
}
|
|
2027
|
+
// Parse token from request headers
|
|
2028
|
+
static parseTokenFromHeaders(headers) {
|
|
2029
|
+
const authHeader = headers.get("authorization");
|
|
2030
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
2031
|
+
return null;
|
|
2032
|
+
}
|
|
2033
|
+
return authHeader.substring(7);
|
|
2034
|
+
}
|
|
2035
|
+
// Parse token from cookies
|
|
2036
|
+
static parseTokenFromCookies(cookies) {
|
|
2037
|
+
const cookieArray = cookies.split(";");
|
|
2038
|
+
for (const cookie of cookieArray) {
|
|
2039
|
+
const [name, value] = cookie.trim().split("=");
|
|
2040
|
+
if (name === "auth_token") {
|
|
2041
|
+
return decodeURIComponent(value);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
return null;
|
|
2045
|
+
}
|
|
2046
|
+
// Parse token from Next.js request object
|
|
2047
|
+
static parseTokenFromRequest(req) {
|
|
2048
|
+
if (req.headers) {
|
|
2049
|
+
const authHeader = req.headers.authorization || req.headers.Authorization;
|
|
2050
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
2051
|
+
return authHeader.substring(7);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
if (req.cookies) {
|
|
2055
|
+
return req.cookies.auth_token || null;
|
|
2056
|
+
}
|
|
2057
|
+
if (req.headers && req.headers.cookie) {
|
|
2058
|
+
return this.parseTokenFromCookies(req.headers.cookie);
|
|
2059
|
+
}
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
2062
|
+
// Verify token and get user
|
|
2063
|
+
async verifyToken(token) {
|
|
2064
|
+
try {
|
|
2065
|
+
this["httpClient"].setAuthToken(token);
|
|
2066
|
+
const user = await this.getProfile();
|
|
2067
|
+
return user;
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
console.error("Token verification failed:", error);
|
|
2070
|
+
return null;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
// Create authenticated client with token
|
|
2074
|
+
static createAuthenticatedClient(config, token) {
|
|
2075
|
+
const client = new NextServerAuth(config);
|
|
2076
|
+
client["httpClient"].setAuthToken(token);
|
|
2077
|
+
client["token"] = token;
|
|
2078
|
+
return client;
|
|
2079
|
+
}
|
|
2080
|
+
};
|
|
2081
|
+
|
|
2082
|
+
exports.AuthFlow = AuthFlow;
|
|
2083
|
+
exports.AuthService = AuthService;
|
|
2084
|
+
exports.EmailVerificationPage = EmailVerificationPage;
|
|
2085
|
+
exports.HttpClient = HttpClient;
|
|
2086
|
+
exports.LoginForm = LoginForm;
|
|
2087
|
+
exports.NextServerAuth = NextServerAuth;
|
|
2088
|
+
exports.OtpForm = OtpForm;
|
|
2089
|
+
exports.RegisterForm = RegisterForm;
|
|
2090
|
+
exports.useAuth = useAuth;
|
|
2091
|
+
exports.useNextAuth = useNextAuth;
|
|
2092
|
+
//# sourceMappingURL=out.js.map
|
|
2093
|
+
//# sourceMappingURL=index.next.js.map
|