@imksh/create 1.0.30 → 1.0.32

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 (247) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/src/commands/create.js +2 -0
  4. package/src/index.js +1 -1
  5. package/src/utils/askTemplate.js +2 -1
  6. package/templates/layers/electron/base/electron/main.js +262 -0
  7. package/templates/layers/electron/base/electron/preload.js +37 -0
  8. package/templates/layers/electron/base/electron-builder.json5 +68 -0
  9. package/templates/layers/electron/javascript/_gitignore +38 -0
  10. package/templates/layers/electron/javascript/package.json +49 -0
  11. package/templates/layers/electron/javascript/src/components/layout/SidebarLayout.jsx +43 -0
  12. package/templates/layers/electron/javascript/src/components/ui/TitleBar.jsx +130 -0
  13. package/templates/layers/electron/javascript/src/config/appConfig.js +51 -0
  14. package/templates/layers/electron/javascript/src/hooks/useElectron.js +68 -0
  15. package/templates/layers/electron/javascript/src/main.jsx +17 -0
  16. package/templates/layers/electron/javascript/src/store/useUiStore.js +59 -0
  17. package/templates/layers/electron/javascript/vite.config.js +29 -0
  18. package/templates/layers/electron/typescript/_gitignore +38 -0
  19. package/templates/layers/electron/typescript/electron/main.ts +213 -0
  20. package/templates/layers/electron/typescript/electron/preload.ts +52 -0
  21. package/templates/layers/electron/typescript/package.json +52 -0
  22. package/templates/layers/electron/typescript/src/components/layout/SidebarLayout.tsx +42 -0
  23. package/templates/layers/electron/typescript/src/components/ui/TitleBar.tsx +120 -0
  24. package/templates/layers/electron/typescript/src/config/appConfig.ts +52 -0
  25. package/templates/layers/electron/typescript/src/hooks/useElectron.ts +68 -0
  26. package/templates/layers/electron/typescript/src/main.tsx +17 -0
  27. package/templates/layers/electron/typescript/src/store/useUiStore.ts +97 -0
  28. package/templates/layers/electron/typescript/src/vite-env.d.ts +13 -0
  29. package/templates/layers/electron/typescript/tsconfig.json +25 -0
  30. package/templates/layers/electron/typescript/tsconfig.node.json +11 -0
  31. package/templates/layers/electron/typescript/vite.config.ts +29 -0
  32. package/templates/layers/next/javascript/package.json +8 -2
  33. package/templates/layers/next/javascript/src/components/common/Breadcrumbs.jsx +44 -6
  34. package/templates/layers/next/javascript/src/components/common/Loading.jsx +1 -0
  35. package/templates/layers/next/javascript/src/components/common/LottieIcon.jsx +1 -0
  36. package/templates/layers/next/javascript/src/components/common/Pagination.jsx +170 -0
  37. package/templates/layers/next/javascript/src/components/common/SidebarModal.jsx +180 -0
  38. package/templates/layers/next/javascript/src/components/common/StatsCard.jsx +168 -0
  39. package/templates/layers/next/javascript/src/components/common/Table.jsx +191 -41
  40. package/templates/layers/next/javascript/src/components/common/Tabs.jsx +187 -0
  41. package/templates/layers/next/javascript/src/components/common/ToggleSwitch.jsx +4 -3
  42. package/templates/layers/next/javascript/src/components/layout/ProtectedRoute.jsx +2 -1
  43. package/templates/layers/next/javascript/src/components/layout/PublicLayout.jsx +3 -6
  44. package/templates/layers/next/javascript/src/components/layout/SidebarLayout.jsx +4 -17
  45. package/templates/layers/next/javascript/src/components/modals/ConfirmModal.jsx +4 -12
  46. package/templates/layers/next/javascript/src/components/modals/Modal.jsx +50 -19
  47. package/templates/layers/next/javascript/src/components/ui/Input.jsx +50 -0
  48. package/templates/layers/next/{typescript/src/components/ui/sidebar.tsx → javascript/src/components/ui/Sidebar.jsx} +65 -53
  49. package/templates/layers/next/javascript/src/components/ui/SidebarHeader.jsx +11 -6
  50. package/templates/layers/next/javascript/src/config/appConfig.js +4 -4
  51. package/templates/layers/next/javascript/src/hooks/useWindowSize.js +2 -3
  52. package/templates/layers/next/javascript/src/store/useUiStore.js +9 -4
  53. package/templates/layers/next/typescript/.eslintrc.json +12 -0
  54. package/templates/layers/next/typescript/package.json +14 -3
  55. package/templates/layers/next/typescript/src/components/common/Breadcrumbs.tsx +57 -8
  56. package/templates/layers/next/typescript/src/components/common/Loading.tsx +2 -1
  57. package/templates/layers/next/typescript/src/components/common/LottieIcon.tsx +2 -2
  58. package/templates/layers/next/typescript/src/components/common/Pagination.tsx +186 -0
  59. package/templates/layers/next/typescript/src/components/common/SidebarModal.tsx +200 -0
  60. package/templates/layers/next/typescript/src/components/common/StatsCard.tsx +232 -0
  61. package/templates/layers/next/typescript/src/components/common/Table.tsx +205 -39
  62. package/templates/layers/next/typescript/src/components/common/Tabs.tsx +190 -0
  63. package/templates/layers/next/typescript/src/components/common/ToggleSwitch.tsx +12 -8
  64. package/templates/layers/next/typescript/src/components/layout/PublicLayout.tsx +8 -6
  65. package/templates/layers/next/typescript/src/components/layout/SidebarLayout.tsx +8 -17
  66. package/templates/layers/next/typescript/src/components/modals/ConfirmModal.tsx +3 -1
  67. package/templates/layers/next/typescript/src/components/modals/Modal.tsx +67 -21
  68. package/templates/layers/next/typescript/src/components/ui/Button.tsx +1 -0
  69. package/templates/layers/next/typescript/src/components/ui/Header.tsx +2 -2
  70. package/templates/layers/next/typescript/src/components/ui/Input.tsx +40 -60
  71. package/templates/layers/next/{javascript/src/components/ui/sidebar.jsx → typescript/src/components/ui/Sidebar.tsx} +77 -44
  72. package/templates/layers/next/typescript/src/components/ui/SidebarHeader.tsx +16 -10
  73. package/templates/layers/next/typescript/src/config/appConfig.ts +4 -4
  74. package/templates/layers/next/typescript/src/hooks/usePwaInstall.ts +10 -4
  75. package/templates/layers/next/typescript/src/hooks/useWindowSize.ts +2 -3
  76. package/templates/layers/next/typescript/src/services/authService.ts +1 -1
  77. package/templates/layers/next/typescript/src/store/useAuthStore.ts +24 -9
  78. package/templates/layers/next/typescript/src/store/useUiStore.ts +14 -4
  79. package/templates/layers/node/javascript/.env.example +3 -1
  80. package/templates/layers/node/javascript/package.json +12 -3
  81. package/templates/layers/node/javascript/src/app.js +2 -1
  82. package/templates/layers/node/javascript/src/controllers/auth.controller.js +106 -168
  83. package/templates/layers/node/javascript/src/controllers/push.controller.js +51 -58
  84. package/templates/layers/node/javascript/src/controllers/upload.controller.js +12 -19
  85. package/templates/layers/node/javascript/src/middleware/auth.middleware.js +5 -11
  86. package/templates/layers/node/javascript/src/middleware/errorHandler.js +6 -4
  87. package/templates/layers/node/javascript/src/routes/auth.route.js +2 -0
  88. package/templates/layers/node/javascript/src/services/auth.service.js +159 -164
  89. package/templates/layers/node/javascript/src/utils/ApiError.js +20 -0
  90. package/templates/layers/node/javascript/src/utils/SuccessResponse.js +15 -0
  91. package/templates/layers/node/javascript/src/utils/apiResponse.js +4 -0
  92. package/templates/layers/node/javascript/src/utils/asyncHandler.js +5 -0
  93. package/templates/layers/node/typescript/.env.example +3 -1
  94. package/templates/layers/node/typescript/.eslintrc.cjs +28 -0
  95. package/templates/layers/node/typescript/package-lock.json +2 -2
  96. package/templates/layers/node/typescript/package.json +17 -3
  97. package/templates/layers/node/typescript/src/app.ts +3 -2
  98. package/templates/layers/node/typescript/src/config/db.ts +3 -2
  99. package/templates/layers/node/typescript/src/config/socket.ts +5 -4
  100. package/templates/layers/node/typescript/src/controllers/auth.controller.ts +104 -132
  101. package/templates/layers/node/typescript/src/controllers/push.controller.ts +52 -59
  102. package/templates/layers/node/typescript/src/controllers/upload.controller.ts +12 -19
  103. package/templates/layers/node/typescript/src/middleware/auth.middleware.ts +13 -7
  104. package/templates/layers/node/typescript/src/middleware/errorHandler.ts +18 -5
  105. package/templates/layers/node/typescript/src/middleware/rateLimiter.ts +2 -2
  106. package/templates/layers/node/typescript/src/routes/auth.route.ts +2 -0
  107. package/templates/layers/node/typescript/src/services/auth.service.ts +86 -43
  108. package/templates/layers/node/typescript/src/types/express.d.ts +5 -3
  109. package/templates/layers/node/typescript/src/utils/ApiError.ts +25 -0
  110. package/templates/layers/node/typescript/src/utils/SuccessResponse.ts +17 -0
  111. package/templates/layers/node/typescript/src/utils/apiResponse.ts +4 -0
  112. package/templates/layers/node/typescript/src/utils/asyncHandler.ts +13 -0
  113. package/templates/layers/node/typescript/src/utils/cloudinaryUpload.ts +18 -7
  114. package/templates/layers/node/typescript/src/utils/expoNotification.ts +1 -1
  115. package/templates/layers/node/typescript/src/utils/genOtpToken.ts +7 -1
  116. package/templates/layers/node/typescript/src/utils/jwt.ts +8 -2
  117. package/templates/layers/node/typescript/src/utils/logger.ts +2 -1
  118. package/templates/layers/node/typescript/src/utils/pushHelper.ts +13 -9
  119. package/templates/layers/node-prisma/javascript/.env.example +3 -1
  120. package/templates/layers/node-prisma/javascript/package.json +11 -2
  121. package/templates/layers/node-prisma/javascript/src/app.js +2 -1
  122. package/templates/layers/node-prisma/javascript/src/controllers/auth.controller.js +90 -135
  123. package/templates/layers/node-prisma/javascript/src/controllers/push.controller.js +64 -76
  124. package/templates/layers/node-prisma/javascript/src/controllers/upload.controller.js +12 -19
  125. package/templates/layers/node-prisma/javascript/src/middleware/auth.middleware.js +5 -4
  126. package/templates/layers/node-prisma/javascript/src/middleware/errorHandler.js +6 -4
  127. package/templates/layers/node-prisma/javascript/src/routes/auth.route.js +2 -0
  128. package/templates/layers/node-prisma/javascript/src/services/auth.service.js +145 -122
  129. package/templates/layers/node-prisma/javascript/src/utils/ApiError.js +20 -0
  130. package/templates/layers/node-prisma/javascript/src/utils/SuccessResponse.js +15 -0
  131. package/templates/layers/node-prisma/javascript/src/utils/apiResponse.js +4 -0
  132. package/templates/layers/node-prisma/javascript/src/utils/asyncHandler.js +5 -0
  133. package/templates/layers/node-prisma/typescript/.env.example +3 -1
  134. package/templates/layers/node-prisma/typescript/.eslintrc.cjs +28 -0
  135. package/templates/layers/node-prisma/typescript/package.json +19 -5
  136. package/templates/layers/node-prisma/typescript/src/app.ts +3 -2
  137. package/templates/layers/node-prisma/typescript/src/config/prisma.ts +3 -2
  138. package/templates/layers/node-prisma/typescript/src/config/socket.ts +5 -4
  139. package/templates/layers/node-prisma/typescript/src/controllers/auth.controller.ts +89 -105
  140. package/templates/layers/node-prisma/typescript/src/controllers/push.controller.ts +67 -83
  141. package/templates/layers/node-prisma/typescript/src/controllers/upload.controller.ts +12 -19
  142. package/templates/layers/node-prisma/typescript/src/middleware/auth.middleware.ts +9 -13
  143. package/templates/layers/node-prisma/typescript/src/middleware/errorHandler.ts +18 -5
  144. package/templates/layers/node-prisma/typescript/src/middleware/rateLimiter.ts +2 -2
  145. package/templates/layers/node-prisma/typescript/src/routes/auth.route.ts +2 -0
  146. package/templates/layers/node-prisma/typescript/src/services/auth.service.ts +83 -31
  147. package/templates/layers/node-prisma/typescript/src/types/express.d.ts +5 -3
  148. package/templates/layers/node-prisma/typescript/src/utils/ApiError.ts +25 -0
  149. package/templates/layers/node-prisma/typescript/src/utils/SuccessResponse.ts +17 -0
  150. package/templates/layers/node-prisma/typescript/src/utils/apiResponse.ts +4 -0
  151. package/templates/layers/node-prisma/typescript/src/utils/asyncHandler.ts +13 -0
  152. package/templates/layers/node-prisma/typescript/src/utils/cloudinaryUpload.ts +18 -7
  153. package/templates/layers/node-prisma/typescript/src/utils/genOtpToken.ts +7 -1
  154. package/templates/layers/node-prisma/typescript/src/utils/jwt.ts +8 -2
  155. package/templates/layers/node-prisma/typescript/src/utils/logger.ts +2 -1
  156. package/templates/layers/node-prisma/typescript/src/utils/pushHelper.ts +10 -6
  157. package/templates/layers/prisma/javascript/package.json +8 -0
  158. package/templates/layers/prisma/typescript/package.json +14 -1
  159. package/templates/layers/prisma/typescript/prisma/schema.prisma +35 -10
  160. package/templates/layers/prisma/typescript/src/config/db.ts +3 -2
  161. package/templates/layers/react/javascript/package.json +6 -0
  162. package/templates/layers/react/javascript/src/components/common/Breadcrumbs.jsx +62 -58
  163. package/templates/layers/react/javascript/src/components/common/Pagination.jsx +164 -76
  164. package/templates/layers/react/javascript/src/components/common/SidebarModal.jsx +179 -0
  165. package/templates/layers/react/javascript/src/components/common/StatsCard.jsx +167 -0
  166. package/templates/layers/react/javascript/src/components/common/Table.jsx +248 -132
  167. package/templates/layers/react/javascript/src/components/common/Tabs.jsx +164 -112
  168. package/templates/layers/react/javascript/src/components/common/ToggleSwitch.jsx +3 -3
  169. package/templates/layers/react/javascript/src/components/layout/SidebarLayout.jsx +4 -12
  170. package/templates/layers/react/javascript/src/components/modals/Modal.jsx +53 -18
  171. package/templates/layers/react/javascript/src/components/ui/Input.jsx +49 -0
  172. package/templates/layers/react/javascript/src/components/ui/Sidebar.jsx +215 -0
  173. package/templates/layers/react/javascript/src/components/ui/SidebarHeader.jsx +25 -30
  174. package/templates/layers/react/javascript/src/config/appConfig.js +3 -3
  175. package/templates/layers/react/javascript/src/hooks/useWindowSize.js +2 -2
  176. package/templates/layers/react/typescript/.eslintrc.cjs +20 -0
  177. package/templates/layers/react/typescript/package.json +11 -2
  178. package/templates/layers/react/typescript/src/components/common/Breadcrumbs.tsx +32 -6
  179. package/templates/layers/react/typescript/src/components/common/Pagination.tsx +151 -57
  180. package/templates/layers/react/typescript/src/components/common/SidebarModal.tsx +199 -0
  181. package/templates/layers/react/typescript/src/components/common/StatsCard.tsx +231 -0
  182. package/templates/layers/react/typescript/src/components/common/Table.tsx +201 -38
  183. package/templates/layers/react/typescript/src/components/common/Tabs.tsx +56 -12
  184. package/templates/layers/react/typescript/src/components/common/ToggleSwitch.tsx +15 -3
  185. package/templates/layers/react/typescript/src/components/layout/SidebarLayout.tsx +3 -6
  186. package/templates/layers/react/typescript/src/components/modals/Modal.tsx +151 -0
  187. package/templates/layers/react/typescript/src/components/ui/Input.tsx +58 -0
  188. package/templates/layers/react/typescript/src/components/ui/Sidebar.tsx +116 -53
  189. package/templates/layers/react/typescript/src/components/ui/SidebarHeader.tsx +5 -4
  190. package/templates/layers/react/typescript/src/config/appConfig.ts +3 -3
  191. package/templates/layers/react/typescript/src/hooks/useWindowSize.ts +2 -3
  192. package/templates/layers/react/typescript/src/main.tsx +11 -11
  193. package/templates/layers/react/typescript/src/services/authService.ts +1 -1
  194. package/templates/layers/react/typescript/src/store/useAuthStore.ts +24 -9
  195. package/templates/layers/react-native/base/app.json +9 -22
  196. package/templates/layers/react-native/base/eslint.config.js +5 -1
  197. package/templates/layers/react-native/base/package.json +11 -1
  198. package/templates/layers/react-native/base/src/app/(auth)/edit-profile.tsx +7 -7
  199. package/templates/layers/react-native/base/src/app/(auth)/login.tsx +31 -7
  200. package/templates/layers/react-native/base/src/app/(tabs)/_layout.tsx +3 -3
  201. package/templates/layers/react-native/base/src/app/(tabs)/index.tsx +6 -5
  202. package/templates/layers/react-native/base/src/app/_layout.tsx +3 -3
  203. package/templates/layers/react-native/base/src/app/doc-viewer.tsx +3 -3
  204. package/templates/layers/react-native/base/src/components/common/ConfirmationToast.tsx +58 -40
  205. package/templates/layers/react-native/base/src/components/common/GoogleAuthButton.tsx +144 -0
  206. package/templates/layers/react-native/base/src/components/common/LocationLoader.tsx +64 -9
  207. package/templates/layers/react-native/base/src/components/common/Typography.tsx +54 -19
  208. package/templates/layers/react-native/base/src/components/ui/ClassicTabBar.tsx +15 -12
  209. package/templates/layers/react-native/base/src/components/ui/CustomTabBar.tsx +84 -90
  210. package/templates/layers/react-native/base/src/components/ui/Drawer.tsx +344 -0
  211. package/templates/layers/react-native/base/src/components/ui/Sidebar.tsx +4 -4
  212. package/templates/layers/react-native/base/src/components/ui/buttons/Button.tsx +29 -6
  213. package/templates/layers/react-native/base/src/components/ui/data-display/Accordion.tsx +2 -2
  214. package/templates/layers/react-native/base/src/components/ui/data-display/Badge.tsx +1 -2
  215. package/templates/layers/react-native/base/src/components/ui/data-display/Image.tsx +3 -3
  216. package/templates/layers/react-native/base/src/components/ui/data-display/SwipeableRow.tsx +28 -7
  217. package/templates/layers/react-native/base/src/components/ui/feedback/GestureWrapper.tsx +11 -4
  218. package/templates/layers/react-native/base/src/components/ui/inputs/DatePicker.tsx +3 -3
  219. package/templates/layers/react-native/base/src/components/ui/inputs/ImagePickerModal.tsx +45 -19
  220. package/templates/layers/react-native/base/src/components/ui/inputs/Input.tsx +28 -9
  221. package/templates/layers/react-native/base/src/components/ui/inputs/SearchablePicker.tsx +199 -0
  222. package/templates/layers/react-native/base/src/components/ui/inputs/Switch.tsx +7 -7
  223. package/templates/layers/react-native/base/src/components/ui/inputs/WebLocationPicker.tsx +146 -72
  224. package/templates/layers/react-native/base/src/config/api.ts +5 -5
  225. package/templates/layers/react-native/base/src/config/appConfig.ts +1 -1
  226. package/templates/layers/react-native/base/src/services/auth.service.ts +3 -1
  227. package/templates/layers/react-native/base/src/services/permission.service.ts +0 -2
  228. package/templates/layers/react-native/base/src/services/socket.service.ts +0 -7
  229. package/templates/layers/react-native/base/src/store/useAuthStore.ts +61 -16
  230. package/templates/layers/react-native/base/src/store/useNotificationStore.ts +36 -42
  231. package/templates/layers/react-native/base/src/types/images.d.ts +7 -5
  232. package/templates/layers/react-native/base/src/utils/fileDownload.ts +206 -0
  233. package/templates/layers/react-native/base/src/utils/storage.ts +1 -1
  234. package/templates/presets/electron/preset.json +9 -0
  235. package/templates/presets/electron-ts/preset.json +9 -0
  236. package/templates/presets/production-fullstack/overrides/client/package.json +9 -0
  237. package/templates/presets/production-fullstack/overrides/mobile/app.json +2 -15
  238. package/templates/presets/production-fullstack/overrides/mobile/package.json +11 -1
  239. package/templates/presets/production-fullstack/overrides/mobile/src/app/_layout.tsx +3 -3
  240. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/Drawer.tsx +344 -0
  241. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/DatePicker.tsx +3 -3
  242. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/inputs/ImagePickerModal.tsx +3 -3
  243. package/templates/presets/production-fullstack/overrides/server/package.json +11 -2
  244. package/templates/layers/react/javascript/src/components/ui/sidebar.jsx +0 -169
  245. package/templates/layers/react-native/base/src/components/ui/BottomModal.tsx +0 -176
  246. package/templates/presets/production-fullstack/overrides/mobile/src/components/ui/BottomModal.tsx +0 -159
  247. /package/templates/layers/react-native/base/assets/images/logo/{logoWithBg.png → icon.png} +0 -0
@@ -2,13 +2,17 @@ import React, { useState, useCallback } from "react";
2
2
  import { View } from "react-native";
3
3
  import { useAuthStore } from "../../store/useAuthStore";
4
4
  import { Txt } from "../../components/common/Typography";
5
- import { Redirect, router, useFocusEffect } from "expo-router";
5
+ import { router, useFocusEffect } from "expo-router";
6
6
  import ScrollContainer from "../../components/ui/layout/ScrollContainer";
7
7
  import Input from "../../components/ui/inputs/Input";
8
8
  import Button from "../../components/ui/buttons/Button";
9
9
  import Tabs from "../../components/ui/navigation/Tabs";
10
10
  import Image from "@/components/ui/data-display/Image";
11
11
  import logo from "../../../assets/images/logo/logo.png";
12
+ import GoogleAuthButton from "../../components/common/GoogleAuthButton";
13
+ import { ActivityIndicator } from "react-native-paper";
14
+ import { useColorScheme } from "nativewind";
15
+ import { Colors } from "@/constants/Colors";
12
16
 
13
17
  export default function LoginScreen() {
14
18
  const {
@@ -22,6 +26,9 @@ export default function LoginScreen() {
22
26
  clearError,
23
27
  demoLogin,
24
28
  } = useAuthStore();
29
+ const { colorScheme } = useColorScheme();
30
+ const colors = Colors[colorScheme ?? "light"];
31
+ const [isNavigating, setIsNavigating] = useState(false);
25
32
 
26
33
  useFocusEffect(
27
34
  useCallback(() => {
@@ -55,13 +62,13 @@ export default function LoginScreen() {
55
62
  };
56
63
 
57
64
  const handleSubmit = async () => {
58
- let ok;
65
+ let ok = false;
59
66
  if (mode === "login") {
60
67
  ok = await login(form.email, form.password);
61
68
  } else {
62
69
  if (!otpSent) {
63
- ok = await sendOtp(form.email);
64
- if (ok) {
70
+ const sent = await sendOtp(form.email);
71
+ if (sent) {
65
72
  setOtpSent(true);
66
73
  setTimer(60);
67
74
  }
@@ -69,10 +76,17 @@ export default function LoginScreen() {
69
76
  ok = await signup(form.name, form.email, form.password, form.otp);
70
77
  }
71
78
  }
79
+ if (ok && (mode === "login" || otpSent)) {
80
+ setIsNavigating(true);
81
+ }
72
82
  };
73
83
 
74
- if (!isCheckingAuth && user) {
75
- return <Redirect href="/(tabs)" />;
84
+ if (isNavigating || (!isCheckingAuth && user)) {
85
+ return (
86
+ <View className="flex-1 bg-base-100 items-center justify-center">
87
+ <ActivityIndicator size="large" color={colors.primary} />
88
+ </View>
89
+ );
76
90
  }
77
91
 
78
92
  return (
@@ -204,7 +218,10 @@ export default function LoginScreen() {
204
218
  <View className="mt-2">
205
219
  <Button
206
220
  label="Demo Login"
207
- onPress={() => demoLogin()}
221
+ onPress={async () => {
222
+ await demoLogin();
223
+ setIsNavigating(true);
224
+ }}
208
225
  isLoading={loading}
209
226
  variant="outline"
210
227
  isFullWidth
@@ -212,6 +229,13 @@ export default function LoginScreen() {
212
229
  </View>
213
230
  )}
214
231
 
232
+ <GoogleAuthButton
233
+ isLogin={mode === "login"}
234
+ onSuccess={() => {
235
+ setIsNavigating(true);
236
+ }}
237
+ />
238
+
215
239
  {mode === "signup" && otpSent && (
216
240
  <View className="mt-2">
217
241
  <Button
@@ -1,4 +1,4 @@
1
- import { Tabs, Redirect } from "expo-router";
1
+ import { Tabs } from "expo-router";
2
2
  import { useColorScheme } from "nativewind";
3
3
  import { Colors } from "../../constants/Colors";
4
4
  import CustomTabBar from "../../components/ui/CustomTabBar";
@@ -10,7 +10,7 @@ const TabLayout = () => {
10
10
  const { user, isCheckingAuth } = useAuthStore();
11
11
 
12
12
  if (!isCheckingAuth && !user) {
13
- return <Redirect href="/login" />;
13
+ return null;
14
14
  }
15
15
 
16
16
  return (
@@ -19,7 +19,7 @@ const TabLayout = () => {
19
19
  <CustomTabBar
20
20
  {...props}
21
21
  showCenterButton={false}
22
- onCenterButtonPress={() => console.log("Create button pressed!")}
22
+ onCenterButtonPress={() => {}}
23
23
  />
24
24
  )}
25
25
  screenOptions={{
@@ -38,7 +38,7 @@ import CircularProgress from "@/components/ui/feedback/CircularProgress";
38
38
  import Skeleton from "@/components/ui/feedback/Skeleton";
39
39
  import { GestureWrapper } from "@/components/ui/feedback/GestureWrapper";
40
40
 
41
- import BottomModal from "@/components/ui/BottomModal";
41
+ import Drawer from "@/components/ui/Drawer";
42
42
  import Tabs from "@/components/ui/navigation/Tabs";
43
43
  import { useColorScheme } from "nativewind";
44
44
  import { Colors } from "@/constants/Colors";
@@ -424,11 +424,12 @@ const Index = () => {
424
424
  <FloatingActionButton icon="add" onPress={() => setIsModalOpen(true)} />
425
425
  </View>
426
426
 
427
- {/* Interactive Bottom Modal */}
428
- <BottomModal
427
+ {/* Interactive Drawer */}
428
+ <Drawer
429
429
  isOpen={isModalOpen}
430
430
  onClose={() => setIsModalOpen(false)}
431
- heightPercent={0.45}
431
+ position="bottom"
432
+ sizePercent={0.45}
432
433
  >
433
434
  <VStack spacing={20} className="px-4 py-2">
434
435
  <View className="h-16 w-16 bg-primary/10 rounded-full items-center justify-center self-center mb-2">
@@ -456,7 +457,7 @@ const Index = () => {
456
457
  onPress={() => setIsModalOpen(false)}
457
458
  />
458
459
  </VStack>
459
- </BottomModal>
460
+ </Drawer>
460
461
  </View>
461
462
  );
462
463
  };
@@ -63,8 +63,8 @@ export default function RootLayout() {
63
63
  if (!user && !inAuthGroup) {
64
64
  // Redirect to the auth group
65
65
  router.replace("/(auth)/login");
66
- } else if (user && inAuthGroup) {
67
- // Redirect away from auth
66
+ } else if (user && (inAuthGroup || !segments[0])) {
67
+ // Redirect away from auth or root to main app tabs
68
68
  router.replace("/(tabs)");
69
69
  }
70
70
  }, [user, isCheckingAuth, segments]);
@@ -99,8 +99,8 @@ export default function RootLayout() {
99
99
  />
100
100
  </Stack>
101
101
  </BiometricLock>
102
- <Toast />
103
102
  </PaperProvider>
103
+ <Toast />
104
104
  </GestureHandlerRootView>
105
105
  );
106
106
  }
@@ -162,9 +162,9 @@ export default function DocViewerScreen() {
162
162
  onPageChanged={(page) => {
163
163
  setCurrentPage(page);
164
164
  }}
165
- onError={(error: any) => {
166
-
167
- if (error?.message?.toLowerCase().includes('password')) {
165
+ onError={(error: unknown) => {
166
+ const err = error as { message?: string };
167
+ if (err?.message?.toLowerCase().includes('password')) {
168
168
  setIsPasswordRequired(true);
169
169
  setErrorMsg('Incorrect password. Please try again.');
170
170
  }
@@ -1,17 +1,33 @@
1
1
  import { View, TouchableOpacity } from "react-native";
2
- import React from "react";
2
+
3
3
  import { Txt } from "./Typography";
4
4
 
5
5
  import { useColorScheme } from "nativewind";
6
6
  import { Colors } from "../../constants/Colors";
7
+ import { useTranslation } from "react-i18next";
8
+
9
+ import { Portal } from "react-native-paper";
10
+
11
+ export interface ConfirmationToastProps {
12
+ name?: string;
13
+ message: string;
14
+ fun: () => void;
15
+ setShow: (show: boolean) => void;
16
+ cancleText?: string;
17
+ confirmText?: string;
18
+ }
7
19
 
8
20
  export default function ConfirmationToast({
9
21
  name,
10
22
  message,
11
23
  fun,
12
- icon,
13
24
  setShow,
14
- }) {
25
+ cancleText,
26
+ confirmText,
27
+ }: ConfirmationToastProps) {
28
+ const { t } = useTranslation();
29
+ const cText = cancleText ?? t("common.cancel");
30
+ const confText = confirmText ?? t("common.confirm");
15
31
  const { colorScheme } = useColorScheme();
16
32
  const colors = Colors[colorScheme ?? "light"];
17
33
 
@@ -21,47 +37,49 @@ export default function ConfirmationToast({
21
37
  };
22
38
 
23
39
  return (
24
- <View className="absolute top-[50%] left-[50%] -translate-x-[50%] -translate-y-[50%] w-[90%]">
25
- <View
26
- className="my-4 pt-8 bg-base-100"
27
- style={{
28
- borderRadius: 20,
29
- shadowColor: "#000",
30
- shadowOffset: {
31
- width: 0,
32
- height: 4,
33
- },
34
- shadowOpacity: 0.1,
35
- shadowRadius: 8,
36
- elevation: 8,
37
- }}
38
- >
39
- <View className="justify-center items-center px-8">
40
- <Txt variant="h1">{name}</Txt>
41
- <Txt variant="body" className="mt-4" style={{ textAlign: "center" }}>
42
- {message}
43
- </Txt>
44
- </View>
40
+ <Portal>
41
+ <View className="absolute inset-0 justify-center items-center bg-black/40 z-50">
45
42
  <View
46
- className="flex-row mt-8"
47
- style={{ borderTopWidth: 1, borderTopColor: colors.base300 }}
43
+ className="w-[90%] pt-8 bg-base-100"
44
+ style={{
45
+ borderRadius: 20,
46
+ shadowColor: "#000",
47
+ shadowOffset: {
48
+ width: 0,
49
+ height: 4,
50
+ },
51
+ shadowOpacity: 0.1,
52
+ shadowRadius: 8,
53
+ elevation: 8,
54
+ }}
48
55
  >
49
- <TouchableOpacity
50
- className="w-[50%] justify-center items-center h-20"
51
- style={{ borderRightWidth: 1, borderRightColor: colors.base300 }}
52
- onPress={() => setShow(false)}
53
- >
54
- <Txt variant="mid">Cancle</Txt>
55
- </TouchableOpacity>
56
- <TouchableOpacity
57
- className="w-[50%] justify-center items-center"
58
- style={{ borderLeftWidth: 1, borderLeftColor: colors.base300 }}
59
- onPress={ok}
56
+ <View className="justify-center items-center px-8">
57
+ <Txt variant="xl">{name}</Txt>
58
+ <Txt variant="sm" className="mt-4" style={{ textAlign: "center" }}>
59
+ {message}
60
+ </Txt>
61
+ </View>
62
+ <View
63
+ className="flex-row mt-8"
64
+ style={{ borderTopWidth: 1, borderTopColor: colors.base300 }}
60
65
  >
61
- <Txt variant="mid">Ok</Txt>
62
- </TouchableOpacity>
66
+ <TouchableOpacity
67
+ className="w-[50%] justify-center items-center h-20"
68
+ style={{ borderRightWidth: 1, borderRightColor: colors.base300 }}
69
+ onPress={() => setShow(false)}
70
+ >
71
+ <Txt variant="sm">{cText}</Txt>
72
+ </TouchableOpacity>
73
+ <TouchableOpacity
74
+ className="w-[50%] justify-center items-center"
75
+ style={{ borderLeftWidth: 1, borderLeftColor: colors.base300 }}
76
+ onPress={ok}
77
+ >
78
+ <Txt variant="sm">{confText}</Txt>
79
+ </TouchableOpacity>
80
+ </View>
63
81
  </View>
64
82
  </View>
65
- </View>
83
+ </Portal>
66
84
  );
67
85
  }
@@ -0,0 +1,144 @@
1
+ import { useEffect, useState } from "react";
2
+ import { TouchableOpacity, View, ActivityIndicator } from "react-native";
3
+ import Constants from "expo-constants";
4
+ import { useColorScheme } from "nativewind";
5
+ import { Colors } from "../../../constants/Colors";
6
+ import { Txt } from "./Typography";
7
+ import { useAuthStore } from "../../../store/useAuthStore";
8
+ import { toast } from "../../../utils/toast";
9
+ import { Ionicons } from "@expo/vector-icons";
10
+
11
+ const isExpoGo = Constants.appOwnership === "expo";
12
+
13
+ interface GoogleSigninType {
14
+ configure: (options: Record<string, unknown>) => void;
15
+ hasPlayServices: (options: { showPlayServicesUpdateDialog: boolean }) => Promise<boolean>;
16
+ signIn: () => Promise<{ data?: { idToken?: string }; idToken?: string }>;
17
+ }
18
+
19
+ interface StatusCodesType {
20
+ SIGN_IN_CANCELLED: string;
21
+ IN_PROGRESS: string;
22
+ PLAY_SERVICES_NOT_AVAILABLE: string;
23
+ }
24
+
25
+ let GoogleSignin: GoogleSigninType | undefined;
26
+ let statusCodes: StatusCodesType | undefined;
27
+
28
+ if (!isExpoGo) {
29
+ try {
30
+ const googleModule = require("@react-native-google-signin/google-signin");
31
+ GoogleSignin = googleModule.GoogleSignin;
32
+ statusCodes = googleModule.statusCodes;
33
+ } catch {
34
+ // Module not found or not supported in current environment
35
+ }
36
+ }
37
+
38
+ interface GoogleAuthButtonProps {
39
+ onSuccess?: () => void;
40
+ label?: string;
41
+ isLogin?: boolean;
42
+ }
43
+
44
+ export default function GoogleAuthButton({
45
+ onSuccess,
46
+ label,
47
+ isLogin = true,
48
+ }: GoogleAuthButtonProps) {
49
+ const { colorScheme } = useColorScheme();
50
+ const colors = Colors[colorScheme ?? "light"];
51
+ const { googleLogin } = useAuthStore();
52
+ const [loading, setLoading] = useState(false);
53
+
54
+ useEffect(() => {
55
+ if (!isExpoGo && GoogleSignin) {
56
+ GoogleSignin.configure({
57
+ webClientId: process.env.EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID || "",
58
+ iosClientId: process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID || "",
59
+ });
60
+ }
61
+ }, []);
62
+
63
+ const handlePress = async () => {
64
+ if (isExpoGo) {
65
+ toast.info(
66
+ "Expo Go",
67
+ "Google Sign-In is not supported in Expo Go. Please use a custom dev client."
68
+ );
69
+ return;
70
+ }
71
+
72
+ if (!GoogleSignin) {
73
+ toast.error("Error", "Google Sign-In module is not loaded.");
74
+ return;
75
+ }
76
+
77
+ try {
78
+ setLoading(true);
79
+ await GoogleSignin.hasPlayServices();
80
+
81
+ // Force account selection every time
82
+ try {
83
+ await GoogleSignin.signOut();
84
+ } catch {
85
+ // Ignore if already signed out
86
+ }
87
+
88
+ const userInfo = await GoogleSignin.signIn();
89
+ const idToken = userInfo.data?.idToken;
90
+
91
+ if (!idToken) {
92
+ throw new Error("No ID token returned from Google");
93
+ }
94
+
95
+ const ok = await googleLogin(idToken);
96
+ if (ok) {
97
+ const currentUser = useAuthStore.getState().user;
98
+ toast.success("Success", `Welcome back, ${currentUser?.name || "User"}`);
99
+ onSuccess?.();
100
+ } else {
101
+ toast.error("Error", "Google authentication failed");
102
+ }
103
+ } catch (error: unknown) {
104
+ const err = error as { code?: string; message?: string };
105
+ if (err.code === statusCodes?.SIGN_IN_CANCELLED) {
106
+ // user cancelled the login flow
107
+ } else if (err.code === statusCodes?.IN_PROGRESS) {
108
+ // operation (e.g. sign in) is in progress already
109
+ } else if (err.code === statusCodes?.PLAY_SERVICES_NOT_AVAILABLE) {
110
+ // play services not available or outdated
111
+ toast.error("Error", "Google Play Services not available");
112
+ } else {
113
+ // some other error happened
114
+ toast.error("Error", err.message || "An unexpected error occurred");
115
+ }
116
+ } finally {
117
+ setLoading(false);
118
+ }
119
+ };
120
+
121
+ return (
122
+ <TouchableOpacity
123
+ activeOpacity={0.8}
124
+ onPress={handlePress}
125
+ disabled={loading}
126
+ className="w-full flex-row items-center justify-center py-4 rounded-xl mt-4 border"
127
+ style={{
128
+ backgroundColor: colors.base100,
129
+ borderColor: colors.base300,
130
+ }}
131
+ >
132
+ {loading ? (
133
+ <ActivityIndicator color={colors.primary} />
134
+ ) : (
135
+ <View className="flex-row items-center justify-center gap-2">
136
+ <Ionicons name="logo-google" size={20} color={colors.baseContent} />
137
+ <Txt className="font-semibold text-base text-base-content">
138
+ {label || (isLogin ? "Continue with Google" : "Sign up with Google")}
139
+ </Txt>
140
+ </View>
141
+ )}
142
+ </TouchableOpacity>
143
+ );
144
+ }
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, ReactElement, useState } from "react";
2
- import { View, Dimensions, StyleSheet } from "react-native";
2
+ import { View, Dimensions, StyleSheet, DimensionValue } from "react-native";
3
3
  import { Ionicons } from "@expo/vector-icons";
4
4
  import { Txt } from "./Typography";
5
5
  import { useColorScheme } from "nativewind";
@@ -49,21 +49,41 @@ const DARK_MAP = {
49
49
  };
50
50
 
51
51
  // ─── Map Primitives ───
52
- const Water = ({ top, left, w, h, rx = 8, dark }: any) => (
52
+ interface MapShapeProps {
53
+ top: number;
54
+ left: number;
55
+ w: number;
56
+ h: number;
57
+ rx?: number;
58
+ dark?: boolean;
59
+ }
60
+
61
+ const Water = ({ top, left, w, h, rx = 8, dark }: MapShapeProps) => (
53
62
  <View style={{
54
63
  position: "absolute", top, left, width: w, height: h,
55
64
  backgroundColor: dark ? DARK_MAP.water : LIGHT_MAP.water,
56
65
  borderRadius: rx, opacity: 0.9,
57
66
  }} />
58
67
  );
59
- const Park = ({ top, left, w, h, rx = 6, dark }: any) => (
68
+
69
+ const Park = ({ top, left, w, h, rx = 6, dark }: MapShapeProps) => (
60
70
  <View style={{
61
71
  position: "absolute", top, left, width: w, height: h,
62
72
  backgroundColor: dark ? DARK_MAP.park : LIGHT_MAP.park,
63
73
  borderRadius: rx, opacity: dark ? 0.6 : 0.55,
64
74
  }} />
65
75
  );
66
- const Block = ({ top, left, w, h, shade = 0, dark }: any) => {
76
+
77
+ interface BlockProps {
78
+ top: number;
79
+ left: number;
80
+ w: number;
81
+ h: number;
82
+ shade?: number;
83
+ dark?: boolean;
84
+ }
85
+
86
+ const Block = ({ top, left, w, h, shade = 0, dark }: BlockProps) => {
67
87
  const palette = dark ? DARK_MAP.block : LIGHT_MAP.block;
68
88
  return (
69
89
  <View style={{
@@ -73,7 +93,17 @@ const Block = ({ top, left, w, h, shade = 0, dark }: any) => {
73
93
  }} />
74
94
  );
75
95
  };
76
- const Road = ({ top, left, w, h, major = false, dark }: any) => (
96
+
97
+ interface RoadProps {
98
+ top: number;
99
+ left: number;
100
+ w: number;
101
+ h: number;
102
+ major?: boolean;
103
+ dark?: boolean;
104
+ }
105
+
106
+ const Road = ({ top, left, w, h, major = false, dark }: RoadProps) => (
77
107
  <View style={{
78
108
  position: "absolute", top, left, width: w, height: h,
79
109
  backgroundColor: major ? (dark ? DARK_MAP.road : LIGHT_MAP.road)
@@ -81,7 +111,15 @@ const Road = ({ top, left, w, h, major = false, dark }: any) => (
81
111
  opacity: major ? 0.95 : 0.75,
82
112
  }} />
83
113
  );
84
- const LaneDash = ({ top, left, vertical = false, dark }: any) => (
114
+
115
+ interface LaneDashProps {
116
+ top: number;
117
+ left: number;
118
+ vertical?: boolean;
119
+ dark?: boolean;
120
+ }
121
+
122
+ const LaneDash = ({ top, left, vertical = false, dark }: LaneDashProps) => (
85
123
  <View style={{
86
124
  position: "absolute", top, left,
87
125
  width: vertical ? 2 : 12, height: vertical ? 12 : 2,
@@ -154,7 +192,16 @@ const MapWorld = ({ dark }: { dark: boolean }) => {
154
192
  };
155
193
 
156
194
  // ─── MOVING TRAFFIC DOT ───
157
- const TrafficDot = ({ startX, startY, endX, endY, delay, color }: any) => {
195
+ interface TrafficDotProps {
196
+ startX: number;
197
+ startY: number;
198
+ endX: number;
199
+ endY: number;
200
+ delay: number;
201
+ color: string;
202
+ }
203
+
204
+ const TrafficDot = ({ startX, startY, endX, endY, delay, color }: TrafficDotProps) => {
158
205
  const x = useSharedValue(startX);
159
206
  const y = useSharedValue(startY);
160
207
 
@@ -181,7 +228,15 @@ const TrafficDot = ({ startX, startY, endX, endY, delay, color }: any) => {
181
228
  };
182
229
 
183
230
  // ─── PROPERTY PRICE PIN ───
184
- const PropertyPin = ({ top, left, delay, price, color }: any) => {
231
+ interface PropertyPinProps {
232
+ top: number;
233
+ left: number;
234
+ delay: number;
235
+ price: string;
236
+ color: string;
237
+ }
238
+
239
+ const PropertyPin = ({ top, left, delay, price, color }: PropertyPinProps) => {
185
240
  const scale = useSharedValue(0);
186
241
  const opacity = useSharedValue(0);
187
242
  const bounce = useSharedValue(0);
@@ -328,7 +383,7 @@ const AltitudeBar = ({ primary }: { primary: string }) => {
328
383
  }, []);
329
384
 
330
385
  const barStyle = useAnimatedStyle(() => ({
331
- height: `${prog.value * 100}%` as any,
386
+ height: `${prog.value * 100}%` as DimensionValue,
332
387
  opacity: interpolate(prog.value, [0, 0.1], [0, 1], Extrapolation.CLAMP),
333
388
  }));
334
389
 
@@ -1,5 +1,4 @@
1
- import React from "react";
2
- import { Text, TextProps } from "react-native";
1
+ import { Text, TextProps, TextStyle } from "react-native";
3
2
  export const FontFamily = {
4
3
  regular: "InterRegular",
5
4
  medium: "InterMedium",
@@ -80,30 +79,65 @@ export const Txt = ({
80
79
  const hasColorClass = className.split(" ").some((c) => {
81
80
  if (!c.startsWith("text-")) return false;
82
81
  const val = c.substring(5).split("/")[0]; // handle potential opacity suffix like text-white/80
83
- const isSize = ["xxs", "xs", "sm", "base", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "caption"].includes(val);
84
- return !isSize;
82
+ const nonColors = [
83
+ "xxs",
84
+ "xs",
85
+ "sm",
86
+ "base",
87
+ "md",
88
+ "lg",
89
+ "xl",
90
+ "2xl",
91
+ "3xl",
92
+ "4xl",
93
+ "5xl",
94
+ "6xl",
95
+ "7xl",
96
+ "caption",
97
+ "center",
98
+ "left",
99
+ "right",
100
+ "justify",
101
+ "start",
102
+ "end",
103
+ "wrap",
104
+ "nowrap",
105
+ "balance",
106
+ "pretty",
107
+ "clip",
108
+ "ellipsis",
109
+ "truncate",
110
+ ];
111
+ return !nonColors.includes(val);
85
112
  });
86
- const defaultColorClass = hasColorClass || color
87
- ? ""
88
- : variant === "xs"
89
- ? "text-secondary"
90
- : "text-base-content";
91
-
92
- const customStyles: any = {};
113
+ const defaultColorClass =
114
+ hasColorClass || color
115
+ ? ""
116
+ : variant === "xs" || variant === "caption"
117
+ ? "text-secondary"
118
+ : "text-base-content";
119
+
120
+ const customStyles: TextStyle = {};
93
121
  if (color) customStyles.color = color;
94
122
  if (align) customStyles.textAlign = align;
95
123
 
96
124
  // Intercept font weight classes from Nativewind or weight prop
97
125
  let finalClassName = className;
98
-
99
- const resolvedWeight = weight || (
100
- finalClassName.includes("font-black") || finalClassName.includes("font-extrabold") ? "black" :
101
- finalClassName.includes("font-bold") ? "bold" :
102
- finalClassName.includes("font-semibold") ? "semibold" :
103
- finalClassName.includes("font-medium") ? "medium" : null
104
- );
105
126
 
106
- if (resolvedWeight === "black" || resolvedWeight === "extrabold") {
127
+ const resolvedWeight =
128
+ weight ||
129
+ (finalClassName.includes("font-black") ||
130
+ finalClassName.includes("font-extrabold")
131
+ ? "black"
132
+ : finalClassName.includes("font-bold")
133
+ ? "bold"
134
+ : finalClassName.includes("font-semibold")
135
+ ? "semibold"
136
+ : finalClassName.includes("font-medium")
137
+ ? "medium"
138
+ : null);
139
+
140
+ if (resolvedWeight === "black") {
107
141
  customStyles.fontFamily = FontFamily.extrabold;
108
142
  customStyles.fontWeight = "normal"; // Prevent Android fallback
109
143
  } else if (resolvedWeight === "bold") {
@@ -132,6 +166,7 @@ export const Txt = ({
132
166
  <Text
133
167
  className={`${defaultColorClass} ${finalClassName}`}
134
168
  style={[baseStyle, customStyles, style]}
169
+ textBreakStrategy="simple"
135
170
  {...props}
136
171
  >
137
172
  {children}