@rqdhw3n/react-auth-flow 1.0.1 → 1.0.3

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.
@@ -0,0 +1,944 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const React = require("react");
5
+ const reactRouterDom = require("react-router-dom");
6
+ const AuthContext = React.createContext(
7
+ void 0
8
+ );
9
+ AuthContext.displayName = "AuthContext";
10
+ function normalizeError(error) {
11
+ if (isAuthError(error)) {
12
+ return error;
13
+ }
14
+ if (error instanceof Error) {
15
+ return {
16
+ code: "ERROR",
17
+ message: error.message,
18
+ statusCode: void 0
19
+ };
20
+ }
21
+ if (typeof error === "object" && error !== null && "status" in error && "statusText" in error) {
22
+ const fetchError = error;
23
+ return {
24
+ code: `HTTP_${fetchError.status}`,
25
+ message: fetchError.statusText || "Request failed",
26
+ statusCode: fetchError.status
27
+ };
28
+ }
29
+ if (typeof error === "object" && error !== null && "error" in error && typeof error.error === "object") {
30
+ const apiError = error.error;
31
+ return {
32
+ code: apiError.code || "API_ERROR",
33
+ message: apiError.message || "An error occurred",
34
+ statusCode: apiError.statusCode || void 0,
35
+ details: apiError.details
36
+ };
37
+ }
38
+ if (typeof error === "object" && error !== null && "message" in error) {
39
+ const objError = error;
40
+ return {
41
+ code: objError.code || "ERROR",
42
+ message: typeof objError.message === "string" ? objError.message : "An unknown error occurred"
43
+ };
44
+ }
45
+ if (typeof error === "string") {
46
+ return {
47
+ code: "ERROR",
48
+ message: error
49
+ };
50
+ }
51
+ return {
52
+ code: "UNKNOWN_ERROR",
53
+ message: "An unknown error occurred"
54
+ };
55
+ }
56
+ function isAuthError(error) {
57
+ return typeof error === "object" && error !== null && "code" in error && "message" in error && typeof error.code === "string" && typeof error.message === "string";
58
+ }
59
+ const DEFAULT_ENDPOINTS = {
60
+ login: "/auth/login",
61
+ register: "/auth/register",
62
+ logout: "/auth/logout",
63
+ me: "/auth/me",
64
+ refresh: "/auth/refresh",
65
+ forgotPassword: "/auth/forgot-password",
66
+ resetPassword: "/auth/reset-password",
67
+ verifyEmail: "/auth/verify-email"
68
+ };
69
+ const defaultAdapter = async (url, options) => {
70
+ const response = await fetch(url, options);
71
+ return response;
72
+ };
73
+ function createAuthClient(config = {}) {
74
+ const {
75
+ baseURL = "",
76
+ endpoints = {},
77
+ headers = {},
78
+ credentials = "include",
79
+ adapter = defaultAdapter
80
+ } = config;
81
+ const finalEndpoints = { ...DEFAULT_ENDPOINTS, ...endpoints };
82
+ async function request(method, endpoint, data) {
83
+ const url = `${baseURL}${endpoint}`;
84
+ const options = {
85
+ method,
86
+ credentials,
87
+ headers: {
88
+ "Content-Type": "application/json",
89
+ ...headers
90
+ }
91
+ };
92
+ if (data) {
93
+ options.body = JSON.stringify(data);
94
+ }
95
+ try {
96
+ const response = await adapter(url, options);
97
+ if (!response.ok) {
98
+ let errorData = null;
99
+ try {
100
+ errorData = await response.json();
101
+ } catch {
102
+ errorData = {
103
+ error: {
104
+ message: response.statusText,
105
+ statusCode: response.status
106
+ }
107
+ };
108
+ }
109
+ throw errorData;
110
+ }
111
+ const contentType = response.headers.get("content-type");
112
+ if (contentType && contentType.includes("application/json")) {
113
+ return await response.json();
114
+ }
115
+ return {};
116
+ } catch (error) {
117
+ throw normalizeError(error);
118
+ }
119
+ }
120
+ return {
121
+ /**
122
+ * Login with email and password
123
+ */
124
+ async login(email, password, rememberMe) {
125
+ const response = await request(
126
+ "POST",
127
+ finalEndpoints.login,
128
+ { email, password, rememberMe }
129
+ );
130
+ return response;
131
+ },
132
+ /**
133
+ * Register a new account
134
+ */
135
+ async register(payload) {
136
+ const response = await request(
137
+ "POST",
138
+ finalEndpoints.register,
139
+ payload
140
+ );
141
+ return response;
142
+ },
143
+ /**
144
+ * Logout the user
145
+ */
146
+ async logout() {
147
+ await request("POST", finalEndpoints.logout);
148
+ },
149
+ /**
150
+ * Get current user
151
+ */
152
+ async me() {
153
+ const response = await request(
154
+ "GET",
155
+ finalEndpoints.me
156
+ );
157
+ return response;
158
+ },
159
+ /**
160
+ * Refresh the authentication session
161
+ */
162
+ async refresh() {
163
+ const response = await request(
164
+ "POST",
165
+ finalEndpoints.refresh
166
+ );
167
+ return response;
168
+ },
169
+ /**
170
+ * Request a password reset
171
+ */
172
+ async forgotPassword(email) {
173
+ await request("POST", finalEndpoints.forgotPassword, { email });
174
+ },
175
+ /**
176
+ * Reset password with token
177
+ */
178
+ async resetPassword(token, password, confirmPassword) {
179
+ await request("POST", finalEndpoints.resetPassword, {
180
+ token,
181
+ password,
182
+ confirmPassword
183
+ });
184
+ },
185
+ /**
186
+ * Verify email with token
187
+ */
188
+ async verifyEmail(token, email) {
189
+ await request("POST", finalEndpoints.verifyEmail, { token, email });
190
+ },
191
+ /**
192
+ * Set custom headers for subsequent requests
193
+ */
194
+ setHeaders(newHeaders) {
195
+ Object.assign(headers, newHeaders);
196
+ },
197
+ /**
198
+ * Get current endpoints configuration
199
+ */
200
+ getEndpoints() {
201
+ return finalEndpoints;
202
+ }
203
+ };
204
+ }
205
+ const initialState = {
206
+ user: null,
207
+ isAuthenticated: false,
208
+ isLoading: false,
209
+ error: null
210
+ };
211
+ function authReducer(state, action) {
212
+ switch (action.type) {
213
+ case "SET_LOADING":
214
+ return { ...state, isLoading: action.payload };
215
+ case "SET_ERROR":
216
+ return { ...state, error: action.payload, isLoading: false };
217
+ case "SET_USER":
218
+ return {
219
+ ...state,
220
+ user: action.payload,
221
+ isAuthenticated: action.payload !== null,
222
+ error: null,
223
+ isLoading: false
224
+ };
225
+ case "LOGOUT":
226
+ return initialState;
227
+ default:
228
+ return state;
229
+ }
230
+ }
231
+ const AuthProvider = ({
232
+ children,
233
+ baseURL = "",
234
+ endpoints = {},
235
+ onAuthError,
236
+ autoRefresh = true,
237
+ refreshInterval = 5 * 60 * 1e3
238
+ // 5 minutes
239
+ }) => {
240
+ const [state, dispatch] = React.useReducer(authReducer, initialState);
241
+ const clientRef = React.useRef(
242
+ createAuthClient({
243
+ baseURL,
244
+ endpoints,
245
+ credentials: "include"
246
+ })
247
+ );
248
+ const client = clientRef.current;
249
+ const handleError = React.useCallback(
250
+ (error) => {
251
+ dispatch({ type: "SET_ERROR", payload: error });
252
+ onAuthError?.(error);
253
+ },
254
+ [onAuthError]
255
+ );
256
+ const restoreSession = React.useCallback(async () => {
257
+ dispatch({ type: "SET_LOADING", payload: true });
258
+ try {
259
+ const response = await client.me();
260
+ if (response.user) {
261
+ dispatch({ type: "SET_USER", payload: response.user });
262
+ } else {
263
+ dispatch({ type: "LOGOUT" });
264
+ }
265
+ } catch (_error) {
266
+ dispatch({ type: "SET_LOADING", payload: false });
267
+ }
268
+ }, [client]);
269
+ const refreshSession = React.useCallback(async () => {
270
+ try {
271
+ const response = await client.refresh();
272
+ if (response.user) {
273
+ dispatch({ type: "SET_USER", payload: response.user });
274
+ }
275
+ } catch (error) {
276
+ const authError = normalizeError(error);
277
+ handleError(authError);
278
+ }
279
+ }, [client, handleError]);
280
+ const login = React.useCallback(
281
+ async (payload) => {
282
+ dispatch({ type: "SET_LOADING", payload: true });
283
+ try {
284
+ const response = await client.login(payload.email, payload.password);
285
+ if (!response.user) {
286
+ throw new Error("No user data in response");
287
+ }
288
+ dispatch({ type: "SET_USER", payload: response.user });
289
+ return response.user;
290
+ } catch (error) {
291
+ const authError = normalizeError(error);
292
+ handleError(authError);
293
+ throw authError;
294
+ }
295
+ },
296
+ [client, handleError]
297
+ );
298
+ const register = React.useCallback(
299
+ async (payload) => {
300
+ dispatch({ type: "SET_LOADING", payload: true });
301
+ try {
302
+ const response = await client.register(payload);
303
+ if (!response.user) {
304
+ throw new Error("No user data in response");
305
+ }
306
+ dispatch({ type: "SET_USER", payload: response.user });
307
+ return response.user;
308
+ } catch (error) {
309
+ const authError = normalizeError(error);
310
+ handleError(authError);
311
+ throw authError;
312
+ }
313
+ },
314
+ [client, handleError]
315
+ );
316
+ const logout = React.useCallback(async () => {
317
+ dispatch({ type: "SET_LOADING", payload: true });
318
+ try {
319
+ await client.logout();
320
+ } catch (error) {
321
+ console.error("Logout error:", error);
322
+ } finally {
323
+ dispatch({ type: "LOGOUT" });
324
+ }
325
+ }, [client]);
326
+ const forgotPassword = React.useCallback(
327
+ async (payload) => {
328
+ dispatch({ type: "SET_LOADING", payload: true });
329
+ try {
330
+ await client.forgotPassword(payload.email);
331
+ dispatch({ type: "SET_LOADING", payload: false });
332
+ } catch (error) {
333
+ const authError = normalizeError(error);
334
+ handleError(authError);
335
+ throw authError;
336
+ }
337
+ },
338
+ [client, handleError]
339
+ );
340
+ const resetPassword = React.useCallback(
341
+ async (payload) => {
342
+ dispatch({ type: "SET_LOADING", payload: true });
343
+ try {
344
+ await client.resetPassword(
345
+ payload.token,
346
+ payload.password,
347
+ payload.confirmPassword
348
+ );
349
+ dispatch({ type: "SET_LOADING", payload: false });
350
+ } catch (error) {
351
+ const authError = normalizeError(error);
352
+ handleError(authError);
353
+ throw authError;
354
+ }
355
+ },
356
+ [client, handleError]
357
+ );
358
+ const verifyEmail = React.useCallback(
359
+ async (payload) => {
360
+ dispatch({ type: "SET_LOADING", payload: true });
361
+ try {
362
+ await client.verifyEmail(payload.token, payload.email);
363
+ dispatch({ type: "SET_LOADING", payload: false });
364
+ } catch (error) {
365
+ const authError = normalizeError(error);
366
+ handleError(authError);
367
+ throw authError;
368
+ }
369
+ },
370
+ [client, handleError]
371
+ );
372
+ const setUser = React.useCallback((user) => {
373
+ dispatch({ type: "SET_USER", payload: user });
374
+ }, []);
375
+ React.useEffect(() => {
376
+ restoreSession();
377
+ }, [restoreSession]);
378
+ React.useEffect(() => {
379
+ if (!autoRefresh || !state.isAuthenticated) {
380
+ return;
381
+ }
382
+ const interval = setInterval(() => {
383
+ refreshSession();
384
+ }, refreshInterval);
385
+ return () => clearInterval(interval);
386
+ }, [autoRefresh, state.isAuthenticated, refreshSession, refreshInterval]);
387
+ const value = {
388
+ ...state,
389
+ login,
390
+ register,
391
+ logout,
392
+ forgotPassword,
393
+ resetPassword,
394
+ verifyEmail,
395
+ refreshSession,
396
+ restoreSession,
397
+ setUser
398
+ };
399
+ return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
400
+ };
401
+ function useAuth() {
402
+ const context = React.useContext(AuthContext);
403
+ if (!context) {
404
+ throw new Error("useAuth must be used within an AuthProvider");
405
+ }
406
+ return context;
407
+ }
408
+ const LoginForm = ({
409
+ className = "",
410
+ labels = {},
411
+ placeholders = {},
412
+ submitButtonText = "Login",
413
+ onSuccess,
414
+ onError
415
+ }) => {
416
+ const { login, isLoading: authLoading, error: authError } = useAuth();
417
+ const [formError, setFormError] = React.useState("");
418
+ const [email, setEmail] = React.useState("");
419
+ const [password, setPassword] = React.useState("");
420
+ const [rememberMe, setRememberMe] = React.useState(false);
421
+ const isLoading = authLoading;
422
+ const error = formError || authError?.message;
423
+ const handleSubmit = async (e) => {
424
+ e.preventDefault();
425
+ setFormError("");
426
+ if (!email || !password) {
427
+ setFormError("Email and password are required");
428
+ return;
429
+ }
430
+ try {
431
+ const user = await login({ email, password, rememberMe });
432
+ onSuccess?.(user);
433
+ } catch (err) {
434
+ const errorMsg = err instanceof Error ? err.message : "Login failed";
435
+ setFormError(errorMsg);
436
+ onError?.({
437
+ code: "LOGIN_ERROR",
438
+ message: errorMsg
439
+ });
440
+ }
441
+ };
442
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, children: [
443
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
444
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", className: "auth-form-label", children: labels.email || "Email" }),
445
+ /* @__PURE__ */ jsxRuntime.jsx(
446
+ "input",
447
+ {
448
+ id: "email",
449
+ type: "email",
450
+ value: email,
451
+ onChange: (e) => setEmail(e.target.value),
452
+ placeholder: placeholders.email || "your@email.com",
453
+ disabled: isLoading,
454
+ className: "auth-form-input",
455
+ required: true
456
+ }
457
+ )
458
+ ] }),
459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
460
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "password", className: "auth-form-label", children: labels.password || "Password" }),
461
+ /* @__PURE__ */ jsxRuntime.jsx(
462
+ "input",
463
+ {
464
+ id: "password",
465
+ type: "password",
466
+ value: password,
467
+ onChange: (e) => setPassword(e.target.value),
468
+ placeholder: placeholders.password || "••••••••",
469
+ disabled: isLoading,
470
+ className: "auth-form-input",
471
+ required: true
472
+ }
473
+ )
474
+ ] }),
475
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group auth-form-checkbox", children: [
476
+ /* @__PURE__ */ jsxRuntime.jsx(
477
+ "input",
478
+ {
479
+ id: "rememberMe",
480
+ type: "checkbox",
481
+ checked: rememberMe,
482
+ onChange: (e) => setRememberMe(e.target.checked),
483
+ disabled: isLoading,
484
+ className: "auth-form-input"
485
+ }
486
+ ),
487
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "rememberMe", className: "auth-form-label", children: labels.rememberMe || "Remember me" })
488
+ ] }),
489
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-form-error", children: error }),
490
+ /* @__PURE__ */ jsxRuntime.jsx(
491
+ "button",
492
+ {
493
+ type: "submit",
494
+ disabled: isLoading,
495
+ className: "auth-form-button auth-form-button-primary",
496
+ children: isLoading ? "Loading..." : submitButtonText
497
+ }
498
+ )
499
+ ] });
500
+ };
501
+ LoginForm.displayName = "LoginForm";
502
+ const RegisterForm = ({
503
+ className = "",
504
+ labels = {},
505
+ placeholders = {},
506
+ submitButtonText = "Register",
507
+ onSuccess,
508
+ onError
509
+ }) => {
510
+ const { register, isLoading: authLoading, error: authError } = useAuth();
511
+ const [formError, setFormError] = React.useState("");
512
+ const [name, setName] = React.useState("");
513
+ const [email, setEmail] = React.useState("");
514
+ const [password, setPassword] = React.useState("");
515
+ const [confirmPassword, setConfirmPassword] = React.useState("");
516
+ const isLoading = authLoading;
517
+ const error = formError || authError?.message;
518
+ const handleSubmit = async (e) => {
519
+ e.preventDefault();
520
+ setFormError("");
521
+ if (!name || !email || !password || !confirmPassword) {
522
+ setFormError("All fields are required");
523
+ return;
524
+ }
525
+ if (password !== confirmPassword) {
526
+ setFormError("Passwords do not match");
527
+ return;
528
+ }
529
+ if (password.length < 8) {
530
+ setFormError("Password must be at least 8 characters");
531
+ return;
532
+ }
533
+ try {
534
+ const user = await register({
535
+ name,
536
+ email,
537
+ password,
538
+ confirmPassword
539
+ });
540
+ onSuccess?.(user);
541
+ } catch (err) {
542
+ const errorMsg = err instanceof Error ? err.message : "Registration failed";
543
+ setFormError(errorMsg);
544
+ onError?.({
545
+ code: "REGISTER_ERROR",
546
+ message: errorMsg
547
+ });
548
+ }
549
+ };
550
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, children: [
551
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
552
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "name", className: "auth-form-label", children: labels.name || "Full Name" }),
553
+ /* @__PURE__ */ jsxRuntime.jsx(
554
+ "input",
555
+ {
556
+ id: "name",
557
+ type: "text",
558
+ value: name,
559
+ onChange: (e) => setName(e.target.value),
560
+ placeholder: placeholders.name || "John Doe",
561
+ disabled: isLoading,
562
+ className: "auth-form-input",
563
+ required: true
564
+ }
565
+ )
566
+ ] }),
567
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
568
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", className: "auth-form-label", children: labels.email || "Email" }),
569
+ /* @__PURE__ */ jsxRuntime.jsx(
570
+ "input",
571
+ {
572
+ id: "email",
573
+ type: "email",
574
+ value: email,
575
+ onChange: (e) => setEmail(e.target.value),
576
+ placeholder: placeholders.email || "your@email.com",
577
+ disabled: isLoading,
578
+ className: "auth-form-input",
579
+ required: true
580
+ }
581
+ )
582
+ ] }),
583
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
584
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "password", className: "auth-form-label", children: labels.password || "Password" }),
585
+ /* @__PURE__ */ jsxRuntime.jsx(
586
+ "input",
587
+ {
588
+ id: "password",
589
+ type: "password",
590
+ value: password,
591
+ onChange: (e) => setPassword(e.target.value),
592
+ placeholder: placeholders.password || "••••••••",
593
+ disabled: isLoading,
594
+ className: "auth-form-input",
595
+ required: true
596
+ }
597
+ )
598
+ ] }),
599
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
600
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirmPassword", className: "auth-form-label", children: labels.confirmPassword || "Confirm Password" }),
601
+ /* @__PURE__ */ jsxRuntime.jsx(
602
+ "input",
603
+ {
604
+ id: "confirmPassword",
605
+ type: "password",
606
+ value: confirmPassword,
607
+ onChange: (e) => setConfirmPassword(e.target.value),
608
+ placeholder: placeholders.confirmPassword || "••••••••",
609
+ disabled: isLoading,
610
+ className: "auth-form-input",
611
+ required: true
612
+ }
613
+ )
614
+ ] }),
615
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-form-error", children: error }),
616
+ /* @__PURE__ */ jsxRuntime.jsx(
617
+ "button",
618
+ {
619
+ type: "submit",
620
+ disabled: isLoading,
621
+ className: "auth-form-button auth-form-button-primary",
622
+ children: isLoading ? "Loading..." : submitButtonText
623
+ }
624
+ )
625
+ ] });
626
+ };
627
+ RegisterForm.displayName = "RegisterForm";
628
+ const ForgotPasswordForm = ({
629
+ className = "",
630
+ labels = {},
631
+ placeholders = {},
632
+ submitButtonText = "Send Reset Link",
633
+ onSuccess,
634
+ onError
635
+ }) => {
636
+ const {
637
+ forgotPassword,
638
+ isLoading: authLoading,
639
+ error: authError
640
+ } = useAuth();
641
+ const [formError, setFormError] = React.useState("");
642
+ const [email, setEmail] = React.useState("");
643
+ const [successMessage, setSuccessMessage] = React.useState("");
644
+ const isLoading = authLoading;
645
+ const error = formError || authError?.message;
646
+ const handleSubmit = async (e) => {
647
+ e.preventDefault();
648
+ setFormError("");
649
+ setSuccessMessage("");
650
+ if (!email) {
651
+ setFormError("Email is required");
652
+ return;
653
+ }
654
+ try {
655
+ await forgotPassword({ email });
656
+ setSuccessMessage("Password reset link has been sent to your email");
657
+ setEmail("");
658
+ onSuccess?.();
659
+ } catch (err) {
660
+ const errorMsg = err instanceof Error ? err.message : "Request failed";
661
+ setFormError(errorMsg);
662
+ onError?.({
663
+ code: "FORGOT_PASSWORD_ERROR",
664
+ message: errorMsg
665
+ });
666
+ }
667
+ };
668
+ if (successMessage) {
669
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `auth-form-success ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "auth-form-success-message", children: successMessage }) });
670
+ }
671
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, children: [
672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
673
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", className: "auth-form-label", children: labels.email || "Email" }),
674
+ /* @__PURE__ */ jsxRuntime.jsx(
675
+ "input",
676
+ {
677
+ id: "email",
678
+ type: "email",
679
+ value: email,
680
+ onChange: (e) => setEmail(e.target.value),
681
+ placeholder: placeholders.email || "your@email.com",
682
+ disabled: isLoading,
683
+ className: "auth-form-input",
684
+ required: true
685
+ }
686
+ )
687
+ ] }),
688
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-form-error", children: error }),
689
+ /* @__PURE__ */ jsxRuntime.jsx(
690
+ "button",
691
+ {
692
+ type: "submit",
693
+ disabled: isLoading,
694
+ className: "auth-form-button auth-form-button-primary",
695
+ children: isLoading ? "Loading..." : submitButtonText
696
+ }
697
+ )
698
+ ] });
699
+ };
700
+ ForgotPasswordForm.displayName = "ForgotPasswordForm";
701
+ const ResetPasswordForm = ({
702
+ token,
703
+ className = "",
704
+ labels = {},
705
+ placeholders = {},
706
+ submitButtonText = "Reset Password",
707
+ onSuccess,
708
+ onError
709
+ }) => {
710
+ const {
711
+ resetPassword,
712
+ isLoading: authLoading,
713
+ error: authError
714
+ } = useAuth();
715
+ const [formError, setFormError] = React.useState("");
716
+ const [password, setPassword] = React.useState("");
717
+ const [confirmPassword, setConfirmPassword] = React.useState("");
718
+ const [successMessage, setSuccessMessage] = React.useState("");
719
+ const isLoading = authLoading;
720
+ const error = formError || authError?.message;
721
+ const handleSubmit = async (e) => {
722
+ e.preventDefault();
723
+ setFormError("");
724
+ setSuccessMessage("");
725
+ if (!password || !confirmPassword) {
726
+ setFormError("Both password fields are required");
727
+ return;
728
+ }
729
+ if (password !== confirmPassword) {
730
+ setFormError("Passwords do not match");
731
+ return;
732
+ }
733
+ if (password.length < 8) {
734
+ setFormError("Password must be at least 8 characters");
735
+ return;
736
+ }
737
+ try {
738
+ await resetPassword({ token, password, confirmPassword });
739
+ setSuccessMessage("Password has been reset successfully");
740
+ setPassword("");
741
+ setConfirmPassword("");
742
+ onSuccess?.();
743
+ } catch (err) {
744
+ const errorMsg = err instanceof Error ? err.message : "Reset failed";
745
+ setFormError(errorMsg);
746
+ onError?.({
747
+ code: "RESET_PASSWORD_ERROR",
748
+ message: errorMsg
749
+ });
750
+ }
751
+ };
752
+ if (successMessage) {
753
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `auth-form-success ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "auth-form-success-message", children: successMessage }) });
754
+ }
755
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, children: [
756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
757
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "password", className: "auth-form-label", children: labels.password || "New Password" }),
758
+ /* @__PURE__ */ jsxRuntime.jsx(
759
+ "input",
760
+ {
761
+ id: "password",
762
+ type: "password",
763
+ value: password,
764
+ onChange: (e) => setPassword(e.target.value),
765
+ placeholder: placeholders.password || "••••••••",
766
+ disabled: isLoading,
767
+ className: "auth-form-input",
768
+ required: true
769
+ }
770
+ )
771
+ ] }),
772
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
773
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "confirmPassword", className: "auth-form-label", children: labels.confirmPassword || "Confirm Password" }),
774
+ /* @__PURE__ */ jsxRuntime.jsx(
775
+ "input",
776
+ {
777
+ id: "confirmPassword",
778
+ type: "password",
779
+ value: confirmPassword,
780
+ onChange: (e) => setConfirmPassword(e.target.value),
781
+ placeholder: placeholders.confirmPassword || "••••••••",
782
+ disabled: isLoading,
783
+ className: "auth-form-input",
784
+ required: true
785
+ }
786
+ )
787
+ ] }),
788
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-form-error", children: error }),
789
+ /* @__PURE__ */ jsxRuntime.jsx(
790
+ "button",
791
+ {
792
+ type: "submit",
793
+ disabled: isLoading,
794
+ className: "auth-form-button auth-form-button-primary",
795
+ children: isLoading ? "Loading..." : submitButtonText
796
+ }
797
+ )
798
+ ] });
799
+ };
800
+ ResetPasswordForm.displayName = "ResetPasswordForm";
801
+ const VerifyEmailForm = ({
802
+ token: initialToken,
803
+ email: initialEmail,
804
+ className = "",
805
+ labels = {},
806
+ placeholders = {},
807
+ submitButtonText = "Verify Email",
808
+ onSuccess,
809
+ onError
810
+ }) => {
811
+ const {
812
+ verifyEmail,
813
+ isLoading: authLoading,
814
+ error: authError
815
+ } = useAuth();
816
+ const [formError, setFormError] = React.useState("");
817
+ const [email, setEmail] = React.useState(initialEmail || "");
818
+ const [token, setToken] = React.useState(initialToken || "");
819
+ const [successMessage, setSuccessMessage] = React.useState("");
820
+ const isLoading = authLoading;
821
+ const error = formError || authError?.message;
822
+ React.useEffect(() => {
823
+ if (token && email && !successMessage && !error) {
824
+ handleSubmit({ preventDefault: () => {
825
+ } });
826
+ }
827
+ }, [token, email]);
828
+ const handleSubmit = async (e) => {
829
+ e.preventDefault();
830
+ setFormError("");
831
+ setSuccessMessage("");
832
+ if (!token) {
833
+ setFormError("Verification token is required");
834
+ return;
835
+ }
836
+ if (!email) {
837
+ setFormError("Email is required");
838
+ return;
839
+ }
840
+ try {
841
+ await verifyEmail({ token, email });
842
+ setSuccessMessage("Email has been verified successfully");
843
+ onSuccess?.();
844
+ } catch (err) {
845
+ const errorMsg = err instanceof Error ? err.message : "Verification failed";
846
+ setFormError(errorMsg);
847
+ onError?.({
848
+ code: "VERIFY_EMAIL_ERROR",
849
+ message: errorMsg
850
+ });
851
+ }
852
+ };
853
+ if (successMessage) {
854
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `auth-form-success ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "auth-form-success-message", children: successMessage }) });
855
+ }
856
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, children: [
857
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
858
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", className: "auth-form-label", children: labels.email || "Email" }),
859
+ /* @__PURE__ */ jsxRuntime.jsx(
860
+ "input",
861
+ {
862
+ id: "email",
863
+ type: "email",
864
+ value: email,
865
+ onChange: (e) => setEmail(e.target.value),
866
+ placeholder: placeholders.email || "your@email.com",
867
+ disabled: isLoading,
868
+ className: "auth-form-input",
869
+ required: true
870
+ }
871
+ )
872
+ ] }),
873
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "auth-form-group", children: [
874
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "token", className: "auth-form-label", children: labels.token || "Verification Code" }),
875
+ /* @__PURE__ */ jsxRuntime.jsx(
876
+ "input",
877
+ {
878
+ id: "token",
879
+ type: "text",
880
+ value: token,
881
+ onChange: (e) => setToken(e.target.value),
882
+ placeholder: placeholders.token || "Enter verification code",
883
+ disabled: isLoading,
884
+ className: "auth-form-input",
885
+ required: true
886
+ }
887
+ )
888
+ ] }),
889
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-form-error", children: error }),
890
+ /* @__PURE__ */ jsxRuntime.jsx(
891
+ "button",
892
+ {
893
+ type: "submit",
894
+ disabled: isLoading,
895
+ className: "auth-form-button auth-form-button-primary",
896
+ children: isLoading ? "Loading..." : submitButtonText
897
+ }
898
+ )
899
+ ] });
900
+ };
901
+ VerifyEmailForm.displayName = "VerifyEmailForm";
902
+ const ProtectedRoute = ({
903
+ children,
904
+ redirectTo = "/login",
905
+ fallback,
906
+ roles,
907
+ permissions
908
+ }) => {
909
+ const { isAuthenticated, isLoading, user } = useAuth();
910
+ if (isLoading) {
911
+ return fallback || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-loading", children: "Loading..." });
912
+ }
913
+ if (!isAuthenticated) {
914
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: redirectTo, replace: true });
915
+ }
916
+ if (roles && roles.length > 0) {
917
+ const hasRole = user?.roles?.some((role) => roles.includes(role));
918
+ if (!hasRole) {
919
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-forbidden", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "You do not have permission to access this page." }) });
920
+ }
921
+ }
922
+ if (permissions && permissions.length > 0) {
923
+ const hasPermission = user?.permissions?.some(
924
+ (permission) => permissions.includes(permission)
925
+ );
926
+ if (!hasPermission) {
927
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "auth-forbidden", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "You do not have permission to access this page." }) });
928
+ }
929
+ }
930
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
931
+ };
932
+ ProtectedRoute.displayName = "ProtectedRoute";
933
+ exports.AuthContext = AuthContext;
934
+ exports.AuthProvider = AuthProvider;
935
+ exports.ForgotPasswordForm = ForgotPasswordForm;
936
+ exports.LoginForm = LoginForm;
937
+ exports.ProtectedRoute = ProtectedRoute;
938
+ exports.RegisterForm = RegisterForm;
939
+ exports.ResetPasswordForm = ResetPasswordForm;
940
+ exports.VerifyEmailForm = VerifyEmailForm;
941
+ exports.createAuthClient = createAuthClient;
942
+ exports.normalizeError = normalizeError;
943
+ exports.useAuth = useAuth;
944
+ //# sourceMappingURL=index.cjs.js.map