@thetechfossil/auth2 1.2.19 → 1.2.21

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.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/dist/index.components.d.mts +1 -0
  3. package/dist/index.components.d.ts +1 -0
  4. package/dist/index.components.js +275 -11
  5. package/dist/index.components.js.map +1 -1
  6. package/dist/index.components.mjs +275 -11
  7. package/dist/index.components.mjs.map +1 -1
  8. package/dist/index.d.mts +111 -3
  9. package/dist/index.d.ts +111 -3
  10. package/dist/index.js +470 -30
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +471 -32
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/index.next.d.mts +54 -1
  15. package/dist/index.next.d.ts +54 -1
  16. package/dist/index.next.js +332 -26
  17. package/dist/index.next.js.map +1 -1
  18. package/dist/index.next.mjs +332 -26
  19. package/dist/index.next.mjs.map +1 -1
  20. package/dist/index.next.server.d.mts +81 -2
  21. package/dist/index.next.server.d.ts +81 -2
  22. package/dist/index.next.server.js +406 -9
  23. package/dist/index.next.server.js.map +1 -1
  24. package/dist/index.next.server.mjs +403 -10
  25. package/dist/index.next.server.mjs.map +1 -1
  26. package/dist/index.node.d.mts +81 -2
  27. package/dist/index.node.d.ts +81 -2
  28. package/dist/index.node.js +406 -9
  29. package/dist/index.node.js.map +1 -1
  30. package/dist/index.node.mjs +403 -10
  31. package/dist/index.node.mjs.map +1 -1
  32. package/dist/index.react-native.d.mts +227 -0
  33. package/dist/index.react-native.d.ts +227 -0
  34. package/dist/index.react-native.js +1684 -0
  35. package/dist/index.react-native.js.map +1 -0
  36. package/dist/index.react-native.mjs +1648 -0
  37. package/dist/index.react-native.mjs.map +1 -0
  38. package/package.json +119 -102
@@ -0,0 +1,1684 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var SecureStore = require('expo-secure-store');
5
+ var axios = require('axios');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var reactNative = require('react-native');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var SecureStore__namespace = /*#__PURE__*/_interopNamespace(SecureStore);
30
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
31
+
32
+ // src/react-native/AuthProvider.tsx
33
+ var AuthServiceRN = class {
34
+ constructor(config) {
35
+ this.token = null;
36
+ this.config = config;
37
+ this.client = axios__default.default.create({
38
+ baseURL: config.baseUrl,
39
+ timeout: 3e4,
40
+ headers: {
41
+ "Content-Type": "application/json"
42
+ }
43
+ });
44
+ this.client.interceptors.request.use((config2) => {
45
+ if (this.token) {
46
+ config2.headers.Authorization = `Bearer ${this.token}`;
47
+ }
48
+ return config2;
49
+ });
50
+ }
51
+ setToken(token) {
52
+ this.token = token;
53
+ }
54
+ getToken() {
55
+ return this.token;
56
+ }
57
+ isAuthenticated() {
58
+ return !!this.token;
59
+ }
60
+ getCurrentUser() {
61
+ if (!this.token) return null;
62
+ try {
63
+ const payload = JSON.parse(atob(this.token.split(".")[1]));
64
+ return payload.user || null;
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+ async login(data) {
70
+ try {
71
+ const response = await this.client.post("/api/v1/auth/login", data);
72
+ if (response.data.success && response.data.token) {
73
+ this.token = response.data.token;
74
+ }
75
+ return response.data;
76
+ } catch (error) {
77
+ return {
78
+ success: false,
79
+ message: error.response?.data?.message || error.message || "Login failed"
80
+ };
81
+ }
82
+ }
83
+ async register(data) {
84
+ try {
85
+ const response = await this.client.post("/api/v1/auth/register", data);
86
+ return response.data;
87
+ } catch (error) {
88
+ return {
89
+ success: false,
90
+ message: error.response?.data?.message || error.message || "Registration failed"
91
+ };
92
+ }
93
+ }
94
+ async verify(data) {
95
+ try {
96
+ const response = await this.client.post("/api/v1/auth/verify", data);
97
+ if (response.data.success && response.data.token) {
98
+ this.token = response.data.token;
99
+ }
100
+ return response.data;
101
+ } catch (error) {
102
+ return {
103
+ success: false,
104
+ message: error.response?.data?.message || error.message || "Verification failed"
105
+ };
106
+ }
107
+ }
108
+ async logout() {
109
+ try {
110
+ await this.client.post("/api/v1/auth/logout", {});
111
+ } catch {
112
+ }
113
+ this.token = null;
114
+ }
115
+ async getProfile() {
116
+ const response = await this.client.get("/api/v1/user/me");
117
+ return response.data.user;
118
+ }
119
+ async updateProfile(data) {
120
+ try {
121
+ const response = await this.client.post("/api/v1/user/update/profile", data);
122
+ if (response.data.success && response.data.token) {
123
+ this.token = response.data.token;
124
+ }
125
+ return response.data;
126
+ } catch (error) {
127
+ return {
128
+ success: false,
129
+ message: error.response?.data?.message || error.message || "Update failed"
130
+ };
131
+ }
132
+ }
133
+ async forgotPassword(email) {
134
+ try {
135
+ const response = await this.client.post("/api/v1/auth/forgot-password", { email });
136
+ return response.data;
137
+ } catch (error) {
138
+ return {
139
+ success: false,
140
+ message: error.response?.data?.message || error.message || "Request failed"
141
+ };
142
+ }
143
+ }
144
+ async resetPassword(token, password) {
145
+ try {
146
+ const response = await this.client.post("/api/v1/auth/reset-password", { token, password });
147
+ return response.data;
148
+ } catch (error) {
149
+ return {
150
+ success: false,
151
+ message: error.response?.data?.message || error.message || "Reset failed"
152
+ };
153
+ }
154
+ }
155
+ async changePassword(oldPassword, newPassword) {
156
+ try {
157
+ const response = await this.client.post("/api/v1/user/change-password", {
158
+ oldPassword,
159
+ newPassword
160
+ });
161
+ return response.data;
162
+ } catch (error) {
163
+ return {
164
+ success: false,
165
+ message: error.response?.data?.message || error.message || "Change password failed"
166
+ };
167
+ }
168
+ }
169
+ };
170
+ var AuthContext = react.createContext(void 0);
171
+ var STORAGE_KEYS = {
172
+ TOKEN: "auth_token",
173
+ USER: "auth_user"
174
+ };
175
+ var AuthProvider = ({ children, config }) => {
176
+ const authConfig = {
177
+ baseUrl: config?.baseUrl || process.env.EXPO_PUBLIC_AUTH_API_URL || "http://localhost:7000",
178
+ localStorageKey: config?.localStorageKey || STORAGE_KEYS.TOKEN,
179
+ csrfEnabled: false
180
+ };
181
+ const [authService] = react.useState(() => new AuthServiceRN(authConfig));
182
+ const [user, setUser] = react.useState(null);
183
+ const [token, setToken] = react.useState(null);
184
+ const [isLoaded, setIsLoaded] = react.useState(false);
185
+ const [loading, setLoading] = react.useState(false);
186
+ react.useEffect(() => {
187
+ loadStoredAuth();
188
+ }, []);
189
+ const loadStoredAuth = async () => {
190
+ try {
191
+ const storedToken = await SecureStore__namespace.getItemAsync(STORAGE_KEYS.TOKEN);
192
+ const storedUser = await SecureStore__namespace.getItemAsync(STORAGE_KEYS.USER);
193
+ if (storedToken && storedUser) {
194
+ const parsedUser = JSON.parse(storedUser);
195
+ setToken(storedToken);
196
+ setUser(parsedUser);
197
+ authService.setToken(storedToken);
198
+ }
199
+ } catch (error) {
200
+ console.warn("[Auth SDK RN] Failed to load stored auth:", error);
201
+ } finally {
202
+ setIsLoaded(true);
203
+ }
204
+ };
205
+ const saveAuth = async (authToken, authUser) => {
206
+ await SecureStore__namespace.setItemAsync(STORAGE_KEYS.TOKEN, authToken);
207
+ await SecureStore__namespace.setItemAsync(STORAGE_KEYS.USER, JSON.stringify(authUser));
208
+ setToken(authToken);
209
+ setUser(authUser);
210
+ authService.setToken(authToken);
211
+ };
212
+ const clearAuth = async () => {
213
+ await SecureStore__namespace.deleteItemAsync(STORAGE_KEYS.TOKEN);
214
+ await SecureStore__namespace.deleteItemAsync(STORAGE_KEYS.USER);
215
+ setToken(null);
216
+ setUser(null);
217
+ authService.setToken(null);
218
+ };
219
+ const signIn = react.useCallback(async (data) => {
220
+ setLoading(true);
221
+ try {
222
+ const response = await authService.login(data);
223
+ if (response.success && response.user && response.token) {
224
+ await saveAuth(response.token, response.user);
225
+ }
226
+ return response;
227
+ } finally {
228
+ setLoading(false);
229
+ }
230
+ }, [authService]);
231
+ const signUp = react.useCallback(async (data) => {
232
+ setLoading(true);
233
+ try {
234
+ return await authService.register(data);
235
+ } finally {
236
+ setLoading(false);
237
+ }
238
+ }, [authService]);
239
+ const signOut = react.useCallback(async () => {
240
+ setLoading(true);
241
+ try {
242
+ await authService.logout();
243
+ await clearAuth();
244
+ } finally {
245
+ setLoading(false);
246
+ }
247
+ }, [authService]);
248
+ const verify = react.useCallback(async (data) => {
249
+ setLoading(true);
250
+ try {
251
+ const response = await authService.verify(data);
252
+ if (response.success && response.user && response.token) {
253
+ await saveAuth(response.token, response.user);
254
+ }
255
+ return response;
256
+ } finally {
257
+ setLoading(false);
258
+ }
259
+ }, [authService]);
260
+ const updateProfile = react.useCallback(async (data) => {
261
+ setLoading(true);
262
+ try {
263
+ const response = await authService.updateProfile(data);
264
+ if (response.success && response.user) {
265
+ setUser(response.user);
266
+ await SecureStore__namespace.setItemAsync(STORAGE_KEYS.USER, JSON.stringify(response.user));
267
+ }
268
+ return response;
269
+ } finally {
270
+ setLoading(false);
271
+ }
272
+ }, [authService]);
273
+ const getProfile = react.useCallback(async () => {
274
+ setLoading(true);
275
+ try {
276
+ const userData = await authService.getProfile();
277
+ setUser(userData);
278
+ await SecureStore__namespace.setItemAsync(STORAGE_KEYS.USER, JSON.stringify(userData));
279
+ return userData;
280
+ } finally {
281
+ setLoading(false);
282
+ }
283
+ }, [authService]);
284
+ const forgotPassword = react.useCallback(async (email) => {
285
+ setLoading(true);
286
+ try {
287
+ return await authService.forgotPassword(email);
288
+ } finally {
289
+ setLoading(false);
290
+ }
291
+ }, [authService]);
292
+ const resetPassword = react.useCallback(async (resetToken, password) => {
293
+ setLoading(true);
294
+ try {
295
+ return await authService.resetPassword(resetToken, password);
296
+ } finally {
297
+ setLoading(false);
298
+ }
299
+ }, [authService]);
300
+ const changePassword = react.useCallback(async (oldPassword, newPassword) => {
301
+ setLoading(true);
302
+ try {
303
+ return await authService.changePassword(oldPassword, newPassword);
304
+ } finally {
305
+ setLoading(false);
306
+ }
307
+ }, [authService]);
308
+ const value = {
309
+ user,
310
+ isLoaded,
311
+ isSignedIn: !!user,
312
+ loading,
313
+ token,
314
+ signIn,
315
+ signUp,
316
+ signOut,
317
+ verify,
318
+ updateProfile,
319
+ getProfile,
320
+ forgotPassword,
321
+ resetPassword,
322
+ changePassword,
323
+ authService
324
+ };
325
+ return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
326
+ };
327
+ var useAuth = () => {
328
+ const context = react.useContext(AuthContext);
329
+ if (context === void 0) {
330
+ throw new Error("useAuth must be used within an AuthProvider");
331
+ }
332
+ return context;
333
+ };
334
+ var Input = ({
335
+ label,
336
+ error,
337
+ containerStyle,
338
+ isPassword,
339
+ style,
340
+ theme,
341
+ ...props
342
+ }) => {
343
+ const [showPassword, setShowPassword] = react.useState(false);
344
+ const colors = {
345
+ backgroundColor: theme?.backgroundColor ?? "#F8FAFC",
346
+ borderColor: theme?.borderColor ?? "#E2E8F0",
347
+ textColor: theme?.textColor ?? "#1E293B",
348
+ labelColor: theme?.labelColor ?? "#374151",
349
+ placeholderColor: theme?.placeholderColor ?? "#9CA3AF",
350
+ accentColor: theme?.accentColor ?? "#4F46E5"
351
+ };
352
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.container, containerStyle], children: [
353
+ label && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.label, { color: colors.labelColor }], children: label }),
354
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.inputWrapper, children: [
355
+ /* @__PURE__ */ jsxRuntime.jsx(
356
+ reactNative.TextInput,
357
+ {
358
+ style: [
359
+ styles.input,
360
+ {
361
+ backgroundColor: colors.backgroundColor,
362
+ borderColor: error ? "#EF4444" : colors.borderColor,
363
+ color: colors.textColor
364
+ },
365
+ style
366
+ ],
367
+ placeholderTextColor: colors.placeholderColor,
368
+ secureTextEntry: isPassword && !showPassword,
369
+ ...props
370
+ }
371
+ ),
372
+ isPassword && /* @__PURE__ */ jsxRuntime.jsx(
373
+ reactNative.TouchableOpacity,
374
+ {
375
+ style: styles.eyeButton,
376
+ onPress: () => setShowPassword(!showPassword),
377
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.eyeText, { color: colors.accentColor }], children: showPassword ? "Hide" : "Show" })
378
+ }
379
+ )
380
+ ] }),
381
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.errorText, children: error })
382
+ ] });
383
+ };
384
+ var styles = reactNative.StyleSheet.create({
385
+ container: {
386
+ marginBottom: 16,
387
+ width: "100%"
388
+ },
389
+ label: {
390
+ fontSize: 14,
391
+ fontWeight: "600",
392
+ marginBottom: 8
393
+ },
394
+ inputWrapper: {
395
+ position: "relative",
396
+ width: "100%"
397
+ },
398
+ input: {
399
+ borderWidth: 1.5,
400
+ borderRadius: 12,
401
+ paddingHorizontal: 16,
402
+ paddingVertical: 14,
403
+ fontSize: 16,
404
+ width: "100%"
405
+ },
406
+ eyeButton: {
407
+ position: "absolute",
408
+ right: 14,
409
+ top: 0,
410
+ bottom: 0,
411
+ justifyContent: "center"
412
+ },
413
+ eyeText: {
414
+ fontSize: 14,
415
+ fontWeight: "600"
416
+ },
417
+ errorText: {
418
+ color: "#EF4444",
419
+ fontSize: 12,
420
+ marginTop: 4
421
+ }
422
+ });
423
+ var Button = ({
424
+ title,
425
+ onPress,
426
+ loading = false,
427
+ disabled = false,
428
+ variant = "primary",
429
+ style,
430
+ textStyle,
431
+ theme
432
+ }) => {
433
+ const isDisabled = disabled || loading;
434
+ const colors = {
435
+ primaryColor: theme?.primaryColor ?? "#4F46E5",
436
+ primaryTextColor: theme?.primaryTextColor ?? "#FFFFFF",
437
+ secondaryColor: theme?.secondaryColor ?? "#F1F5F9",
438
+ secondaryTextColor: theme?.secondaryTextColor ?? "#374151"
439
+ };
440
+ const getButtonStyle = () => {
441
+ switch (variant) {
442
+ case "secondary":
443
+ return { backgroundColor: colors.secondaryColor };
444
+ case "outline":
445
+ return { backgroundColor: "transparent", borderWidth: 2, borderColor: colors.primaryColor };
446
+ case "ghost":
447
+ return { backgroundColor: "transparent" };
448
+ default:
449
+ return {
450
+ backgroundColor: colors.primaryColor,
451
+ shadowColor: colors.primaryColor,
452
+ shadowOffset: { width: 0, height: 4 },
453
+ shadowOpacity: 0.3,
454
+ shadowRadius: 8,
455
+ elevation: 4
456
+ };
457
+ }
458
+ };
459
+ const getTextColor = () => {
460
+ switch (variant) {
461
+ case "secondary":
462
+ return colors.secondaryTextColor;
463
+ case "outline":
464
+ case "ghost":
465
+ return colors.primaryColor;
466
+ default:
467
+ return colors.primaryTextColor;
468
+ }
469
+ };
470
+ return /* @__PURE__ */ jsxRuntime.jsx(
471
+ reactNative.TouchableOpacity,
472
+ {
473
+ style: [
474
+ styles2.button,
475
+ getButtonStyle(),
476
+ isDisabled && styles2.disabled,
477
+ style
478
+ ],
479
+ onPress,
480
+ disabled: isDisabled,
481
+ activeOpacity: 0.7,
482
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx(
483
+ reactNative.ActivityIndicator,
484
+ {
485
+ color: variant === "primary" ? colors.primaryTextColor : colors.primaryColor,
486
+ size: "small"
487
+ }
488
+ ) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.text, { color: getTextColor() }, textStyle], children: title })
489
+ }
490
+ );
491
+ };
492
+ var styles2 = reactNative.StyleSheet.create({
493
+ button: {
494
+ paddingVertical: 16,
495
+ paddingHorizontal: 24,
496
+ borderRadius: 14,
497
+ alignItems: "center",
498
+ justifyContent: "center",
499
+ minHeight: 52,
500
+ width: "100%"
501
+ },
502
+ disabled: {
503
+ opacity: 0.6
504
+ },
505
+ text: {
506
+ fontSize: 16,
507
+ fontWeight: "700"
508
+ }
509
+ });
510
+ var LoginForm = ({
511
+ onSuccess,
512
+ onOtpRequired,
513
+ onRegisterPress,
514
+ onForgotPasswordPress,
515
+ showRegisterLink = true,
516
+ showForgotPassword = true,
517
+ usePasswordLogin = true,
518
+ theme
519
+ }) => {
520
+ const { signIn, loading } = useAuth();
521
+ const [email, setEmail] = react.useState("");
522
+ const [password, setPassword] = react.useState("");
523
+ const [useOtp, setUseOtp] = react.useState(!usePasswordLogin);
524
+ const [error, setError] = react.useState(null);
525
+ const colors = {
526
+ textColor: theme?.textColor ?? "#111827",
527
+ secondaryTextColor: theme?.secondaryTextColor ?? "#6B7280",
528
+ mutedTextColor: theme?.mutedTextColor ?? "#9CA3AF",
529
+ accentColor: theme?.accentColor ?? "#4F46E5",
530
+ borderColor: theme?.borderColor ?? "#E5E7EB",
531
+ inputBackgroundColor: theme?.inputBackgroundColor ?? "#F8FAFC",
532
+ inputBorderColor: theme?.inputBorderColor ?? "#E2E8F0"
533
+ };
534
+ const inputTheme = {
535
+ backgroundColor: colors.inputBackgroundColor,
536
+ borderColor: colors.inputBorderColor,
537
+ textColor: colors.textColor,
538
+ labelColor: colors.secondaryTextColor,
539
+ placeholderColor: colors.mutedTextColor,
540
+ accentColor: colors.accentColor
541
+ };
542
+ const buttonTheme = {
543
+ primaryColor: colors.accentColor,
544
+ secondaryColor: colors.inputBackgroundColor,
545
+ secondaryTextColor: colors.textColor
546
+ };
547
+ const handleSubmit = async () => {
548
+ if (!email.trim()) {
549
+ setError("Email is required");
550
+ return;
551
+ }
552
+ if (!useOtp && !password.trim()) {
553
+ setError("Password is required");
554
+ return;
555
+ }
556
+ setError(null);
557
+ try {
558
+ const loginData = { email: email.trim() };
559
+ if (!useOtp) {
560
+ loginData.password = password;
561
+ }
562
+ const response = await signIn(loginData);
563
+ if (response.success) {
564
+ if (response.message?.includes("OTP sent")) {
565
+ onOtpRequired?.(email);
566
+ } else {
567
+ onSuccess?.(response);
568
+ }
569
+ } else {
570
+ setError(response.message || "Login failed");
571
+ }
572
+ } catch (err) {
573
+ setError(err instanceof Error ? err.message : "An error occurred");
574
+ }
575
+ };
576
+ return /* @__PURE__ */ jsxRuntime.jsx(
577
+ reactNative.KeyboardAvoidingView,
578
+ {
579
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
580
+ style: styles3.container,
581
+ children: /* @__PURE__ */ jsxRuntime.jsx(
582
+ reactNative.ScrollView,
583
+ {
584
+ contentContainerStyle: styles3.scrollContent,
585
+ keyboardShouldPersistTaps: "handled",
586
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles3.card, children: [
587
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.title, { color: colors.textColor }], children: useOtp ? "Login with OTP" : "Login" }),
588
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.errorContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles3.errorText, children: error }) }),
589
+ /* @__PURE__ */ jsxRuntime.jsx(
590
+ Input,
591
+ {
592
+ label: "Email",
593
+ value: email,
594
+ onChangeText: setEmail,
595
+ placeholder: "Enter your email",
596
+ keyboardType: "email-address",
597
+ autoCapitalize: "none",
598
+ autoCorrect: false,
599
+ editable: !loading,
600
+ theme: inputTheme
601
+ }
602
+ ),
603
+ !useOtp && /* @__PURE__ */ jsxRuntime.jsx(
604
+ Input,
605
+ {
606
+ label: "Password",
607
+ value: password,
608
+ onChangeText: setPassword,
609
+ placeholder: "Enter your password",
610
+ isPassword: true,
611
+ editable: !loading,
612
+ theme: inputTheme
613
+ }
614
+ ),
615
+ /* @__PURE__ */ jsxRuntime.jsx(
616
+ Button,
617
+ {
618
+ title: loading ? "Please wait..." : useOtp ? "Send OTP" : "Login",
619
+ onPress: handleSubmit,
620
+ loading,
621
+ disabled: loading,
622
+ theme: buttonTheme
623
+ }
624
+ ),
625
+ /* @__PURE__ */ jsxRuntime.jsx(
626
+ reactNative.TouchableOpacity,
627
+ {
628
+ style: styles3.switchMethod,
629
+ onPress: () => setUseOtp(!useOtp),
630
+ disabled: loading,
631
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.switchMethodText, { color: colors.accentColor }], children: useOtp ? "Login with password instead" : "Login with OTP instead" })
632
+ }
633
+ ),
634
+ showForgotPassword && !useOtp && /* @__PURE__ */ jsxRuntime.jsx(
635
+ reactNative.TouchableOpacity,
636
+ {
637
+ style: styles3.forgotPassword,
638
+ onPress: onForgotPasswordPress,
639
+ disabled: loading,
640
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.forgotPasswordText, { color: colors.secondaryTextColor }], children: "Forgot password?" })
641
+ }
642
+ ),
643
+ showRegisterLink && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles3.registerContainer, { borderTopColor: colors.borderColor }], children: [
644
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles3.registerText, { color: colors.secondaryTextColor }], children: [
645
+ "Don't have an account?",
646
+ " "
647
+ ] }),
648
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onRegisterPress, disabled: loading, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.registerLink, { color: colors.accentColor }], children: "Register" }) })
649
+ ] })
650
+ ] })
651
+ }
652
+ )
653
+ }
654
+ );
655
+ };
656
+ var styles3 = reactNative.StyleSheet.create({
657
+ container: {
658
+ flex: 1,
659
+ width: "100%"
660
+ },
661
+ scrollContent: {
662
+ flexGrow: 1
663
+ },
664
+ card: {
665
+ width: "100%"
666
+ },
667
+ title: {
668
+ fontSize: 24,
669
+ fontWeight: "700",
670
+ textAlign: "center",
671
+ marginBottom: 24
672
+ },
673
+ errorContainer: {
674
+ backgroundColor: "#FEE2E2",
675
+ borderWidth: 1,
676
+ borderColor: "#FECACA",
677
+ borderRadius: 8,
678
+ padding: 12,
679
+ marginBottom: 16
680
+ },
681
+ errorText: {
682
+ color: "#DC2626",
683
+ fontSize: 14,
684
+ textAlign: "center"
685
+ },
686
+ switchMethod: {
687
+ marginTop: 16,
688
+ alignItems: "center"
689
+ },
690
+ switchMethodText: {
691
+ fontSize: 14,
692
+ fontWeight: "600"
693
+ },
694
+ forgotPassword: {
695
+ marginTop: 12,
696
+ alignItems: "center"
697
+ },
698
+ forgotPasswordText: {
699
+ fontSize: 14
700
+ },
701
+ registerContainer: {
702
+ flexDirection: "row",
703
+ justifyContent: "center",
704
+ marginTop: 24,
705
+ paddingTop: 16,
706
+ borderTopWidth: 1
707
+ },
708
+ registerText: {
709
+ fontSize: 14
710
+ },
711
+ registerLink: {
712
+ fontSize: 14,
713
+ fontWeight: "600"
714
+ }
715
+ });
716
+ var RegisterForm = ({
717
+ onSuccess,
718
+ onOtpRequired,
719
+ onLoginPress,
720
+ showLoginLink = true
721
+ }) => {
722
+ const { signUp, loading } = useAuth();
723
+ const [name, setName] = react.useState("");
724
+ const [email, setEmail] = react.useState("");
725
+ const [password, setPassword] = react.useState("");
726
+ const [confirmPassword, setConfirmPassword] = react.useState("");
727
+ const [error, setError] = react.useState(null);
728
+ const handleSubmit = async () => {
729
+ if (!name.trim()) {
730
+ setError("Name is required");
731
+ return;
732
+ }
733
+ if (!email.trim()) {
734
+ setError("Email is required");
735
+ return;
736
+ }
737
+ if (!password.trim()) {
738
+ setError("Password is required");
739
+ return;
740
+ }
741
+ if (password !== confirmPassword) {
742
+ setError("Passwords do not match");
743
+ return;
744
+ }
745
+ if (password.length < 6) {
746
+ setError("Password must be at least 6 characters");
747
+ return;
748
+ }
749
+ setError(null);
750
+ try {
751
+ const response = await signUp({
752
+ name: name.trim(),
753
+ email: email.trim(),
754
+ password
755
+ });
756
+ if (response.success) {
757
+ if (response.message?.includes("OTP") || response.message?.includes("Verification")) {
758
+ onOtpRequired?.(email);
759
+ } else {
760
+ onSuccess?.(response);
761
+ }
762
+ } else {
763
+ setError(response.message || "Registration failed");
764
+ }
765
+ } catch (err) {
766
+ setError(err instanceof Error ? err.message : "An error occurred");
767
+ }
768
+ };
769
+ return /* @__PURE__ */ jsxRuntime.jsx(
770
+ reactNative.KeyboardAvoidingView,
771
+ {
772
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
773
+ style: styles4.container,
774
+ children: /* @__PURE__ */ jsxRuntime.jsx(
775
+ reactNative.ScrollView,
776
+ {
777
+ contentContainerStyle: styles4.scrollContent,
778
+ keyboardShouldPersistTaps: "handled",
779
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.card, children: [
780
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.title, children: "Create Account" }),
781
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.errorContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.errorText, children: error }) }),
782
+ /* @__PURE__ */ jsxRuntime.jsx(
783
+ Input,
784
+ {
785
+ label: "Full Name",
786
+ value: name,
787
+ onChangeText: setName,
788
+ placeholder: "Enter your name",
789
+ autoCapitalize: "words",
790
+ editable: !loading
791
+ }
792
+ ),
793
+ /* @__PURE__ */ jsxRuntime.jsx(
794
+ Input,
795
+ {
796
+ label: "Email",
797
+ value: email,
798
+ onChangeText: setEmail,
799
+ placeholder: "Enter your email",
800
+ keyboardType: "email-address",
801
+ autoCapitalize: "none",
802
+ autoCorrect: false,
803
+ editable: !loading
804
+ }
805
+ ),
806
+ /* @__PURE__ */ jsxRuntime.jsx(
807
+ Input,
808
+ {
809
+ label: "Password",
810
+ value: password,
811
+ onChangeText: setPassword,
812
+ placeholder: "Create a password",
813
+ isPassword: true,
814
+ editable: !loading
815
+ }
816
+ ),
817
+ /* @__PURE__ */ jsxRuntime.jsx(
818
+ Input,
819
+ {
820
+ label: "Confirm Password",
821
+ value: confirmPassword,
822
+ onChangeText: setConfirmPassword,
823
+ placeholder: "Confirm your password",
824
+ isPassword: true,
825
+ editable: !loading
826
+ }
827
+ ),
828
+ /* @__PURE__ */ jsxRuntime.jsx(
829
+ Button,
830
+ {
831
+ title: loading ? "Creating account..." : "Register",
832
+ onPress: handleSubmit,
833
+ loading,
834
+ disabled: loading
835
+ }
836
+ ),
837
+ showLoginLink && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.loginContainer, children: [
838
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.loginText, children: "Already have an account? " }),
839
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onLoginPress, disabled: loading, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles4.loginLink, children: "Login" }) })
840
+ ] })
841
+ ] })
842
+ }
843
+ )
844
+ }
845
+ );
846
+ };
847
+ var styles4 = reactNative.StyleSheet.create({
848
+ container: {
849
+ flex: 1
850
+ },
851
+ scrollContent: {
852
+ flexGrow: 1,
853
+ justifyContent: "center",
854
+ padding: 20
855
+ },
856
+ card: {
857
+ backgroundColor: "#FFFFFF",
858
+ borderRadius: 16,
859
+ padding: 24,
860
+ shadowColor: "#000",
861
+ shadowOffset: { width: 0, height: 2 },
862
+ shadowOpacity: 0.1,
863
+ shadowRadius: 8,
864
+ elevation: 4
865
+ },
866
+ title: {
867
+ fontSize: 24,
868
+ fontWeight: "700",
869
+ color: "#111827",
870
+ textAlign: "center",
871
+ marginBottom: 24
872
+ },
873
+ errorContainer: {
874
+ backgroundColor: "#FEE2E2",
875
+ borderWidth: 1,
876
+ borderColor: "#FECACA",
877
+ borderRadius: 8,
878
+ padding: 12,
879
+ marginBottom: 16
880
+ },
881
+ errorText: {
882
+ color: "#DC2626",
883
+ fontSize: 14,
884
+ textAlign: "center"
885
+ },
886
+ loginContainer: {
887
+ flexDirection: "row",
888
+ justifyContent: "center",
889
+ marginTop: 24,
890
+ paddingTop: 16,
891
+ borderTopWidth: 1,
892
+ borderTopColor: "#E5E7EB"
893
+ },
894
+ loginText: {
895
+ color: "#6B7280",
896
+ fontSize: 14
897
+ },
898
+ loginLink: {
899
+ color: "#4F46E5",
900
+ fontSize: 14,
901
+ fontWeight: "600"
902
+ }
903
+ });
904
+ var OtpForm = ({
905
+ email,
906
+ onSuccess,
907
+ onResendOtp,
908
+ onBackPress,
909
+ otpLength = 6,
910
+ theme
911
+ }) => {
912
+ const { verify, signIn, loading } = useAuth();
913
+ const [otp, setOtp] = react.useState(Array(otpLength).fill(""));
914
+ const [error, setError] = react.useState(null);
915
+ const [resendTimer, setResendTimer] = react.useState(30);
916
+ const inputRefs = react.useRef([]);
917
+ const colors = {
918
+ textColor: theme?.textColor ?? "#111827",
919
+ secondaryTextColor: theme?.secondaryTextColor ?? "#6B7280",
920
+ accentColor: theme?.accentColor ?? "#4F46E5",
921
+ inputBackgroundColor: theme?.inputBackgroundColor ?? "#F9FAFB",
922
+ inputBorderColor: theme?.inputBorderColor ?? "#D1D5DB",
923
+ inputFilledBackgroundColor: theme?.inputFilledBackgroundColor ?? "#EEF2FF"
924
+ };
925
+ const buttonTheme = {
926
+ primaryColor: colors.accentColor
927
+ };
928
+ react.useEffect(() => {
929
+ if (resendTimer > 0) {
930
+ const timer = setTimeout(() => setResendTimer(resendTimer - 1), 1e3);
931
+ return () => clearTimeout(timer);
932
+ }
933
+ return void 0;
934
+ }, [resendTimer]);
935
+ const handleOtpChange = (value, index) => {
936
+ if (value.length > 1) {
937
+ const pastedOtp = value.slice(0, otpLength).split("");
938
+ const newOtp = [...otp];
939
+ pastedOtp.forEach((char, i) => {
940
+ if (index + i < otpLength) {
941
+ newOtp[index + i] = char;
942
+ }
943
+ });
944
+ setOtp(newOtp);
945
+ const nextIndex = Math.min(index + pastedOtp.length, otpLength - 1);
946
+ inputRefs.current[nextIndex]?.focus();
947
+ } else {
948
+ const newOtp = [...otp];
949
+ newOtp[index] = value;
950
+ setOtp(newOtp);
951
+ if (value && index < otpLength - 1) {
952
+ inputRefs.current[index + 1]?.focus();
953
+ }
954
+ }
955
+ setError(null);
956
+ };
957
+ const handleKeyPress = (e, index) => {
958
+ if (e.nativeEvent.key === "Backspace" && !otp[index] && index > 0) {
959
+ inputRefs.current[index - 1]?.focus();
960
+ }
961
+ };
962
+ const handleSubmit = async () => {
963
+ const otpCode = otp.join("");
964
+ if (otpCode.length !== otpLength) {
965
+ setError(`Please enter all ${otpLength} digits`);
966
+ return;
967
+ }
968
+ setError(null);
969
+ try {
970
+ const response = await verify({ email, otp: otpCode });
971
+ if (response.success) {
972
+ onSuccess?.(response);
973
+ } else {
974
+ setError(response.message || "Verification failed");
975
+ }
976
+ } catch (err) {
977
+ setError(err instanceof Error ? err.message : "An error occurred");
978
+ }
979
+ };
980
+ const handleResend = async () => {
981
+ setError(null);
982
+ setResendTimer(30);
983
+ try {
984
+ await signIn({ email });
985
+ onResendOtp?.();
986
+ } catch (err) {
987
+ setError("Failed to resend OTP");
988
+ }
989
+ };
990
+ return /* @__PURE__ */ jsxRuntime.jsx(
991
+ reactNative.KeyboardAvoidingView,
992
+ {
993
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
994
+ style: styles5.container,
995
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.card, children: [
996
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.title, { color: colors.textColor }], children: "Verify OTP" }),
997
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles5.subtitle, { color: colors.secondaryTextColor }], children: [
998
+ "Enter the ",
999
+ otpLength,
1000
+ "-digit code sent to",
1001
+ "\n",
1002
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.email, { color: colors.accentColor }], children: email })
1003
+ ] }),
1004
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.errorContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles5.errorText, children: error }) }),
1005
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.otpContainer, children: otp.map((digit, index) => /* @__PURE__ */ jsxRuntime.jsx(
1006
+ reactNative.TextInput,
1007
+ {
1008
+ ref: (ref) => {
1009
+ inputRefs.current[index] = ref;
1010
+ },
1011
+ style: [
1012
+ styles5.otpInput,
1013
+ {
1014
+ backgroundColor: colors.inputBackgroundColor,
1015
+ borderColor: colors.inputBorderColor,
1016
+ color: colors.textColor
1017
+ },
1018
+ digit && {
1019
+ borderColor: colors.accentColor,
1020
+ backgroundColor: colors.inputFilledBackgroundColor
1021
+ }
1022
+ ],
1023
+ value: digit,
1024
+ onChangeText: (value) => handleOtpChange(value, index),
1025
+ onKeyPress: (e) => handleKeyPress(e, index),
1026
+ keyboardType: "number-pad",
1027
+ maxLength: otpLength,
1028
+ editable: !loading,
1029
+ selectTextOnFocus: true
1030
+ },
1031
+ index
1032
+ )) }),
1033
+ /* @__PURE__ */ jsxRuntime.jsx(
1034
+ Button,
1035
+ {
1036
+ title: loading ? "Verifying..." : "Verify",
1037
+ onPress: handleSubmit,
1038
+ loading,
1039
+ disabled: loading || otp.join("").length !== otpLength,
1040
+ theme: buttonTheme
1041
+ }
1042
+ ),
1043
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles5.resendContainer, children: resendTimer > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles5.resendTimer, { color: colors.secondaryTextColor }], children: [
1044
+ "Resend OTP in ",
1045
+ resendTimer,
1046
+ "s"
1047
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: handleResend, disabled: loading, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.resendLink, { color: colors.accentColor }], children: "Resend OTP" }) }) }),
1048
+ onBackPress && /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { style: styles5.backButton, onPress: onBackPress, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.backText, { color: colors.secondaryTextColor }], children: "\u2190 Back to login" }) })
1049
+ ] })
1050
+ }
1051
+ );
1052
+ };
1053
+ var styles5 = reactNative.StyleSheet.create({
1054
+ container: {
1055
+ flex: 1,
1056
+ justifyContent: "center"
1057
+ },
1058
+ card: {
1059
+ width: "100%"
1060
+ },
1061
+ title: {
1062
+ fontSize: 24,
1063
+ fontWeight: "700",
1064
+ textAlign: "center",
1065
+ marginBottom: 8
1066
+ },
1067
+ subtitle: {
1068
+ fontSize: 14,
1069
+ textAlign: "center",
1070
+ marginBottom: 24,
1071
+ lineHeight: 20
1072
+ },
1073
+ email: {
1074
+ fontWeight: "600"
1075
+ },
1076
+ errorContainer: {
1077
+ backgroundColor: "#FEE2E2",
1078
+ borderWidth: 1,
1079
+ borderColor: "#FECACA",
1080
+ borderRadius: 8,
1081
+ padding: 12,
1082
+ marginBottom: 16
1083
+ },
1084
+ errorText: {
1085
+ color: "#DC2626",
1086
+ fontSize: 14,
1087
+ textAlign: "center"
1088
+ },
1089
+ otpContainer: {
1090
+ flexDirection: "row",
1091
+ justifyContent: "space-between",
1092
+ marginBottom: 24
1093
+ },
1094
+ otpInput: {
1095
+ width: 45,
1096
+ height: 55,
1097
+ borderWidth: 2,
1098
+ borderRadius: 10,
1099
+ fontSize: 24,
1100
+ fontWeight: "700",
1101
+ textAlign: "center"
1102
+ },
1103
+ resendContainer: {
1104
+ alignItems: "center",
1105
+ marginTop: 16
1106
+ },
1107
+ resendTimer: {
1108
+ fontSize: 14
1109
+ },
1110
+ resendLink: {
1111
+ fontSize: 14,
1112
+ fontWeight: "600"
1113
+ },
1114
+ backButton: {
1115
+ marginTop: 16,
1116
+ alignItems: "center"
1117
+ },
1118
+ backText: {
1119
+ fontSize: 14
1120
+ }
1121
+ });
1122
+ var ForgotPassword = ({
1123
+ onSuccess,
1124
+ onBackPress
1125
+ }) => {
1126
+ const { forgotPassword, loading } = useAuth();
1127
+ const [email, setEmail] = react.useState("");
1128
+ const [error, setError] = react.useState(null);
1129
+ const [success, setSuccess] = react.useState(false);
1130
+ const handleSubmit = async () => {
1131
+ if (!email.trim()) {
1132
+ setError("Email is required");
1133
+ return;
1134
+ }
1135
+ setError(null);
1136
+ try {
1137
+ const response = await forgotPassword(email.trim());
1138
+ if (response.success) {
1139
+ setSuccess(true);
1140
+ onSuccess?.(email);
1141
+ } else {
1142
+ setError(response.message || "Failed to send reset email");
1143
+ }
1144
+ } catch (err) {
1145
+ setError(err instanceof Error ? err.message : "An error occurred");
1146
+ }
1147
+ };
1148
+ if (success) {
1149
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.container, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.card, children: [
1150
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.successIcon, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.successIconText, children: "\u2713" }) }),
1151
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.title, children: "Check Your Email" }),
1152
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: styles6.subtitle, children: [
1153
+ "We've sent a password reset link to",
1154
+ "\n",
1155
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.email, children: email })
1156
+ ] }),
1157
+ /* @__PURE__ */ jsxRuntime.jsx(
1158
+ Button,
1159
+ {
1160
+ title: "Back to Login",
1161
+ onPress: onBackPress || (() => {
1162
+ }),
1163
+ variant: "outline"
1164
+ }
1165
+ )
1166
+ ] }) });
1167
+ }
1168
+ return /* @__PURE__ */ jsxRuntime.jsx(
1169
+ reactNative.KeyboardAvoidingView,
1170
+ {
1171
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1172
+ style: styles6.container,
1173
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.card, children: [
1174
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.title, children: "Forgot Password" }),
1175
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.subtitle, children: "Enter your email address and we'll send you a link to reset your password." }),
1176
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles6.errorContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.errorText, children: error }) }),
1177
+ /* @__PURE__ */ jsxRuntime.jsx(
1178
+ Input,
1179
+ {
1180
+ label: "Email",
1181
+ value: email,
1182
+ onChangeText: setEmail,
1183
+ placeholder: "Enter your email",
1184
+ keyboardType: "email-address",
1185
+ autoCapitalize: "none",
1186
+ autoCorrect: false,
1187
+ editable: !loading
1188
+ }
1189
+ ),
1190
+ /* @__PURE__ */ jsxRuntime.jsx(
1191
+ Button,
1192
+ {
1193
+ title: loading ? "Sending..." : "Send Reset Link",
1194
+ onPress: handleSubmit,
1195
+ loading,
1196
+ disabled: loading
1197
+ }
1198
+ ),
1199
+ onBackPress && /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { style: styles6.backButton, onPress: onBackPress, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles6.backText, children: "\u2190 Back to login" }) })
1200
+ ] })
1201
+ }
1202
+ );
1203
+ };
1204
+ var styles6 = reactNative.StyleSheet.create({
1205
+ container: {
1206
+ flex: 1,
1207
+ justifyContent: "center",
1208
+ padding: 20
1209
+ },
1210
+ card: {
1211
+ backgroundColor: "#FFFFFF",
1212
+ borderRadius: 16,
1213
+ padding: 24,
1214
+ shadowColor: "#000",
1215
+ shadowOffset: { width: 0, height: 2 },
1216
+ shadowOpacity: 0.1,
1217
+ shadowRadius: 8,
1218
+ elevation: 4
1219
+ },
1220
+ title: {
1221
+ fontSize: 24,
1222
+ fontWeight: "700",
1223
+ color: "#111827",
1224
+ textAlign: "center",
1225
+ marginBottom: 8
1226
+ },
1227
+ subtitle: {
1228
+ fontSize: 14,
1229
+ color: "#6B7280",
1230
+ textAlign: "center",
1231
+ marginBottom: 24,
1232
+ lineHeight: 20
1233
+ },
1234
+ email: {
1235
+ color: "#4F46E5",
1236
+ fontWeight: "600"
1237
+ },
1238
+ errorContainer: {
1239
+ backgroundColor: "#FEE2E2",
1240
+ borderWidth: 1,
1241
+ borderColor: "#FECACA",
1242
+ borderRadius: 8,
1243
+ padding: 12,
1244
+ marginBottom: 16
1245
+ },
1246
+ errorText: {
1247
+ color: "#DC2626",
1248
+ fontSize: 14,
1249
+ textAlign: "center"
1250
+ },
1251
+ backButton: {
1252
+ marginTop: 16,
1253
+ alignItems: "center"
1254
+ },
1255
+ backText: {
1256
+ color: "#6B7280",
1257
+ fontSize: 14
1258
+ },
1259
+ successIcon: {
1260
+ width: 60,
1261
+ height: 60,
1262
+ borderRadius: 30,
1263
+ backgroundColor: "#D1FAE5",
1264
+ alignItems: "center",
1265
+ justifyContent: "center",
1266
+ alignSelf: "center",
1267
+ marginBottom: 16
1268
+ },
1269
+ successIconText: {
1270
+ fontSize: 28,
1271
+ color: "#059669"
1272
+ }
1273
+ });
1274
+ var ResetPassword = ({
1275
+ token,
1276
+ onSuccess,
1277
+ onBackPress
1278
+ }) => {
1279
+ const { resetPassword, loading } = useAuth();
1280
+ const [password, setPassword] = react.useState("");
1281
+ const [confirmPassword, setConfirmPassword] = react.useState("");
1282
+ const [error, setError] = react.useState(null);
1283
+ const [success, setSuccess] = react.useState(false);
1284
+ const handleSubmit = async () => {
1285
+ if (!password.trim()) {
1286
+ setError("Password is required");
1287
+ return;
1288
+ }
1289
+ if (password.length < 6) {
1290
+ setError("Password must be at least 6 characters");
1291
+ return;
1292
+ }
1293
+ if (password !== confirmPassword) {
1294
+ setError("Passwords do not match");
1295
+ return;
1296
+ }
1297
+ setError(null);
1298
+ try {
1299
+ const response = await resetPassword(token, password);
1300
+ if (response.success) {
1301
+ setSuccess(true);
1302
+ onSuccess?.();
1303
+ } else {
1304
+ setError(response.message || "Failed to reset password");
1305
+ }
1306
+ } catch (err) {
1307
+ setError(err instanceof Error ? err.message : "An error occurred");
1308
+ }
1309
+ };
1310
+ if (success) {
1311
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.container, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.card, children: [
1312
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.successIcon, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.successIconText, children: "\u2713" }) }),
1313
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.title, children: "Password Reset" }),
1314
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.subtitle, children: "Your password has been successfully reset. You can now login with your new password." }),
1315
+ /* @__PURE__ */ jsxRuntime.jsx(
1316
+ Button,
1317
+ {
1318
+ title: "Back to Login",
1319
+ onPress: onBackPress || (() => {
1320
+ })
1321
+ }
1322
+ )
1323
+ ] }) });
1324
+ }
1325
+ return /* @__PURE__ */ jsxRuntime.jsx(
1326
+ reactNative.KeyboardAvoidingView,
1327
+ {
1328
+ behavior: reactNative.Platform.OS === "ios" ? "padding" : "height",
1329
+ style: styles7.container,
1330
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1331
+ reactNative.ScrollView,
1332
+ {
1333
+ contentContainerStyle: styles7.scrollContent,
1334
+ keyboardShouldPersistTaps: "handled",
1335
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.card, children: [
1336
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.title, children: "Reset Password" }),
1337
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.subtitle, children: "Enter your new password below." }),
1338
+ error && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles7.errorContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles7.errorText, children: error }) }),
1339
+ /* @__PURE__ */ jsxRuntime.jsx(
1340
+ Input,
1341
+ {
1342
+ label: "New Password",
1343
+ value: password,
1344
+ onChangeText: setPassword,
1345
+ placeholder: "Enter new password",
1346
+ isPassword: true,
1347
+ editable: !loading
1348
+ }
1349
+ ),
1350
+ /* @__PURE__ */ jsxRuntime.jsx(
1351
+ Input,
1352
+ {
1353
+ label: "Confirm Password",
1354
+ value: confirmPassword,
1355
+ onChangeText: setConfirmPassword,
1356
+ placeholder: "Confirm new password",
1357
+ isPassword: true,
1358
+ editable: !loading
1359
+ }
1360
+ ),
1361
+ /* @__PURE__ */ jsxRuntime.jsx(
1362
+ Button,
1363
+ {
1364
+ title: loading ? "Resetting..." : "Reset Password",
1365
+ onPress: handleSubmit,
1366
+ loading,
1367
+ disabled: loading
1368
+ }
1369
+ )
1370
+ ] })
1371
+ }
1372
+ )
1373
+ }
1374
+ );
1375
+ };
1376
+ var styles7 = reactNative.StyleSheet.create({
1377
+ container: {
1378
+ flex: 1
1379
+ },
1380
+ scrollContent: {
1381
+ flexGrow: 1,
1382
+ justifyContent: "center",
1383
+ padding: 20
1384
+ },
1385
+ card: {
1386
+ backgroundColor: "#FFFFFF",
1387
+ borderRadius: 16,
1388
+ padding: 24,
1389
+ shadowColor: "#000",
1390
+ shadowOffset: { width: 0, height: 2 },
1391
+ shadowOpacity: 0.1,
1392
+ shadowRadius: 8,
1393
+ elevation: 4
1394
+ },
1395
+ title: {
1396
+ fontSize: 24,
1397
+ fontWeight: "700",
1398
+ color: "#111827",
1399
+ textAlign: "center",
1400
+ marginBottom: 8
1401
+ },
1402
+ subtitle: {
1403
+ fontSize: 14,
1404
+ color: "#6B7280",
1405
+ textAlign: "center",
1406
+ marginBottom: 24,
1407
+ lineHeight: 20
1408
+ },
1409
+ errorContainer: {
1410
+ backgroundColor: "#FEE2E2",
1411
+ borderWidth: 1,
1412
+ borderColor: "#FECACA",
1413
+ borderRadius: 8,
1414
+ padding: 12,
1415
+ marginBottom: 16
1416
+ },
1417
+ errorText: {
1418
+ color: "#DC2626",
1419
+ fontSize: 14,
1420
+ textAlign: "center"
1421
+ },
1422
+ successIcon: {
1423
+ width: 60,
1424
+ height: 60,
1425
+ borderRadius: 30,
1426
+ backgroundColor: "#D1FAE5",
1427
+ alignItems: "center",
1428
+ justifyContent: "center",
1429
+ alignSelf: "center",
1430
+ marginBottom: 16
1431
+ },
1432
+ successIconText: {
1433
+ fontSize: 28,
1434
+ color: "#059669"
1435
+ }
1436
+ });
1437
+ var UserProfile = ({
1438
+ onEditPress,
1439
+ onLogoutPress,
1440
+ showLogoutButton = true
1441
+ }) => {
1442
+ const { user, signOut, loading } = useAuth();
1443
+ const handleLogout = async () => {
1444
+ await signOut();
1445
+ onLogoutPress?.();
1446
+ };
1447
+ if (!user) {
1448
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.container, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.notLoggedIn, children: "Not logged in" }) });
1449
+ }
1450
+ const getInitials = (name, email) => {
1451
+ if (name) {
1452
+ return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
1453
+ }
1454
+ return email?.charAt(0).toUpperCase() || "?";
1455
+ };
1456
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.container, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.card, children: [
1457
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.header, children: [
1458
+ user.avatar ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Image, { source: { uri: user.avatar }, style: styles8.avatar }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.avatarPlaceholder, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.avatarText, children: getInitials(user.name, user.email) }) }),
1459
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.userInfo, children: [
1460
+ user.name && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.name, children: user.name }),
1461
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.email, children: user.email })
1462
+ ] }),
1463
+ onEditPress && /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { style: styles8.editButton, onPress: onEditPress, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.editText, children: "Edit" }) })
1464
+ ] }),
1465
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.divider }),
1466
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.details, children: [
1467
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.detailRow, children: [
1468
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailLabel, children: "Email" }),
1469
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailValue, children: user.email })
1470
+ ] }),
1471
+ user.phoneNumber && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.detailRow, children: [
1472
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailLabel, children: "Phone" }),
1473
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailValue, children: user.phoneNumber })
1474
+ ] }),
1475
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.detailRow, children: [
1476
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailLabel, children: "Email Verified" }),
1477
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.badge, user.emailVerified ? styles8.badgeSuccess : styles8.badgeWarning], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.badgeText, user.emailVerified ? styles8.badgeTextSuccess : styles8.badgeTextWarning], children: user.emailVerified ? "Verified" : "Not Verified" }) })
1478
+ ] }),
1479
+ user.twoFactorEnabled !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.detailRow, children: [
1480
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles8.detailLabel, children: "2FA" }),
1481
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles8.badge, user.twoFactorEnabled ? styles8.badgeSuccess : styles8.badgeNeutral], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.badgeText, user.twoFactorEnabled ? styles8.badgeTextSuccess : styles8.badgeTextNeutral], children: user.twoFactorEnabled ? "Enabled" : "Disabled" }) })
1482
+ ] })
1483
+ ] }),
1484
+ showLogoutButton && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1485
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles8.divider }),
1486
+ /* @__PURE__ */ jsxRuntime.jsx(
1487
+ Button,
1488
+ {
1489
+ title: loading ? "Logging out..." : "Logout",
1490
+ onPress: handleLogout,
1491
+ loading,
1492
+ variant: "outline",
1493
+ style: styles8.logoutButton,
1494
+ textStyle: styles8.logoutText
1495
+ }
1496
+ )
1497
+ ] })
1498
+ ] }) });
1499
+ };
1500
+ var styles8 = reactNative.StyleSheet.create({
1501
+ container: {
1502
+ padding: 20
1503
+ },
1504
+ card: {
1505
+ backgroundColor: "#FFFFFF",
1506
+ borderRadius: 16,
1507
+ padding: 20,
1508
+ shadowColor: "#000",
1509
+ shadowOffset: { width: 0, height: 2 },
1510
+ shadowOpacity: 0.1,
1511
+ shadowRadius: 8,
1512
+ elevation: 4
1513
+ },
1514
+ header: {
1515
+ flexDirection: "row",
1516
+ alignItems: "center"
1517
+ },
1518
+ avatar: {
1519
+ width: 60,
1520
+ height: 60,
1521
+ borderRadius: 30
1522
+ },
1523
+ avatarPlaceholder: {
1524
+ width: 60,
1525
+ height: 60,
1526
+ borderRadius: 30,
1527
+ backgroundColor: "#4F46E5",
1528
+ alignItems: "center",
1529
+ justifyContent: "center"
1530
+ },
1531
+ avatarText: {
1532
+ color: "#FFFFFF",
1533
+ fontSize: 20,
1534
+ fontWeight: "700"
1535
+ },
1536
+ userInfo: {
1537
+ flex: 1,
1538
+ marginLeft: 16
1539
+ },
1540
+ name: {
1541
+ fontSize: 18,
1542
+ fontWeight: "600",
1543
+ color: "#111827"
1544
+ },
1545
+ email: {
1546
+ fontSize: 14,
1547
+ color: "#6B7280",
1548
+ marginTop: 2
1549
+ },
1550
+ editButton: {
1551
+ padding: 8
1552
+ },
1553
+ editText: {
1554
+ color: "#4F46E5",
1555
+ fontSize: 14,
1556
+ fontWeight: "600"
1557
+ },
1558
+ divider: {
1559
+ height: 1,
1560
+ backgroundColor: "#E5E7EB",
1561
+ marginVertical: 16
1562
+ },
1563
+ details: {
1564
+ gap: 12
1565
+ },
1566
+ detailRow: {
1567
+ flexDirection: "row",
1568
+ justifyContent: "space-between",
1569
+ alignItems: "center"
1570
+ },
1571
+ detailLabel: {
1572
+ fontSize: 14,
1573
+ color: "#6B7280"
1574
+ },
1575
+ detailValue: {
1576
+ fontSize: 14,
1577
+ color: "#111827",
1578
+ fontWeight: "500"
1579
+ },
1580
+ badge: {
1581
+ paddingHorizontal: 10,
1582
+ paddingVertical: 4,
1583
+ borderRadius: 12
1584
+ },
1585
+ badgeSuccess: {
1586
+ backgroundColor: "#D1FAE5"
1587
+ },
1588
+ badgeWarning: {
1589
+ backgroundColor: "#FEF3C7"
1590
+ },
1591
+ badgeNeutral: {
1592
+ backgroundColor: "#F3F4F6"
1593
+ },
1594
+ badgeText: {
1595
+ fontSize: 12,
1596
+ fontWeight: "600"
1597
+ },
1598
+ badgeTextSuccess: {
1599
+ color: "#059669"
1600
+ },
1601
+ badgeTextWarning: {
1602
+ color: "#D97706"
1603
+ },
1604
+ badgeTextNeutral: {
1605
+ color: "#6B7280"
1606
+ },
1607
+ logoutButton: {
1608
+ borderColor: "#EF4444"
1609
+ },
1610
+ logoutText: {
1611
+ color: "#EF4444"
1612
+ },
1613
+ notLoggedIn: {
1614
+ textAlign: "center",
1615
+ color: "#6B7280",
1616
+ fontSize: 16
1617
+ }
1618
+ });
1619
+ var ProtectedRoute = ({
1620
+ children,
1621
+ fallback,
1622
+ loadingComponent
1623
+ }) => {
1624
+ const { isLoaded, isSignedIn } = useAuth();
1625
+ if (!isLoaded) {
1626
+ return loadingComponent || /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.loadingContainer, children: [
1627
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { size: "large", color: "#4F46E5" }),
1628
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles9.loadingText, children: "Loading..." })
1629
+ ] });
1630
+ }
1631
+ if (!isSignedIn) {
1632
+ return fallback || /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.unauthorizedContainer, children: [
1633
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles9.unauthorizedTitle, children: "Access Denied" }),
1634
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles9.unauthorizedText, children: "Please sign in to access this content." })
1635
+ ] });
1636
+ }
1637
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1638
+ };
1639
+ var styles9 = reactNative.StyleSheet.create({
1640
+ loadingContainer: {
1641
+ flex: 1,
1642
+ justifyContent: "center",
1643
+ alignItems: "center",
1644
+ backgroundColor: "#F9FAFB"
1645
+ },
1646
+ loadingText: {
1647
+ marginTop: 12,
1648
+ fontSize: 16,
1649
+ color: "#6B7280"
1650
+ },
1651
+ unauthorizedContainer: {
1652
+ flex: 1,
1653
+ justifyContent: "center",
1654
+ alignItems: "center",
1655
+ padding: 20,
1656
+ backgroundColor: "#F9FAFB"
1657
+ },
1658
+ unauthorizedTitle: {
1659
+ fontSize: 20,
1660
+ fontWeight: "700",
1661
+ color: "#111827",
1662
+ marginBottom: 8
1663
+ },
1664
+ unauthorizedText: {
1665
+ fontSize: 14,
1666
+ color: "#6B7280",
1667
+ textAlign: "center"
1668
+ }
1669
+ });
1670
+
1671
+ exports.AuthProvider = AuthProvider;
1672
+ exports.AuthServiceRN = AuthServiceRN;
1673
+ exports.Button = Button;
1674
+ exports.ForgotPassword = ForgotPassword;
1675
+ exports.Input = Input;
1676
+ exports.LoginForm = LoginForm;
1677
+ exports.OtpForm = OtpForm;
1678
+ exports.ProtectedRoute = ProtectedRoute;
1679
+ exports.RegisterForm = RegisterForm;
1680
+ exports.ResetPassword = ResetPassword;
1681
+ exports.UserProfile = UserProfile;
1682
+ exports.useAuth = useAuth;
1683
+ //# sourceMappingURL=index.react-native.js.map
1684
+ //# sourceMappingURL=index.react-native.js.map