@imksh/create 1.0.23 → 1.0.25

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 (163) hide show
  1. package/package.json +1 -1
  2. package/src/utils/copyTemplate.js +6 -0
  3. package/templates/mern-react-native/client/src/vite-env.d.ts +1 -0
  4. package/templates/mern-react-native/mobile/babel.config.js +1 -0
  5. package/templates/mern-react-native/mobile/drizzle.config.ts +8 -0
  6. package/templates/mern-react-native/mobile/expo-env.d.ts +3 -0
  7. package/templates/mern-react-native/mobile/package.json +6 -0
  8. package/templates/mern-react-native/mobile/src/app/(auth)/_layout.tsx +12 -0
  9. package/templates/mern-react-native/mobile/src/app/(auth)/change-password.tsx +112 -0
  10. package/templates/mern-react-native/mobile/src/app/(auth)/edit-profile.tsx +160 -0
  11. package/templates/mern-react-native/mobile/src/app/(auth)/forgot-password.tsx +191 -0
  12. package/templates/mern-react-native/mobile/src/app/{login.tsx → (auth)/login.tsx} +69 -21
  13. package/templates/mern-react-native/mobile/src/app/(tabs)/index.tsx +18 -17
  14. package/templates/mern-react-native/mobile/src/app/(tabs)/profile.tsx +23 -60
  15. package/templates/mern-react-native/mobile/src/app/_layout.tsx +22 -4
  16. package/templates/mern-react-native/mobile/src/components/common/AnimatedHeader.tsx +328 -0
  17. package/templates/mern-react-native/mobile/src/components/common/LocationLoader.tsx +591 -0
  18. package/templates/mern-react-native/mobile/src/components/common/ScreenHeader.tsx +41 -17
  19. package/templates/mern-react-native/mobile/src/components/common/TabHeader.tsx +58 -0
  20. package/templates/mern-react-native/mobile/src/components/common/Typography.tsx +49 -30
  21. package/templates/mern-react-native/mobile/src/components/common/Welcome.tsx +2 -2
  22. package/templates/mern-react-native/mobile/src/components/ui/BottomModal.tsx +31 -20
  23. package/templates/mern-react-native/mobile/src/components/ui/ClassicTabBar.tsx +4 -3
  24. package/templates/mern-react-native/mobile/src/components/ui/CustomTabBar.tsx +108 -71
  25. package/templates/mern-react-native/mobile/src/components/ui/Sidebar.tsx +81 -56
  26. package/templates/mern-react-native/mobile/src/components/ui/buttons/Button.tsx +106 -37
  27. package/templates/mern-react-native/mobile/src/components/ui/buttons/IconButton.tsx +4 -2
  28. package/templates/mern-react-native/mobile/src/components/ui/data-display/Accordion.tsx +3 -2
  29. package/templates/mern-react-native/mobile/src/components/ui/data-display/Avatar.tsx +4 -3
  30. package/templates/mern-react-native/mobile/src/components/ui/data-display/Badge.tsx +45 -17
  31. package/templates/mern-react-native/mobile/src/components/ui/data-display/ImageViewer.tsx +19 -9
  32. package/templates/mern-react-native/mobile/src/components/ui/feedback/CircularProgress.tsx +5 -4
  33. package/templates/mern-react-native/mobile/src/components/ui/feedback/ProgressBar.tsx +4 -3
  34. package/templates/mern-react-native/mobile/src/components/ui/feedback/Skeleton.tsx +3 -0
  35. package/templates/mern-react-native/mobile/src/components/ui/feedback/Spinner.tsx +11 -3
  36. package/templates/mern-react-native/mobile/src/components/ui/inputs/Checkbox.tsx +3 -2
  37. package/templates/mern-react-native/mobile/src/components/ui/inputs/DatePicker.tsx +186 -0
  38. package/templates/mern-react-native/mobile/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
  39. package/templates/mern-react-native/mobile/src/components/ui/inputs/Input.tsx +54 -14
  40. package/templates/mern-react-native/mobile/src/components/ui/inputs/LocationPicker.tsx +211 -0
  41. package/templates/mern-react-native/mobile/src/components/ui/inputs/OTPInput.tsx +32 -9
  42. package/templates/mern-react-native/mobile/src/components/ui/inputs/PasswordInput.tsx +2 -1
  43. package/templates/mern-react-native/mobile/src/components/ui/inputs/Radio.tsx +3 -2
  44. package/templates/mern-react-native/mobile/src/components/ui/inputs/SearchBar.tsx +41 -4
  45. package/templates/mern-react-native/mobile/src/components/ui/inputs/Slider.tsx +4 -3
  46. package/templates/mern-react-native/mobile/src/components/ui/inputs/Switch.tsx +3 -2
  47. package/templates/mern-react-native/mobile/src/components/ui/inputs/TextArea.tsx +2 -1
  48. package/templates/mern-react-native/mobile/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
  49. package/templates/mern-react-native/mobile/src/components/ui/layout/Grid.tsx +52 -10
  50. package/templates/mern-react-native/mobile/src/components/ui/layout/Section.tsx +7 -8
  51. package/templates/mern-react-native/mobile/src/components/ui/navigation/Pagination.tsx +4 -3
  52. package/templates/mern-react-native/mobile/src/components/ui/navigation/ProgressStepper.tsx +6 -5
  53. package/templates/mern-react-native/mobile/src/components/ui/navigation/Tabs.tsx +30 -4
  54. package/templates/mern-react-native/mobile/src/config/api.ts +12 -1
  55. package/templates/mern-react-native/mobile/src/config/sidebar.config.ts +72 -0
  56. package/templates/mern-react-native/mobile/src/config/tabNavigation.ts +37 -7
  57. package/templates/mern-react-native/mobile/src/db/index.ts +9 -0
  58. package/templates/mern-react-native/mobile/src/db/schema.ts +14 -0
  59. package/templates/mern-react-native/mobile/src/hooks/useDebounce.ts +17 -0
  60. package/templates/mern-react-native/mobile/src/services/socket.service.ts +36 -0
  61. package/templates/mern-react-native/mobile/src/store/useAuthStore.ts +122 -27
  62. package/templates/mern-react-native/mobile/src/store/useNotificationStore.ts +53 -0
  63. package/templates/mern-react-native/mobile/src/types/auth.type.ts +14 -0
  64. package/templates/mern-react-native/mobile/tsconfig.json +1 -0
  65. package/templates/mern-ts/client/src/vite-env.d.ts +1 -0
  66. package/templates/react-native/babel.config.js +1 -0
  67. package/templates/react-native/drizzle.config.ts +8 -0
  68. package/templates/react-native/expo-env.d.ts +3 -0
  69. package/templates/react-native/package.json +6 -0
  70. package/templates/react-native/src/app/(auth)/_layout.tsx +12 -0
  71. package/templates/react-native/src/app/(auth)/change-password.tsx +112 -0
  72. package/templates/react-native/src/app/(auth)/edit-profile.tsx +160 -0
  73. package/templates/react-native/src/app/(auth)/forgot-password.tsx +191 -0
  74. package/templates/react-native/src/app/{login.tsx → (auth)/login.tsx} +69 -21
  75. package/templates/react-native/src/app/(tabs)/index.tsx +18 -17
  76. package/templates/react-native/src/app/(tabs)/profile.tsx +23 -60
  77. package/templates/react-native/src/app/_layout.tsx +22 -4
  78. package/templates/react-native/src/components/common/AnimatedHeader.tsx +328 -0
  79. package/templates/react-native/src/components/common/LocationLoader.tsx +591 -0
  80. package/templates/react-native/src/components/common/ScreenHeader.tsx +41 -17
  81. package/templates/react-native/src/components/common/TabHeader.tsx +58 -0
  82. package/templates/react-native/src/components/common/Typography.tsx +49 -30
  83. package/templates/react-native/src/components/common/Welcome.tsx +2 -2
  84. package/templates/react-native/src/components/ui/BottomModal.tsx +31 -20
  85. package/templates/react-native/src/components/ui/ClassicTabBar.tsx +4 -3
  86. package/templates/react-native/src/components/ui/CustomTabBar.tsx +108 -71
  87. package/templates/react-native/src/components/ui/Sidebar.tsx +81 -56
  88. package/templates/react-native/src/components/ui/buttons/Button.tsx +106 -37
  89. package/templates/react-native/src/components/ui/buttons/IconButton.tsx +4 -2
  90. package/templates/react-native/src/components/ui/data-display/Accordion.tsx +3 -2
  91. package/templates/react-native/src/components/ui/data-display/Avatar.tsx +4 -3
  92. package/templates/react-native/src/components/ui/data-display/Badge.tsx +45 -17
  93. package/templates/react-native/src/components/ui/data-display/ImageViewer.tsx +19 -9
  94. package/templates/react-native/src/components/ui/feedback/CircularProgress.tsx +5 -4
  95. package/templates/react-native/src/components/ui/feedback/ProgressBar.tsx +4 -3
  96. package/templates/react-native/src/components/ui/feedback/Skeleton.tsx +3 -0
  97. package/templates/react-native/src/components/ui/feedback/Spinner.tsx +11 -3
  98. package/templates/react-native/src/components/ui/inputs/Checkbox.tsx +3 -2
  99. package/templates/react-native/src/components/ui/inputs/DatePicker.tsx +186 -0
  100. package/templates/react-native/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
  101. package/templates/react-native/src/components/ui/inputs/Input.tsx +54 -14
  102. package/templates/react-native/src/components/ui/inputs/LocationPicker.tsx +211 -0
  103. package/templates/react-native/src/components/ui/inputs/OTPInput.tsx +32 -9
  104. package/templates/react-native/src/components/ui/inputs/PasswordInput.tsx +2 -1
  105. package/templates/react-native/src/components/ui/inputs/Radio.tsx +3 -2
  106. package/templates/react-native/src/components/ui/inputs/SearchBar.tsx +41 -4
  107. package/templates/react-native/src/components/ui/inputs/Slider.tsx +4 -3
  108. package/templates/react-native/src/components/ui/inputs/Switch.tsx +3 -2
  109. package/templates/react-native/src/components/ui/inputs/TextArea.tsx +2 -1
  110. package/templates/react-native/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
  111. package/templates/react-native/src/components/ui/layout/Grid.tsx +52 -10
  112. package/templates/react-native/src/components/ui/layout/Section.tsx +7 -8
  113. package/templates/react-native/src/components/ui/navigation/Pagination.tsx +4 -3
  114. package/templates/react-native/src/components/ui/navigation/ProgressStepper.tsx +6 -5
  115. package/templates/react-native/src/components/ui/navigation/Tabs.tsx +30 -4
  116. package/templates/react-native/src/config/api.ts +12 -1
  117. package/templates/react-native/src/config/sidebar.config.ts +72 -0
  118. package/templates/react-native/src/config/tabNavigation.ts +37 -7
  119. package/templates/react-native/src/db/index.ts +9 -0
  120. package/templates/react-native/src/db/schema.ts +14 -0
  121. package/templates/react-native/src/hooks/useDebounce.ts +17 -0
  122. package/templates/react-native/src/services/socket.service.ts +36 -0
  123. package/templates/react-native/src/store/useAuthStore.ts +122 -27
  124. package/templates/react-native/src/store/useNotificationStore.ts +53 -0
  125. package/templates/react-native/src/types/auth.type.ts +14 -0
  126. package/templates/react-native/tsconfig.json +1 -0
  127. package/templates/react-ts/src/vite-env.d.ts +1 -0
  128. package/templates/mern-react-native/mobile/.env +0 -2
  129. package/templates/mern-react-native/mobile/.env.example +0 -2
  130. package/templates/mern-react-native/mobile/.vscode/extensions.json +0 -1
  131. package/templates/mern-react-native/mobile/.vscode/settings.json +0 -7
  132. package/templates/mern-react-native/mobile/README.md +0 -159
  133. package/templates/mern-react-native/mobile/docs/README.md +0 -17
  134. package/templates/mern-react-native/mobile/docs/components/buttons.md +0 -40
  135. package/templates/mern-react-native/mobile/docs/components/data-display.md +0 -44
  136. package/templates/mern-react-native/mobile/docs/components/feedback.md +0 -36
  137. package/templates/mern-react-native/mobile/docs/components/gestures.md +0 -60
  138. package/templates/mern-react-native/mobile/docs/components/inputs.md +0 -41
  139. package/templates/mern-react-native/mobile/docs/components/layout.md +0 -34
  140. package/templates/mern-react-native/mobile/docs/components/navigation.md +0 -31
  141. package/templates/mern-react-native/mobile/docs/features.md +0 -85
  142. package/templates/mern-react-native/mobile/docs/getting-started.md +0 -47
  143. package/templates/mern-react-native/mobile/src/components/common/HomeHeader.tsx +0 -43
  144. package/templates/mern-react-native/mobile/src/components/settings/SettingToggle.tsx +0 -26
  145. package/templates/mern-react-native/mobile/src/components/settings/SettingsOptions.tsx +0 -47
  146. package/templates/react-native/.env +0 -2
  147. package/templates/react-native/.env.example +0 -2
  148. package/templates/react-native/.vscode/extensions.json +0 -1
  149. package/templates/react-native/.vscode/settings.json +0 -7
  150. package/templates/react-native/README.md +0 -159
  151. package/templates/react-native/docs/README.md +0 -17
  152. package/templates/react-native/docs/components/buttons.md +0 -40
  153. package/templates/react-native/docs/components/data-display.md +0 -44
  154. package/templates/react-native/docs/components/feedback.md +0 -36
  155. package/templates/react-native/docs/components/gestures.md +0 -60
  156. package/templates/react-native/docs/components/inputs.md +0 -41
  157. package/templates/react-native/docs/components/layout.md +0 -34
  158. package/templates/react-native/docs/components/navigation.md +0 -31
  159. package/templates/react-native/docs/features.md +0 -85
  160. package/templates/react-native/docs/getting-started.md +0 -47
  161. package/templates/react-native/src/components/common/HomeHeader.tsx +0 -43
  162. package/templates/react-native/src/components/settings/SettingToggle.tsx +0 -26
  163. package/templates/react-native/src/components/settings/SettingsOptions.tsx +0 -47
@@ -0,0 +1,160 @@
1
+ import React, { useState , useCallback } from "react";
2
+ import { View, TouchableOpacity } from "react-native";
3
+ import { useAuthStore } from "../../store/useAuthStore";
4
+ import { Txt } from "../../components/common/Typography";
5
+ import { router, useFocusEffect } from "expo-router";
6
+ import * as ImagePicker from "expo-image-picker";
7
+ import { Ionicons } from "@expo/vector-icons";
8
+ import Avatar from "../../components/ui/data-display/Avatar";
9
+
10
+ import ScrollContainer from "../../components/ui/layout/ScrollContainer";
11
+ import Input from "../../components/ui/inputs/Input";
12
+ import Button from "../../components/ui/buttons/Button";
13
+ import ScreenHeader from "@/components/common/ScreenHeader";
14
+ import { toast } from "@/utils/toast";
15
+ import { authService } from "@/services/auth.service";
16
+
17
+ export default function EditProfileScreen() {
18
+ const { user, error, setUser, clearError } = useAuthStore();
19
+ const [loading, setLoading] = useState(false);
20
+
21
+ useFocusEffect(
22
+ useCallback(() => {
23
+ return () => clearError();
24
+ }, [clearError])
25
+ );
26
+
27
+ const [name, setName] = useState(user?.name || "");
28
+ const [phone, setPhone] = useState(user?.phone || "");
29
+ const [avatarUri, setAvatarUri] = useState<string | null>(null);
30
+
31
+ const pickImage = async () => {
32
+ const result = await ImagePicker.launchImageLibraryAsync({
33
+ mediaTypes: ImagePicker.MediaTypeOptions.Images,
34
+ allowsEditing: true,
35
+ aspect: [1, 1],
36
+ quality: 0.8,
37
+ });
38
+
39
+ if (!result.canceled && result.assets[0]) {
40
+ setAvatarUri(result.assets[0].uri);
41
+ }
42
+ };
43
+
44
+ const handleSave = async () => {
45
+ const formData = new FormData();
46
+ try {
47
+ setLoading(true);
48
+ if (name !== user?.name) formData.append("name", name);
49
+ if (phone !== user?.phone) formData.append("phone", phone);
50
+
51
+ if (avatarUri) {
52
+ const filename = avatarUri.split("/").pop() || "avatar.jpg";
53
+ const match = /\.(\w+)$/.exec(filename);
54
+ const type = match ? `image/${match[1]}` : `image`;
55
+
56
+ formData.append("file", {
57
+ uri: avatarUri,
58
+ name: filename,
59
+ type,
60
+ } as any);
61
+ }
62
+
63
+ // Only update if something changed
64
+ if (
65
+ (formData as any).getParts &&
66
+ (formData as any).getParts().length === 0
67
+ ) {
68
+ router.back();
69
+ return;
70
+ }
71
+
72
+ const res = await authService.updateMe(formData);
73
+ if (res.data.success) {
74
+ setUser(res.data.data);
75
+ toast.success("Profile updated successfully");
76
+ router.back();
77
+ } else {
78
+ toast.error(res.data.message);
79
+ }
80
+
81
+ console.log(res.data.data);
82
+ } catch (error: any) {
83
+ toast.error(error.response?.data?.message || error.message);
84
+ } finally {
85
+ setLoading(false);
86
+ }
87
+ };
88
+
89
+ return (
90
+ <>
91
+ <ScreenHeader title="Edit Profile" />
92
+ <ScrollContainer
93
+ contentContainerStyle={{
94
+ flexGrow: 1,
95
+ padding: 16,
96
+ }}
97
+ className="bg-base-100"
98
+ >
99
+ <View className="items-center mb-8">
100
+ <View className="relative">
101
+ <View className="w-28 h-28 rounded-full items-center justify-center border-4 border-base-100 shadow-sm shadow-base-content/20 overflow-hidden">
102
+ {avatarUri ? (
103
+ <Avatar url={avatarUri} size={104} />
104
+ ) : (
105
+ <Avatar
106
+ url={
107
+ user?.avatar?.url ||
108
+ `https://placehold.co/600x400?text=${user?.name?.charAt(0).toUpperCase() || "U"}`
109
+ }
110
+ size={104}
111
+ />
112
+ )}
113
+ </View>
114
+ <TouchableOpacity
115
+ onPress={pickImage}
116
+ className="absolute bottom-0 right-0 bg-primary p-2 rounded-full border-2 border-base-100"
117
+ >
118
+ <Ionicons name="camera" size={18} color="#fff" />
119
+ </TouchableOpacity>
120
+ </View>
121
+ </View>
122
+
123
+ {error ? (
124
+ <View className="bg-error/10 border border-error/20 rounded-2xl p-3 mb-4">
125
+ <Txt variant="md" className="text-error text-xs text-center">
126
+ ⚠️ {error}
127
+ </Txt>
128
+ </View>
129
+ ) : null}
130
+
131
+ <View className="gap-4">
132
+ <Input
133
+ leftIcon="person"
134
+ placeholder="Full name"
135
+ value={name}
136
+ onChangeText={setName}
137
+ />
138
+
139
+ <Input
140
+ leftIcon="call"
141
+ placeholder="Phone number"
142
+ value={phone}
143
+ onChangeText={setPhone}
144
+ keyboardType="phone-pad"
145
+ />
146
+
147
+ <View className="mt-4">
148
+ <Button
149
+ label="Save Changes"
150
+ onPress={handleSave}
151
+ isLoading={loading}
152
+ variant="primary"
153
+ isFullWidth
154
+ />
155
+ </View>
156
+ </View>
157
+ </ScrollContainer>
158
+ </>
159
+ );
160
+ }
@@ -0,0 +1,191 @@
1
+ import React, { useState, useEffect , useCallback } from "react";
2
+ import { View } from "react-native";
3
+ import { useAuthStore } from "../../store/useAuthStore";
4
+ import { Txt } from "../../components/common/Typography";
5
+ import { router, useFocusEffect } from "expo-router";
6
+ import ScrollContainer from "../../components/ui/layout/ScrollContainer";
7
+ import Input from "../../components/ui/inputs/Input";
8
+ import Button from "../../components/ui/buttons/Button";
9
+
10
+ export default function ForgotPasswordScreen() {
11
+ const { genOtp, verifyOtp, resetPassword, loading, error, clearError } = useAuthStore();
12
+ const [step, setStep] = useState<"email" | "otp" | "password">("email");
13
+
14
+ useFocusEffect(
15
+ useCallback(() => {
16
+ return () => clearError();
17
+ }, [clearError])
18
+ );
19
+
20
+ const [email, setEmail] = useState("");
21
+ const [otp, setOtp] = useState("");
22
+ const [newPassword, setNewPassword] = useState("");
23
+ const [showPassword, setShowPassword] = useState(false);
24
+
25
+ const [timer, setTimer] = useState(0);
26
+
27
+ useEffect(() => {
28
+ let interval: ReturnType<typeof setInterval>;
29
+ if (timer > 0) {
30
+ interval = setInterval(() => {
31
+ setTimer((prev) => prev - 1);
32
+ }, 1000);
33
+ }
34
+ return () => clearInterval(interval);
35
+ }, [timer]);
36
+
37
+ const handleSendOtp = async () => {
38
+ if (!email) return;
39
+ const success = await genOtp(email);
40
+ if (success) {
41
+ setStep("otp");
42
+ setTimer(60);
43
+ }
44
+ };
45
+
46
+ const handleVerifyOtp = async () => {
47
+ if (!otp) return;
48
+ const success = await verifyOtp(email, otp);
49
+ if (success) {
50
+ setStep("password");
51
+ }
52
+ };
53
+
54
+ const handleResetPassword = async () => {
55
+ if (!newPassword) return;
56
+ const success = await resetPassword(newPassword);
57
+ if (success) {
58
+ router.replace("/(auth)/login");
59
+ }
60
+ };
61
+
62
+ return (
63
+ <ScrollContainer
64
+ contentContainerStyle={{
65
+ flexGrow: 1,
66
+ justifyContent: "center",
67
+ padding: 16,
68
+ }}
69
+ className="bg-base-100"
70
+ >
71
+ <View className="w-full p-6">
72
+ <View className="items-center mb-8 w-full">
73
+ <Txt variant="xl" className="text-2xl mb-1 text-center">
74
+ {step === "email" && "Forgot Password"}
75
+ {step === "otp" && "Verify Email"}
76
+ {step === "password" && "Reset Password"}
77
+ </Txt>
78
+ <Txt
79
+ variant="sm"
80
+ className="text-xs text-base-content/50 text-center px-2"
81
+ >
82
+ {step === "email" && "Enter your email to receive an OTP"}
83
+ {step === "otp" && `Enter the OTP sent to ${email}`}
84
+ {step === "password" && "Enter your new password"}
85
+ </Txt>
86
+ </View>
87
+
88
+ {error ? (
89
+ <View className="bg-error/10 border border-error/20 rounded-2xl p-3 mb-4">
90
+ <Txt variant="md" className="text-error text-xs text-center">
91
+ ⚠️ {error}
92
+ </Txt>
93
+ </View>
94
+ ) : null}
95
+
96
+ <View className="gap-2">
97
+ {step === "email" && (
98
+ <>
99
+ <Input
100
+ leftIcon="mail"
101
+ placeholder="Email address"
102
+ value={email}
103
+ onChangeText={setEmail}
104
+ autoCapitalize="none"
105
+ keyboardType="email-address"
106
+ />
107
+ <View className="mt-2">
108
+ <Button
109
+ label="Send OTP →"
110
+ onPress={handleSendOtp}
111
+ isLoading={loading}
112
+ variant="primary"
113
+ isFullWidth
114
+ />
115
+ </View>
116
+ </>
117
+ )}
118
+
119
+ {step === "otp" && (
120
+ <>
121
+ <Input
122
+ leftIcon="key"
123
+ placeholder="Enter OTP"
124
+ value={otp}
125
+ onChangeText={setOtp}
126
+ keyboardType="numeric"
127
+ />
128
+ <View className="mt-2">
129
+ <Button
130
+ label="Verify OTP →"
131
+ onPress={handleVerifyOtp}
132
+ isLoading={loading}
133
+ variant="primary"
134
+ isFullWidth
135
+ />
136
+ </View>
137
+ <View className="mt-4">
138
+ <Button
139
+ label={timer > 0 ? `Resend OTP in ${timer}s` : "Resend OTP"}
140
+ onPress={handleSendOtp}
141
+ disabled={timer > 0 || loading}
142
+ variant="outline"
143
+ isFullWidth
144
+ />
145
+ </View>
146
+ </>
147
+ )}
148
+
149
+ {step === "password" && (
150
+ <>
151
+ <Input
152
+ leftIcon="lock-closed"
153
+ rightIcon={showPassword ? "eye-off" : "eye"}
154
+ onRightIconPress={() => setShowPassword(!showPassword)}
155
+ placeholder="New Password"
156
+ value={newPassword}
157
+ onChangeText={setNewPassword}
158
+ secureTextEntry={!showPassword}
159
+ />
160
+ <View className="mt-2">
161
+ <Button
162
+ label="Reset Password →"
163
+ onPress={handleResetPassword}
164
+ isLoading={loading}
165
+ variant="primary"
166
+ isFullWidth
167
+ />
168
+ </View>
169
+ </>
170
+ )}
171
+ </View>
172
+
173
+ <View className="mt-8">
174
+ <Txt
175
+ variant="sm"
176
+ className="text-sm text-base-content/50 text-center"
177
+ >
178
+ Remember your password?{" "}
179
+ <Txt
180
+ variant="md"
181
+ className="text-primary text-sm"
182
+ onPress={() => router.push("/(auth)/login")}
183
+ >
184
+ Sign in
185
+ </Txt>
186
+ </Txt>
187
+ </View>
188
+ </View>
189
+ </ScrollContainer>
190
+ );
191
+ }
@@ -1,28 +1,34 @@
1
- import React, { useState } from "react";
1
+ import React, { useState, useCallback } from "react";
2
2
  import { View } from "react-native";
3
- import { useAuthStore } from "../store/useAuthStore";
4
- import { Txt } from "../components/common/Typography";
5
- import { Redirect } from "expo-router";
6
-
7
- import ScrollContainer from "../components/ui/layout/ScrollContainer";
8
- import Input from "../components/ui/inputs/Input";
9
- import Button from "../components/ui/buttons/Button";
10
- import Tabs from "../components/ui/navigation/Tabs";
3
+ import { useAuthStore } from "../../store/useAuthStore";
4
+ import { Txt } from "../../components/common/Typography";
5
+ import { Redirect, router, useFocusEffect } from "expo-router";
6
+ import ScrollContainer from "../../components/ui/layout/ScrollContainer";
7
+ import Input from "../../components/ui/inputs/Input";
8
+ import Button from "../../components/ui/buttons/Button";
9
+ import Tabs from "../../components/ui/navigation/Tabs";
11
10
  import Image from "@/components/ui/data-display/Image";
12
- import logo from "../../assets/images/logo/logo.png";
11
+ import logo from "../../../assets/images/logo/logo.png";
13
12
 
14
13
  export default function LoginScreen() {
15
14
  const {
16
15
  login,
17
- demoLogin,
18
16
  signup,
19
17
  sendOtp,
20
18
  loading,
21
19
  error,
22
20
  user,
23
21
  isCheckingAuth,
22
+ clearError,
23
+ demoLogin,
24
24
  } = useAuthStore();
25
25
 
26
+ useFocusEffect(
27
+ useCallback(() => {
28
+ return () => clearError();
29
+ }, [clearError]),
30
+ );
31
+
26
32
  const [mode, setMode] = useState("login");
27
33
  const [showPassword, setShowPassword] = useState(false);
28
34
  const [form, setForm] = useState({
@@ -32,6 +38,17 @@ export default function LoginScreen() {
32
38
  otp: "",
33
39
  });
34
40
  const [otpSent, setOtpSent] = useState(false);
41
+ const [timer, setTimer] = useState(0);
42
+
43
+ React.useEffect(() => {
44
+ let interval: ReturnType<typeof setInterval>;
45
+ if (timer > 0) {
46
+ interval = setInterval(() => {
47
+ setTimer((prev) => prev - 1);
48
+ }, 1000);
49
+ }
50
+ return () => clearInterval(interval);
51
+ }, [timer]);
35
52
 
36
53
  const handleChange = (name: string, value: string) => {
37
54
  setForm((prev) => ({ ...prev, [name]: value }));
@@ -44,7 +61,10 @@ export default function LoginScreen() {
44
61
  } else {
45
62
  if (!otpSent) {
46
63
  ok = await sendOtp(form.email);
47
- if (ok) setOtpSent(true);
64
+ if (ok) {
65
+ setOtpSent(true);
66
+ setTimer(60);
67
+ }
48
68
  } else {
49
69
  ok = await signup(form.name, form.email, form.password, form.otp);
50
70
  }
@@ -62,22 +82,23 @@ export default function LoginScreen() {
62
82
  justifyContent: "center",
63
83
  padding: 16,
64
84
  }}
85
+ className="bg-base-100"
65
86
  >
66
- <View className="w-full p-6">
87
+ <View className="w-full p-6 ">
67
88
  {/* Header */}
68
89
  <View className="items-center mb-8 w-full">
69
90
  <View className="w-16 h-16 rounded-2xl bg-primary/10 border border-primary/20 items-center justify-center mb-4">
70
91
  <Image src={logo} height={40} width={40} />
71
92
  </View>
72
93
  <Txt
73
- variant="h1"
94
+ variant="xl"
74
95
  className="text-2xl mb-1 text-center"
75
96
  numberOfLines={1}
76
97
  >
77
98
  {mode === "login" ? "Welcome back" : "Create account"}
78
99
  </Txt>
79
100
  <Txt
80
- variant="regular"
101
+ variant="sm"
81
102
  className="text-xs text-base-content/50 text-center px-2"
82
103
  >
83
104
  {mode === "login"
@@ -105,7 +126,7 @@ export default function LoginScreen() {
105
126
  {/* Error */}
106
127
  {error ? (
107
128
  <View className="bg-error/10 border border-error/20 rounded-2xl p-3 mb-4">
108
- <Txt variant="mid" className="text-error text-xs text-center">
129
+ <Txt variant="md" className="text-error text-xs text-center">
109
130
  ⚠️ {error}
110
131
  </Txt>
111
132
  </View>
@@ -141,6 +162,18 @@ export default function LoginScreen() {
141
162
  secureTextEntry={!showPassword}
142
163
  />
143
164
 
165
+ {mode === "login" && (
166
+ <View className="items-end mt-1 mb-2">
167
+ <Txt
168
+ variant="md"
169
+ className="text-primary text-xs"
170
+ onPress={() => router.push("/(auth)/forgot-password")}
171
+ >
172
+ Forgot Password?
173
+ </Txt>
174
+ </View>
175
+ )}
176
+
144
177
  {mode === "signup" && otpSent && (
145
178
  <Input
146
179
  leftIcon="key"
@@ -170,9 +203,24 @@ export default function LoginScreen() {
170
203
  {mode === "login" && (
171
204
  <View className="mt-2">
172
205
  <Button
173
- label="Use Demo Account"
174
- onPress={demoLogin}
175
- disabled={loading}
206
+ label="Demo Login"
207
+ onPress={() => demoLogin()}
208
+ isLoading={loading}
209
+ variant="outline"
210
+ isFullWidth
211
+ />
212
+ </View>
213
+ )}
214
+
215
+ {mode === "signup" && otpSent && (
216
+ <View className="mt-2">
217
+ <Button
218
+ label={timer > 0 ? `Resend OTP in ${timer}s` : "Resend OTP"}
219
+ onPress={async () => {
220
+ const ok = await sendOtp(form.email);
221
+ if (ok) setTimer(60);
222
+ }}
223
+ disabled={timer > 0 || loading}
176
224
  variant="outline"
177
225
  isFullWidth
178
226
  />
@@ -183,12 +231,12 @@ export default function LoginScreen() {
183
231
  {/* Footer */}
184
232
  <View className="mt-8">
185
233
  <Txt
186
- variant="regular"
234
+ variant="sm"
187
235
  className="text-sm text-base-content/50 text-center"
188
236
  >
189
237
  {mode === "login" ? "New here? " : "Already have an account? "}
190
238
  <Txt
191
- variant="mid"
239
+ variant="md"
192
240
  className="text-primary text-sm"
193
241
  onPress={() => {
194
242
  setMode(mode === "login" ? "signup" : "login");
@@ -9,6 +9,7 @@ import { toast } from "@/utils/toast";
9
9
  import ScrollContainer from "@/components/ui/layout/ScrollContainer";
10
10
  import Container from "@/components/ui/layout/Container";
11
11
  import Section from "@/components/ui/layout/Section";
12
+ import Divider from "@/components/ui/layout/Divider";
12
13
  import { HStack, VStack } from "@/components/ui/layout/Stack";
13
14
 
14
15
  import Button from "@/components/ui/buttons/Button";
@@ -79,7 +80,7 @@ const Index = () => {
79
80
  >
80
81
  <HStack justify="space-between" align="center">
81
82
  <VStack>
82
- <Txt variant="h2" className="font-extrabold tracking-tight">
83
+ <Txt variant="3xl" className="font-extrabold tracking-tight">
83
84
  imksh-create
84
85
  </Txt>
85
86
  <Txt
@@ -115,12 +116,12 @@ const Index = () => {
115
116
  <Badge label="SOFT" variant="primary" soft={true} />
116
117
  </HStack>
117
118
  <Txt
118
- variant="h1"
119
+ variant="4xl"
119
120
  className="text-primary font-black leading-tight"
120
121
  >
121
122
  Stop configuring. Start building.
122
123
  </Txt>
123
- <Txt variant="body" className="text-primary/70 font-medium">
124
+ <Txt variant="base" className="text-primary/70 font-medium">
124
125
  Skip the setup. Build your product. A complete boilerplate with auth, state management, navigation, and beautiful prebuilt components.
125
126
  </Txt>
126
127
  </VStack>
@@ -197,7 +198,7 @@ const Index = () => {
197
198
  size={50}
198
199
  />
199
200
  <VStack style={{ flex: 1 }}>
200
- <Txt variant="mid" className="font-bold">
201
+ <Txt variant="md" className="font-bold">
201
202
  Swipe me left!
202
203
  </Txt>
203
204
  <Txt
@@ -234,7 +235,7 @@ const Index = () => {
234
235
  color={colors.accent}
235
236
  style={{ marginBottom: 12 }}
236
237
  />
237
- <Txt variant="h3" className="text-accent text-center">
238
+ <Txt variant="2xl" className="text-accent text-center">
238
239
  Double Tap or Swipe Up
239
240
  </Txt>
240
241
  <Txt
@@ -258,11 +259,11 @@ const Index = () => {
258
259
  placeholder="Search components..."
259
260
  />
260
261
 
261
- <View className="h-px w-full bg-base-300/50" />
262
+ <Divider />
262
263
 
263
264
  <HStack justify="space-between" align="center">
264
265
  <VStack>
265
- <Txt variant="mid" className="font-bold">
266
+ <Txt variant="md" className="font-bold">
266
267
  Biometric Login
267
268
  </Txt>
268
269
  <Txt
@@ -275,11 +276,11 @@ const Index = () => {
275
276
  <Switch checked={isEnabled} onChange={setIsEnabled} />
276
277
  </HStack>
277
278
 
278
- <View className="h-px w-full bg-base-300/50" />
279
+ <Divider />
279
280
 
280
281
  <VStack spacing={12}>
281
282
  <HStack justify="space-between" align="center">
282
- <Txt variant="mid" className="font-bold">
283
+ <Txt variant="md" className="font-bold">
283
284
  Intensity
284
285
  </Txt>
285
286
  <Badge label={`${sliderVal}%`} variant="secondary" />
@@ -292,7 +293,7 @@ const Index = () => {
292
293
  />
293
294
  </VStack>
294
295
 
295
- <View className="h-px w-full bg-base-300/50 mt-2" />
296
+ <Divider style={{ marginTop: 8 }} />
296
297
 
297
298
  {/* Text Input */}
298
299
  <Input
@@ -301,7 +302,7 @@ const Index = () => {
301
302
  leftIcon="mail-outline"
302
303
  />
303
304
 
304
- <View className="h-px w-full bg-base-300/50" />
305
+ <Divider />
305
306
 
306
307
  {/* Selection Controls */}
307
308
  <VStack spacing={16}>
@@ -341,7 +342,7 @@ const Index = () => {
341
342
  ]}
342
343
  />
343
344
  <View className="py-6 items-center justify-center">
344
- <Txt variant="body" className="text-base-content/60 italic">
345
+ <Txt variant="base" className="text-base-content/60 italic">
345
346
  Currently viewing {activeTab} content.
346
347
  </Txt>
347
348
  </View>
@@ -380,7 +381,7 @@ const Index = () => {
380
381
 
381
382
  <Card elevation={1} className="rounded-3xl p-6 mt-4">
382
383
  <HStack justify="space-between" align="center" className="mb-4">
383
- <Txt variant="mid" className="font-bold">
384
+ <Txt variant="md" className="font-bold">
384
385
  Background Sync
385
386
  </Txt>
386
387
  <Spinner size={24} />
@@ -399,14 +400,14 @@ const Index = () => {
399
400
  <Section title="Information & FAQs" className="pb-20">
400
401
  <VStack spacing={12}>
401
402
  <Accordion title="How to use this library?">
402
- <Txt variant="body">
403
+ <Txt variant="base">
403
404
  Simply import the components from the `@/components/ui`
404
405
  directory. They are fully typed, gesture-driven, and styled
405
406
  with NativeWind.
406
407
  </Txt>
407
408
  </Accordion>
408
409
  <Accordion title="Does it support dark mode?">
409
- <Txt variant="body">
410
+ <Txt variant="base">
410
411
  Yes! All components automatically respond to the device&apos;s
411
412
  color scheme, utilizing the custom CSS variables defined in
412
413
  global.css.
@@ -437,11 +438,11 @@ const Index = () => {
437
438
  color={colors.primary}
438
439
  />
439
440
  </View>
440
- <Txt variant="h2" className="text-center font-black">
441
+ <Txt variant="3xl" className="text-center font-black">
441
442
  Premium Modal
442
443
  </Txt>
443
444
  <Txt
444
- variant="body"
445
+ variant="base"
445
446
  className="text-center text-base-content/70 leading-relaxed px-4"
446
447
  >
447
448
  This highly responsive bottom sheet is gesture-driven. You can