@imksh/create 1.0.24 → 1.0.26

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 (415) hide show
  1. package/package.json +1 -1
  2. package/src/commands/create.js +2 -1
  3. package/src/index.js +1 -1
  4. package/src/utils/askTemplate.js +1 -0
  5. package/templates/mern-react-native/client/src/vite-env.d.ts +1 -0
  6. package/templates/mern-react-native/mobile/_gitignore +43 -0
  7. package/templates/mern-react-native/mobile/babel.config.js +1 -0
  8. package/templates/mern-react-native/mobile/drizzle.config.ts +8 -0
  9. package/templates/mern-react-native/mobile/expo-env.d.ts +3 -0
  10. package/templates/mern-react-native/mobile/package.json +8 -1
  11. package/templates/mern-react-native/mobile/src/app/(auth)/_layout.tsx +12 -0
  12. package/templates/mern-react-native/mobile/src/app/(auth)/change-password.tsx +112 -0
  13. package/templates/mern-react-native/mobile/src/app/(auth)/edit-profile.tsx +156 -0
  14. package/templates/mern-react-native/mobile/src/app/(auth)/forgot-password.tsx +191 -0
  15. package/templates/mern-react-native/mobile/src/app/{login.tsx → (auth)/login.tsx} +69 -21
  16. package/templates/mern-react-native/mobile/src/app/(tabs)/dashboard.tsx +2 -2
  17. package/templates/mern-react-native/mobile/src/app/(tabs)/index.tsx +18 -17
  18. package/templates/mern-react-native/mobile/src/app/(tabs)/profile.tsx +23 -60
  19. package/templates/mern-react-native/mobile/src/app/(tabs)/search.tsx +2 -2
  20. package/templates/mern-react-native/mobile/src/app/_layout.tsx +22 -4
  21. package/templates/mern-react-native/mobile/src/components/common/AnimatedHeader.tsx +328 -0
  22. package/templates/mern-react-native/mobile/src/components/common/LocationLoader.tsx +591 -0
  23. package/templates/mern-react-native/mobile/src/components/common/ScreenHeader.tsx +41 -17
  24. package/templates/mern-react-native/mobile/src/components/common/TabHeader.tsx +58 -0
  25. package/templates/mern-react-native/mobile/src/components/common/Typography.tsx +49 -30
  26. package/templates/mern-react-native/mobile/src/components/common/Welcome.tsx +2 -2
  27. package/templates/mern-react-native/mobile/src/components/ui/BottomModal.tsx +31 -20
  28. package/templates/mern-react-native/mobile/src/components/ui/ClassicTabBar.tsx +4 -3
  29. package/templates/mern-react-native/mobile/src/components/ui/CustomTabBar.tsx +108 -71
  30. package/templates/mern-react-native/mobile/src/components/ui/Sidebar.tsx +81 -56
  31. package/templates/mern-react-native/mobile/src/components/ui/buttons/Button.tsx +106 -37
  32. package/templates/mern-react-native/mobile/src/components/ui/buttons/IconButton.tsx +4 -2
  33. package/templates/mern-react-native/mobile/src/components/ui/data-display/Accordion.tsx +3 -2
  34. package/templates/mern-react-native/mobile/src/components/ui/data-display/Avatar.tsx +4 -3
  35. package/templates/mern-react-native/mobile/src/components/ui/data-display/Badge.tsx +45 -17
  36. package/templates/mern-react-native/mobile/src/components/ui/data-display/ImageViewer.tsx +19 -9
  37. package/templates/mern-react-native/mobile/src/components/ui/feedback/CircularProgress.tsx +5 -4
  38. package/templates/mern-react-native/mobile/src/components/ui/feedback/ProgressBar.tsx +4 -3
  39. package/templates/mern-react-native/mobile/src/components/ui/feedback/Skeleton.tsx +3 -0
  40. package/templates/mern-react-native/mobile/src/components/ui/feedback/Spinner.tsx +11 -3
  41. package/templates/mern-react-native/mobile/src/components/ui/inputs/Checkbox.tsx +3 -2
  42. package/templates/mern-react-native/mobile/src/components/ui/inputs/DatePicker.tsx +186 -0
  43. package/templates/mern-react-native/mobile/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
  44. package/templates/mern-react-native/mobile/src/components/ui/inputs/Input.tsx +54 -14
  45. package/templates/mern-react-native/mobile/src/components/ui/inputs/LocationPicker.tsx +211 -0
  46. package/templates/mern-react-native/mobile/src/components/ui/inputs/OTPInput.tsx +32 -9
  47. package/templates/mern-react-native/mobile/src/components/ui/inputs/PasswordInput.tsx +2 -1
  48. package/templates/mern-react-native/mobile/src/components/ui/inputs/Radio.tsx +3 -2
  49. package/templates/mern-react-native/mobile/src/components/ui/inputs/SearchBar.tsx +41 -4
  50. package/templates/mern-react-native/mobile/src/components/ui/inputs/Slider.tsx +4 -3
  51. package/templates/mern-react-native/mobile/src/components/ui/inputs/Switch.tsx +3 -2
  52. package/templates/mern-react-native/mobile/src/components/ui/inputs/TextArea.tsx +2 -1
  53. package/templates/mern-react-native/mobile/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
  54. package/templates/mern-react-native/mobile/src/components/ui/layout/Grid.tsx +52 -10
  55. package/templates/mern-react-native/mobile/src/components/ui/layout/Section.tsx +7 -8
  56. package/templates/mern-react-native/mobile/src/components/ui/navigation/Pagination.tsx +4 -3
  57. package/templates/mern-react-native/mobile/src/components/ui/navigation/ProgressStepper.tsx +6 -5
  58. package/templates/mern-react-native/mobile/src/components/ui/navigation/Tabs.tsx +30 -4
  59. package/templates/mern-react-native/mobile/src/config/api.ts +12 -1
  60. package/templates/mern-react-native/mobile/src/config/sidebar.config.ts +12 -0
  61. package/templates/mern-react-native/mobile/src/config/tabNavigation.ts +1 -1
  62. package/templates/mern-react-native/mobile/src/db/index.ts +9 -0
  63. package/templates/mern-react-native/mobile/src/db/schema.ts +14 -0
  64. package/templates/mern-react-native/mobile/src/hooks/useDebounce.ts +17 -0
  65. package/templates/mern-react-native/mobile/src/services/notification.service.ts +22 -0
  66. package/templates/mern-react-native/mobile/src/services/socket.service.ts +36 -0
  67. package/templates/mern-react-native/mobile/src/store/useAuthStore.ts +122 -27
  68. package/templates/mern-react-native/mobile/src/store/useNotificationStore.ts +178 -0
  69. package/templates/mern-react-native/mobile/src/types/auth.type.ts +14 -0
  70. package/templates/mern-react-native/mobile/tsconfig.json +1 -0
  71. package/templates/mern-ts/client/src/vite-env.d.ts +1 -0
  72. package/templates/next/next.config.mjs +1 -0
  73. package/templates/next/package.json +10 -9
  74. package/templates/next/postcss.config.js +5 -0
  75. package/templates/next/src/app/layout.js +1 -0
  76. package/templates/next/src/app/page.js +1 -1
  77. package/templates/next/src/components/layout/ProtectedRoute.jsx +3 -3
  78. package/templates/next/src/index.css +1 -0
  79. package/templates/next/src/store/useUiStore.js +13 -7
  80. package/templates/next-ts/.env.example +0 -0
  81. package/templates/next-ts/AGENTS.md +37 -0
  82. package/templates/next-ts/CLAUDE.md +1 -0
  83. package/templates/next-ts/_gitignore +0 -24
  84. package/templates/next-ts/next-env.d.ts +3 -1
  85. package/templates/next-ts/next.config.mjs +1 -0
  86. package/templates/next-ts/package.json +13 -12
  87. package/templates/next-ts/postcss.config.js +5 -0
  88. package/templates/next-ts/public/logo.png +0 -0
  89. package/templates/next-ts/src/app/error.tsx +41 -0
  90. package/templates/next-ts/src/app/layout.tsx +2 -1
  91. package/templates/next-ts/src/app/not-found.tsx +5 -0
  92. package/templates/next-ts/src/app/page.tsx +1 -1
  93. package/templates/next-ts/src/components/layout/ProtectedRoute.tsx +3 -3
  94. package/templates/next-ts/src/components/ui/Button.tsx +63 -0
  95. package/templates/next-ts/src/components/ui/Input.tsx +79 -0
  96. package/templates/next-ts/src/index.css +1 -0
  97. package/templates/next-ts/src/store/useUiStore.ts +13 -7
  98. package/templates/next-ts/tsconfig.json +19 -5
  99. package/templates/production-fullstack/client/index.html +14 -0
  100. package/templates/production-fullstack/client/package.json +47 -0
  101. package/templates/production-fullstack/client/public/_redirects +1 -0
  102. package/templates/production-fullstack/client/public/favicon.ico +0 -0
  103. package/templates/production-fullstack/client/public/favicon.svg +1 -0
  104. package/templates/production-fullstack/client/public/logo.png +0 -0
  105. package/templates/production-fullstack/client/public/manifest.json +24 -0
  106. package/templates/production-fullstack/client/public/sw.js +56 -0
  107. package/templates/production-fullstack/client/src/App.tsx +68 -0
  108. package/templates/production-fullstack/client/src/assets/animations/loading.json +1 -0
  109. package/templates/production-fullstack/client/src/assets/data/navigation.ts +29 -0
  110. package/templates/production-fullstack/client/src/assets/images/logo.png +0 -0
  111. package/templates/production-fullstack/client/src/components/layout/ProtectedRoute.tsx +23 -0
  112. package/templates/production-fullstack/client/src/components/layout/PublicLayout.tsx +13 -0
  113. package/templates/production-fullstack/client/src/components/layout/SidebarLayout.tsx +37 -0
  114. package/templates/production-fullstack/client/src/components/shared/Breadcrumbs.tsx +27 -0
  115. package/templates/production-fullstack/client/src/components/shared/LottieIcon.tsx +36 -0
  116. package/templates/production-fullstack/client/src/components/shared/NotFound.tsx +78 -0
  117. package/templates/production-fullstack/client/src/components/shared/PwaInstallPrompt.tsx +72 -0
  118. package/templates/production-fullstack/client/src/components/shared/SEO.tsx +67 -0
  119. package/templates/production-fullstack/client/src/components/shared/Scroll.tsx +25 -0
  120. package/templates/production-fullstack/client/src/components/shared/Unauthorized.tsx +76 -0
  121. package/templates/production-fullstack/client/src/components/shared/skeletons/common/CardSkeleton.tsx +23 -0
  122. package/templates/production-fullstack/client/src/components/shared/skeletons/common/DashboardSkeleton.tsx +19 -0
  123. package/templates/production-fullstack/client/src/components/shared/skeletons/common/ListSkeleton.tsx +24 -0
  124. package/templates/production-fullstack/client/src/components/shared/skeletons/common/PageSkeleton.tsx +26 -0
  125. package/templates/production-fullstack/client/src/components/shared/skeletons/common/ProfileSkeleton.tsx +23 -0
  126. package/templates/production-fullstack/client/src/components/shared/skeletons/common/Skeleton.tsx +18 -0
  127. package/templates/production-fullstack/client/src/components/shared/skeletons/common/TableSkeleton.tsx +33 -0
  128. package/templates/production-fullstack/client/src/components/ui/ConfirmModal.tsx +152 -0
  129. package/templates/production-fullstack/client/src/components/ui/Header.tsx +230 -0
  130. package/templates/production-fullstack/client/src/components/ui/Loading.tsx +19 -0
  131. package/templates/production-fullstack/client/src/components/ui/Modal.tsx +106 -0
  132. package/templates/production-fullstack/client/src/components/ui/SidebarHeader.tsx +34 -0
  133. package/templates/production-fullstack/client/src/components/ui/Table.tsx +118 -0
  134. package/templates/production-fullstack/client/src/components/ui/ToggleSwitch.tsx +38 -0
  135. package/templates/production-fullstack/client/src/components/ui/sidebar.tsx +152 -0
  136. package/templates/production-fullstack/client/src/config/index.ts +44 -0
  137. package/templates/production-fullstack/client/src/constants/navigation.ts +14 -0
  138. package/templates/production-fullstack/client/src/features/auth/api/authService.ts +19 -0
  139. package/templates/production-fullstack/client/src/features/auth/pages/Login.tsx +233 -0
  140. package/templates/production-fullstack/client/src/features/auth/store/useAuthStore.ts +143 -0
  141. package/templates/production-fullstack/client/src/features/core/pages/Home.tsx +150 -0
  142. package/templates/production-fullstack/client/src/features/core/pages/Profile.tsx +9 -0
  143. package/templates/production-fullstack/client/src/hooks/useLenis.ts +28 -0
  144. package/templates/production-fullstack/client/src/hooks/usePwaInstall.ts +45 -0
  145. package/templates/production-fullstack/client/src/hooks/useWindowSize.ts +25 -0
  146. package/templates/production-fullstack/client/src/index.css +158 -0
  147. package/templates/production-fullstack/client/src/lib/axios.ts +22 -0
  148. package/templates/production-fullstack/client/src/lib/dayjs.ts +12 -0
  149. package/templates/production-fullstack/client/src/lib/query-client.ts +11 -0
  150. package/templates/production-fullstack/client/src/lib/socket.ts +6 -0
  151. package/templates/production-fullstack/client/src/main.tsx +28 -0
  152. package/templates/production-fullstack/client/src/store/useUiStore.ts +74 -0
  153. package/templates/production-fullstack/client/src/utils/formatDate.ts +19 -0
  154. package/templates/production-fullstack/client/src/utils/getInitials.ts +10 -0
  155. package/templates/production-fullstack/client/src/vite-env.d.ts +1 -0
  156. package/templates/production-fullstack/client/tsconfig.json +25 -0
  157. package/templates/production-fullstack/client/tsconfig.node.json +10 -0
  158. package/templates/production-fullstack/client/vite.config.ts +8 -0
  159. package/templates/production-fullstack/mobile/LICENSE +21 -0
  160. package/templates/production-fullstack/mobile/app.json +84 -0
  161. package/templates/production-fullstack/mobile/assets/animations/celebrate.json +1 -0
  162. package/templates/production-fullstack/mobile/assets/animations/infinity.json +1 -0
  163. package/templates/production-fullstack/mobile/assets/animations/loading.json +1 -0
  164. package/templates/production-fullstack/mobile/assets/fonts/Inter_Bold.ttf +0 -0
  165. package/templates/production-fullstack/mobile/assets/fonts/Inter_ExtraBold.ttf +0 -0
  166. package/templates/production-fullstack/mobile/assets/fonts/Inter_Medium.ttf +0 -0
  167. package/templates/production-fullstack/mobile/assets/fonts/Inter_Regular.ttf +0 -0
  168. package/templates/production-fullstack/mobile/assets/fonts/Inter_SemiBold.ttf +0 -0
  169. package/templates/production-fullstack/mobile/assets/images/logo/logo.png +0 -0
  170. package/templates/production-fullstack/mobile/assets/images/logo/logo.svg +1 -0
  171. package/templates/production-fullstack/mobile/assets/images/logo/logoWithBg.png +0 -0
  172. package/templates/production-fullstack/mobile/babel.config.js +13 -0
  173. package/templates/production-fullstack/mobile/drizzle.config.ts +8 -0
  174. package/templates/production-fullstack/mobile/eas.json +24 -0
  175. package/templates/production-fullstack/mobile/eslint.config.js +10 -0
  176. package/templates/production-fullstack/mobile/expo-env.d.ts +3 -0
  177. package/templates/production-fullstack/mobile/metro.config.js +6 -0
  178. package/templates/production-fullstack/mobile/nativewind-env.d.ts +3 -0
  179. package/templates/production-fullstack/mobile/package.json +89 -0
  180. package/templates/production-fullstack/mobile/src/app/(auth)/_layout.tsx +12 -0
  181. package/templates/production-fullstack/mobile/src/app/(auth)/change-password.tsx +112 -0
  182. package/templates/production-fullstack/mobile/src/app/(auth)/edit-profile.tsx +160 -0
  183. package/templates/production-fullstack/mobile/src/app/(auth)/forgot-password.tsx +191 -0
  184. package/templates/production-fullstack/mobile/src/app/(auth)/login.tsx +253 -0
  185. package/templates/production-fullstack/mobile/src/app/_layout.tsx +102 -0
  186. package/templates/production-fullstack/mobile/src/app/global.css +82 -0
  187. package/templates/production-fullstack/mobile/src/components/common/AnimatedHeader.tsx +328 -0
  188. package/templates/production-fullstack/mobile/src/components/common/ConfirmationToast.tsx +67 -0
  189. package/templates/production-fullstack/mobile/src/components/common/Loading.tsx +26 -0
  190. package/templates/production-fullstack/mobile/src/components/common/LocationLoader.tsx +591 -0
  191. package/templates/production-fullstack/mobile/src/components/common/ScreenHeader.tsx +68 -0
  192. package/templates/production-fullstack/mobile/src/components/common/TabHeader.tsx +58 -0
  193. package/templates/production-fullstack/mobile/src/components/common/Typography.tsx +113 -0
  194. package/templates/production-fullstack/mobile/src/components/common/Welcome.tsx +55 -0
  195. package/templates/production-fullstack/mobile/src/components/ui/BottomModal.tsx +159 -0
  196. package/templates/production-fullstack/mobile/src/components/ui/ClassicTabBar.tsx +129 -0
  197. package/templates/production-fullstack/mobile/src/components/ui/CustomTabBar.tsx +238 -0
  198. package/templates/production-fullstack/mobile/src/components/ui/Sidebar.tsx +258 -0
  199. package/templates/production-fullstack/mobile/src/components/ui/buttons/Button.tsx +180 -0
  200. package/templates/production-fullstack/mobile/src/components/ui/buttons/ButtonGroup.tsx +32 -0
  201. package/templates/production-fullstack/mobile/src/components/ui/buttons/FloatingActionButton.tsx +72 -0
  202. package/templates/production-fullstack/mobile/src/components/ui/buttons/IconButton.tsx +84 -0
  203. package/templates/production-fullstack/mobile/src/components/ui/data-display/Accordion.tsx +82 -0
  204. package/templates/production-fullstack/mobile/src/components/ui/data-display/Avatar.tsx +47 -0
  205. package/templates/production-fullstack/mobile/src/components/ui/data-display/Badge.tsx +104 -0
  206. package/templates/production-fullstack/mobile/src/components/ui/data-display/Card.tsx +36 -0
  207. package/templates/production-fullstack/mobile/src/components/ui/data-display/Image.tsx +43 -0
  208. package/templates/production-fullstack/mobile/src/components/ui/data-display/ImageViewer.tsx +33 -0
  209. package/templates/production-fullstack/mobile/src/components/ui/data-display/SwipeableRow.tsx +94 -0
  210. package/templates/production-fullstack/mobile/src/components/ui/feedback/CircularProgress.tsx +38 -0
  211. package/templates/production-fullstack/mobile/src/components/ui/feedback/GestureWrapper.tsx +114 -0
  212. package/templates/production-fullstack/mobile/src/components/ui/feedback/ProgressBar.tsx +51 -0
  213. package/templates/production-fullstack/mobile/src/components/ui/feedback/Skeleton.tsx +84 -0
  214. package/templates/production-fullstack/mobile/src/components/ui/feedback/Spinner.tsx +50 -0
  215. package/templates/production-fullstack/mobile/src/components/ui/inputs/Checkbox.tsx +54 -0
  216. package/templates/production-fullstack/mobile/src/components/ui/inputs/DatePicker.tsx +186 -0
  217. package/templates/production-fullstack/mobile/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
  218. package/templates/production-fullstack/mobile/src/components/ui/inputs/Input.tsx +158 -0
  219. package/templates/production-fullstack/mobile/src/components/ui/inputs/LocationPicker.tsx +211 -0
  220. package/templates/production-fullstack/mobile/src/components/ui/inputs/OTPInput.tsx +83 -0
  221. package/templates/production-fullstack/mobile/src/components/ui/inputs/PasswordInput.tsx +16 -0
  222. package/templates/production-fullstack/mobile/src/components/ui/inputs/Radio.tsx +54 -0
  223. package/templates/production-fullstack/mobile/src/components/ui/inputs/SearchBar.tsx +53 -0
  224. package/templates/production-fullstack/mobile/src/components/ui/inputs/Slider.tsx +49 -0
  225. package/templates/production-fullstack/mobile/src/components/ui/inputs/Switch.tsx +75 -0
  226. package/templates/production-fullstack/mobile/src/components/ui/inputs/TextArea.tsx +15 -0
  227. package/templates/production-fullstack/mobile/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
  228. package/templates/production-fullstack/mobile/src/components/ui/layout/Container.tsx +23 -0
  229. package/templates/production-fullstack/mobile/src/components/ui/layout/Divider.tsx +20 -0
  230. package/templates/production-fullstack/mobile/src/components/ui/layout/Grid.tsx +62 -0
  231. package/templates/production-fullstack/mobile/src/components/ui/layout/KeyboardAvoidingViewWrapper.tsx +16 -0
  232. package/templates/production-fullstack/mobile/src/components/ui/layout/ScrollContainer.tsx +21 -0
  233. package/templates/production-fullstack/mobile/src/components/ui/layout/Section.tsx +51 -0
  234. package/templates/production-fullstack/mobile/src/components/ui/layout/Spacer.tsx +6 -0
  235. package/templates/production-fullstack/mobile/src/components/ui/layout/Stack.tsx +34 -0
  236. package/templates/production-fullstack/mobile/src/components/ui/navigation/Pagination.tsx +61 -0
  237. package/templates/production-fullstack/mobile/src/components/ui/navigation/ProgressStepper.tsx +66 -0
  238. package/templates/production-fullstack/mobile/src/components/ui/navigation/Tabs.tsx +173 -0
  239. package/templates/production-fullstack/mobile/src/config/sidebar.config.ts +72 -0
  240. package/templates/production-fullstack/mobile/src/config/tabNavigation.ts +64 -0
  241. package/templates/production-fullstack/mobile/src/constants/Colors.ts +71 -0
  242. package/templates/production-fullstack/mobile/src/db/index.ts +9 -0
  243. package/templates/production-fullstack/mobile/src/db/schema.ts +14 -0
  244. package/templates/production-fullstack/mobile/src/features/auth/api/auth.service.ts +35 -0
  245. package/templates/production-fullstack/mobile/src/features/auth/store/useAuthStore.ts +273 -0
  246. package/templates/production-fullstack/mobile/src/features/auth/types/auth.type.ts +14 -0
  247. package/templates/production-fullstack/mobile/src/hooks/useDebounce.ts +17 -0
  248. package/templates/production-fullstack/mobile/src/lib/axios.ts +27 -0
  249. package/templates/production-fullstack/mobile/src/lib/query-client.ts +11 -0
  250. package/templates/production-fullstack/mobile/src/lib/socket.ts +36 -0
  251. package/templates/production-fullstack/mobile/src/lib/storage.ts +55 -0
  252. package/templates/production-fullstack/mobile/src/services/permission.service.ts +214 -0
  253. package/templates/production-fullstack/mobile/src/store/localStore.ts +7 -0
  254. package/templates/production-fullstack/mobile/src/store/useNotificationStore.ts +53 -0
  255. package/templates/production-fullstack/mobile/src/types/common.type.ts +6 -0
  256. package/templates/production-fullstack/mobile/src/types/images.d.ts +24 -0
  257. package/templates/production-fullstack/mobile/src/utils/toast.ts +26 -0
  258. package/templates/production-fullstack/mobile/tailwind.config.js +71 -0
  259. package/templates/production-fullstack/mobile/tsconfig.json +23 -0
  260. package/templates/production-fullstack/server/.env.example +63 -0
  261. package/templates/production-fullstack/server/README.md +75 -0
  262. package/templates/production-fullstack/server/eslint.config.js +13 -0
  263. package/templates/production-fullstack/server/package.json +58 -0
  264. package/templates/production-fullstack/server/prisma/schema/core/attachment.prisma +14 -0
  265. package/templates/production-fullstack/server/prisma/schema/core/notification.prisma +18 -0
  266. package/templates/production-fullstack/server/prisma/schema/core/permission.prisma +26 -0
  267. package/templates/production-fullstack/server/prisma/schema/core/role.prisma +25 -0
  268. package/templates/production-fullstack/server/prisma/schema/core/user.prisma +56 -0
  269. package/templates/production-fullstack/server/prisma/schema/enums/common.prisma +13 -0
  270. package/templates/production-fullstack/server/prisma/schema/enums/notification.prisma +6 -0
  271. package/templates/production-fullstack/server/prisma/schema/enums/user.prisma +11 -0
  272. package/templates/production-fullstack/server/prisma/schema/schema.prisma +7 -0
  273. package/templates/production-fullstack/server/prisma.config.ts +14 -0
  274. package/templates/production-fullstack/server/src/app.ts +36 -0
  275. package/templates/production-fullstack/server/src/common/middlewares/auth.middleware.ts +45 -0
  276. package/templates/production-fullstack/server/src/common/middlewares/errorHandler.ts +16 -0
  277. package/templates/production-fullstack/server/src/common/middlewares/multer.ts +20 -0
  278. package/templates/production-fullstack/server/src/common/middlewares/rateLimiter.ts +53 -0
  279. package/templates/production-fullstack/server/src/common/services/email.service.ts +28 -0
  280. package/templates/production-fullstack/server/src/common/services/push.service.ts +65 -0
  281. package/templates/production-fullstack/server/src/common/services/storage.service.ts +9 -0
  282. package/templates/production-fullstack/server/src/common/types/express.d.ts +10 -0
  283. package/templates/production-fullstack/server/src/common/utils/cloudinaryUpload.ts +44 -0
  284. package/templates/production-fullstack/server/src/common/utils/emailOtp.ts +30 -0
  285. package/templates/production-fullstack/server/src/common/utils/genOtpToken.ts +22 -0
  286. package/templates/production-fullstack/server/src/common/utils/generateVapidKeys.ts +12 -0
  287. package/templates/production-fullstack/server/src/common/utils/jwt.ts +27 -0
  288. package/templates/production-fullstack/server/src/common/utils/pushHelper.ts +22 -0
  289. package/templates/production-fullstack/server/src/config/env.ts +2 -0
  290. package/templates/production-fullstack/server/src/config/logger.ts +58 -0
  291. package/templates/production-fullstack/server/src/config/prisma.ts +26 -0
  292. package/templates/production-fullstack/server/src/features/attachments/upload.controller.ts +22 -0
  293. package/templates/production-fullstack/server/src/features/attachments/upload.routes.ts +11 -0
  294. package/templates/production-fullstack/server/src/features/auth/auth.controller.ts +124 -0
  295. package/templates/production-fullstack/server/src/features/auth/auth.routes.ts +22 -0
  296. package/templates/production-fullstack/server/src/features/auth/auth.service.ts +155 -0
  297. package/templates/production-fullstack/server/src/features/notifications/push.controller.ts +55 -0
  298. package/templates/production-fullstack/server/src/features/notifications/push.routes.ts +11 -0
  299. package/templates/production-fullstack/server/src/index.ts +17 -0
  300. package/templates/production-fullstack/server/src/routes/index.ts +12 -0
  301. package/templates/production-fullstack/server/src/sockets/auth.ts +0 -0
  302. package/templates/production-fullstack/server/src/sockets/connection.ts +31 -0
  303. package/templates/production-fullstack/server/src/sockets/emitters/assignment.emitter.ts +0 -0
  304. package/templates/production-fullstack/server/src/sockets/emitters/attendance.emitter.ts +0 -0
  305. package/templates/production-fullstack/server/src/sockets/emitters/exam.emitter.ts +0 -0
  306. package/templates/production-fullstack/server/src/sockets/emitters/notification.emitter.ts +17 -0
  307. package/templates/production-fullstack/server/src/sockets/events.ts +27 -0
  308. package/templates/production-fullstack/server/src/sockets/handlers/attendance.handler.ts +0 -0
  309. package/templates/production-fullstack/server/src/sockets/handlers/chat.handler.ts +0 -0
  310. package/templates/production-fullstack/server/src/sockets/handlers/index.ts +15 -0
  311. package/templates/production-fullstack/server/src/sockets/handlers/lms.handler.ts +0 -0
  312. package/templates/production-fullstack/server/src/sockets/handlers/notification.handler.ts +39 -0
  313. package/templates/production-fullstack/server/src/sockets/index.ts +39 -0
  314. package/templates/production-fullstack/server/src/sockets/middleware.ts +54 -0
  315. package/templates/production-fullstack/server/src/sockets/rooms.ts +11 -0
  316. package/templates/production-fullstack/server/src/sockets/types.ts +32 -0
  317. package/templates/production-fullstack/server/tsconfig.json +14 -0
  318. package/templates/react-native/babel.config.js +1 -0
  319. package/templates/react-native/drizzle.config.ts +8 -0
  320. package/templates/react-native/package.json +8 -1
  321. package/templates/react-native/src/app/(auth)/_layout.tsx +12 -0
  322. package/templates/react-native/src/app/(auth)/change-password.tsx +112 -0
  323. package/templates/react-native/src/app/(auth)/edit-profile.tsx +156 -0
  324. package/templates/react-native/src/app/(auth)/forgot-password.tsx +191 -0
  325. package/templates/react-native/src/app/{login.tsx → (auth)/login.tsx} +69 -21
  326. package/templates/react-native/src/app/(tabs)/dashboard.tsx +2 -2
  327. package/templates/react-native/src/app/(tabs)/index.tsx +18 -17
  328. package/templates/react-native/src/app/(tabs)/profile.tsx +23 -60
  329. package/templates/react-native/src/app/(tabs)/search.tsx +2 -2
  330. package/templates/react-native/src/app/_layout.tsx +22 -4
  331. package/templates/react-native/src/components/common/AnimatedHeader.tsx +328 -0
  332. package/templates/react-native/src/components/common/LocationLoader.tsx +591 -0
  333. package/templates/react-native/src/components/common/ScreenHeader.tsx +41 -17
  334. package/templates/react-native/src/components/common/TabHeader.tsx +58 -0
  335. package/templates/react-native/src/components/common/Typography.tsx +49 -30
  336. package/templates/react-native/src/components/common/Welcome.tsx +2 -2
  337. package/templates/react-native/src/components/ui/BottomModal.tsx +31 -20
  338. package/templates/react-native/src/components/ui/ClassicTabBar.tsx +4 -3
  339. package/templates/react-native/src/components/ui/CustomTabBar.tsx +108 -71
  340. package/templates/react-native/src/components/ui/Sidebar.tsx +81 -56
  341. package/templates/react-native/src/components/ui/buttons/Button.tsx +106 -37
  342. package/templates/react-native/src/components/ui/buttons/IconButton.tsx +4 -2
  343. package/templates/react-native/src/components/ui/data-display/Accordion.tsx +3 -2
  344. package/templates/react-native/src/components/ui/data-display/Avatar.tsx +4 -3
  345. package/templates/react-native/src/components/ui/data-display/Badge.tsx +45 -17
  346. package/templates/react-native/src/components/ui/data-display/ImageViewer.tsx +19 -9
  347. package/templates/react-native/src/components/ui/feedback/CircularProgress.tsx +5 -4
  348. package/templates/react-native/src/components/ui/feedback/ProgressBar.tsx +4 -3
  349. package/templates/react-native/src/components/ui/feedback/Skeleton.tsx +3 -0
  350. package/templates/react-native/src/components/ui/feedback/Spinner.tsx +11 -3
  351. package/templates/react-native/src/components/ui/inputs/Checkbox.tsx +3 -2
  352. package/templates/react-native/src/components/ui/inputs/DatePicker.tsx +186 -0
  353. package/templates/react-native/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
  354. package/templates/react-native/src/components/ui/inputs/Input.tsx +54 -14
  355. package/templates/react-native/src/components/ui/inputs/LocationPicker.tsx +211 -0
  356. package/templates/react-native/src/components/ui/inputs/OTPInput.tsx +32 -9
  357. package/templates/react-native/src/components/ui/inputs/PasswordInput.tsx +2 -1
  358. package/templates/react-native/src/components/ui/inputs/Radio.tsx +3 -2
  359. package/templates/react-native/src/components/ui/inputs/SearchBar.tsx +41 -4
  360. package/templates/react-native/src/components/ui/inputs/Slider.tsx +4 -3
  361. package/templates/react-native/src/components/ui/inputs/Switch.tsx +3 -2
  362. package/templates/react-native/src/components/ui/inputs/TextArea.tsx +2 -1
  363. package/templates/react-native/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
  364. package/templates/react-native/src/components/ui/layout/Grid.tsx +52 -10
  365. package/templates/react-native/src/components/ui/layout/Section.tsx +7 -8
  366. package/templates/react-native/src/components/ui/navigation/Pagination.tsx +4 -3
  367. package/templates/react-native/src/components/ui/navigation/ProgressStepper.tsx +6 -5
  368. package/templates/react-native/src/components/ui/navigation/Tabs.tsx +30 -4
  369. package/templates/react-native/src/config/api.ts +12 -1
  370. package/templates/react-native/src/config/sidebar.config.ts +12 -0
  371. package/templates/react-native/src/config/tabNavigation.ts +1 -1
  372. package/templates/react-native/src/db/index.ts +9 -0
  373. package/templates/react-native/src/db/schema.ts +14 -0
  374. package/templates/react-native/src/hooks/useDebounce.ts +17 -0
  375. package/templates/react-native/src/services/notification.service.ts +22 -0
  376. package/templates/react-native/src/services/socket.service.ts +36 -0
  377. package/templates/react-native/src/store/useAuthStore.ts +122 -27
  378. package/templates/react-native/src/store/useNotificationStore.ts +178 -0
  379. package/templates/react-native/src/types/auth.type.ts +14 -0
  380. package/templates/react-native/tsconfig.json +1 -0
  381. package/templates/react-ts/src/vite-env.d.ts +1 -0
  382. package/templates/mern-react-native/mobile/.env.example +0 -2
  383. package/templates/mern-react-native/mobile/.vscode/extensions.json +0 -1
  384. package/templates/mern-react-native/mobile/.vscode/settings.json +0 -7
  385. package/templates/mern-react-native/mobile/README.md +0 -159
  386. package/templates/mern-react-native/mobile/docs/README.md +0 -17
  387. package/templates/mern-react-native/mobile/docs/components/buttons.md +0 -40
  388. package/templates/mern-react-native/mobile/docs/components/data-display.md +0 -44
  389. package/templates/mern-react-native/mobile/docs/components/feedback.md +0 -36
  390. package/templates/mern-react-native/mobile/docs/components/gestures.md +0 -60
  391. package/templates/mern-react-native/mobile/docs/components/inputs.md +0 -41
  392. package/templates/mern-react-native/mobile/docs/components/layout.md +0 -34
  393. package/templates/mern-react-native/mobile/docs/components/navigation.md +0 -31
  394. package/templates/mern-react-native/mobile/docs/features.md +0 -85
  395. package/templates/mern-react-native/mobile/docs/getting-started.md +0 -47
  396. package/templates/mern-react-native/mobile/src/components/common/HomeHeader.tsx +0 -43
  397. package/templates/mern-react-native/mobile/src/components/settings/SettingToggle.tsx +0 -26
  398. package/templates/mern-react-native/mobile/src/components/settings/SettingsOptions.tsx +0 -47
  399. package/templates/react-native/.env.example +0 -2
  400. package/templates/react-native/.vscode/extensions.json +0 -1
  401. package/templates/react-native/.vscode/settings.json +0 -7
  402. package/templates/react-native/README.md +0 -159
  403. package/templates/react-native/docs/README.md +0 -17
  404. package/templates/react-native/docs/components/buttons.md +0 -40
  405. package/templates/react-native/docs/components/data-display.md +0 -44
  406. package/templates/react-native/docs/components/feedback.md +0 -36
  407. package/templates/react-native/docs/components/gestures.md +0 -60
  408. package/templates/react-native/docs/components/inputs.md +0 -41
  409. package/templates/react-native/docs/components/layout.md +0 -34
  410. package/templates/react-native/docs/components/navigation.md +0 -31
  411. package/templates/react-native/docs/features.md +0 -85
  412. package/templates/react-native/docs/getting-started.md +0 -47
  413. package/templates/react-native/src/components/common/HomeHeader.tsx +0 -43
  414. package/templates/react-native/src/components/settings/SettingToggle.tsx +0 -26
  415. package/templates/react-native/src/components/settings/SettingsOptions.tsx +0 -47
@@ -0,0 +1,36 @@
1
+ import { io, Socket } from 'socket.io-client';
2
+ import { get } from '../utils/storage';
3
+ import Constants from 'expo-constants';
4
+
5
+ let socket: Socket | null = null;
6
+
7
+ // Set your backend socket URL
8
+ const SOCKET_URL = Constants.expoConfig?.extra?.apiUrl || 'http://localhost:3000';
9
+
10
+ export const initializeSocket = async () => {
11
+ if (socket) return;
12
+ const token = await get('token');
13
+ if (!token) return;
14
+
15
+ socket = io(SOCKET_URL, {
16
+ auth: { token },
17
+ transports: ['websocket'],
18
+ });
19
+
20
+ socket.on('connect', () => {
21
+ console.log('Connected to socket server');
22
+ });
23
+
24
+ socket.on('disconnect', () => {
25
+ console.log('Disconnected from socket server');
26
+ });
27
+ };
28
+
29
+ export const getSocket = () => socket;
30
+
31
+ export const disconnectSocket = () => {
32
+ if (socket) {
33
+ socket.disconnect();
34
+ socket = null;
35
+ }
36
+ };
@@ -1,20 +1,15 @@
1
1
  import { create } from "zustand";
2
2
  import { authService } from "../services/auth.service";
3
- import { save, remove } from "../utils/storage";
4
-
5
- export interface User {
6
- _id: string;
7
- name: string;
8
- email: string;
9
- phone?: string;
10
- role: string;
11
- avatar?: {
12
- url?: string;
13
- publicId?: string;
14
- };
15
- createdAt?: string;
16
- updatedAt?: string;
17
- }
3
+ import { save, remove, get } from "../utils/storage";
4
+ import { User } from "../types/auth.type";
5
+ import { initializeSocket, disconnectSocket } from "../services/socket.service";
6
+ import { useNotificationStore } from "./useNotificationStore";
7
+
8
+ // ── Module-level prefetch ──────────────────────────────────────────────────
9
+ // Kick off the AsyncStorage read the instant this module is imported
10
+ // (before any React component mounts). By the time loadCachedUser() is
11
+ // called from a useEffect, the promise is already resolved or very close.
12
+ const _prefetchedUser: Promise<User | null> = get("user");
18
13
 
19
14
  export interface AuthState {
20
15
  user: User | null;
@@ -34,6 +29,13 @@ export interface AuthState {
34
29
  getMe: () => Promise<void>;
35
30
  updateProfile: (updates: Partial<User> | FormData) => Promise<boolean>;
36
31
  logout: () => Promise<void>;
32
+ genOtp: (email: string) => Promise<boolean>;
33
+ verifyOtp: (email: string, otp: string) => Promise<boolean>;
34
+ resetPassword: (newPassword: string) => Promise<boolean>;
35
+ changePassword: (oldPassword: string, newPassword: string) => Promise<boolean>;
36
+ setUser: (user: User) => void;
37
+ clearError: () => void;
38
+ loadCachedUser: () => Promise<void>;
37
39
  }
38
40
 
39
41
  export const useAuthStore = create<AuthState>((set) => ({
@@ -42,6 +44,27 @@ export const useAuthStore = create<AuthState>((set) => ({
42
44
  isCheckingAuth: true,
43
45
  error: null,
44
46
 
47
+ setUser: (user: User) => set({ user }),
48
+
49
+ clearError: () => set({ error: null }),
50
+
51
+ loadCachedUser: async () => {
52
+ // Await the already-in-flight prefetch — typically resolves in <1ms here
53
+ const cached = await _prefetchedUser;
54
+ if (cached) {
55
+ set({ user: cached, isCheckingAuth: false });
56
+ // Re-establish socket + push on app resume with a cached session
57
+ initializeSocket();
58
+ const notifStore = useNotificationStore.getState();
59
+ notifStore.listenForSocketEvents();
60
+ notifStore.registerForPushNotificationsAsync();
61
+ notifStore.fetchNotifications();
62
+ } else {
63
+ // No cache — mark auth check done so routing doesn't hang
64
+ set({ isCheckingAuth: false });
65
+ }
66
+ },
67
+
45
68
  sendOtp: async (email: string) => {
46
69
  set({ loading: true, error: null });
47
70
  try {
@@ -74,13 +97,21 @@ export const useAuthStore = create<AuthState>((set) => ({
74
97
  otp,
75
98
  role,
76
99
  );
77
- if (data.token) {
78
- save("token", data.token);
100
+ if (data.data?.token) {
101
+ save("token", data.data.token);
79
102
  }
103
+ const user = data.data?.user;
104
+ if (user) save("user", user);
80
105
  set({
81
- user: data.data,
106
+ user,
82
107
  loading: false,
83
108
  });
109
+ // Initialise socket + push after signup
110
+ initializeSocket();
111
+ const notifStore = useNotificationStore.getState();
112
+ notifStore.listenForSocketEvents();
113
+ notifStore.registerForPushNotificationsAsync();
114
+ notifStore.fetchNotifications();
84
115
  return true;
85
116
  } catch (err: any) {
86
117
  set({
@@ -97,13 +128,21 @@ export const useAuthStore = create<AuthState>((set) => ({
97
128
  set({ loading: true, error: null });
98
129
  try {
99
130
  const { data } = await authService.login(email, password);
100
- if (data.token) {
101
- save("token", data.token);
131
+ if (data.data?.token) {
132
+ save("token", data.data.token);
102
133
  }
134
+ const user = data.data?.user;
135
+ if (user) save("user", user);
103
136
  set({
104
- user: data.data,
137
+ user,
105
138
  loading: false,
106
139
  });
140
+ // Initialise socket + push after login
141
+ initializeSocket();
142
+ const notifStore = useNotificationStore.getState();
143
+ notifStore.listenForSocketEvents();
144
+ notifStore.registerForPushNotificationsAsync();
145
+ notifStore.fetchNotifications();
107
146
  return true;
108
147
  } catch (err: any) {
109
148
  set({
@@ -123,7 +162,7 @@ export const useAuthStore = create<AuthState>((set) => ({
123
162
  save("token", "demo-token-123");
124
163
  set({
125
164
  user: {
126
- _id: "demo_user_123",
165
+ id: "demo_user_123",
127
166
  name: "Demo User",
128
167
  email: "demo@imksh.com",
129
168
  role: "admin",
@@ -133,12 +172,13 @@ export const useAuthStore = create<AuthState>((set) => ({
133
172
  },
134
173
 
135
174
  getMe: async () => {
136
- set({ isCheckingAuth: true });
137
175
  try {
138
176
  const { data } = await authService.getMe();
139
- set({ user: data.data, isCheckingAuth: false });
140
- } catch {
141
- set({ isCheckingAuth: false });
177
+ const user = data.data;
178
+ // Always update cache with fresh server data
179
+ if (user) save("user", user);
180
+ set({ user, isCheckingAuth: false });
181
+ // Network failed — cached user (already loaded) stays in place
142
182
  } finally {
143
183
  set({ isCheckingAuth: false });
144
184
  }
@@ -167,7 +207,9 @@ export const useAuthStore = create<AuthState>((set) => ({
167
207
  } catch {
168
208
  // ignore errors — cookie may already be expired
169
209
  } finally {
170
- remove("token");
210
+ await remove("token");
211
+ await remove("user"); // clear cached user on logout
212
+ disconnectSocket();
171
213
  set({ loading: false });
172
214
  }
173
215
  set({
@@ -175,4 +217,57 @@ export const useAuthStore = create<AuthState>((set) => ({
175
217
  error: null,
176
218
  });
177
219
  },
220
+
221
+ genOtp: async (email: string) => {
222
+ set({ loading: true, error: null });
223
+ try {
224
+ await authService.genOtp(email);
225
+ return true;
226
+ } catch (err: any) {
227
+ set({ error: err.response?.data?.message || err.message, loading: false });
228
+ return false;
229
+ } finally {
230
+ set({ loading: false });
231
+ }
232
+ },
233
+
234
+ verifyOtp: async (email: string, otp: string) => {
235
+ set({ loading: true, error: null });
236
+ try {
237
+ const { data } = await authService.verifyOtp(email, otp);
238
+ if (data.token) save("token", data.token);
239
+ return true;
240
+ } catch (err: any) {
241
+ set({ error: err.response?.data?.message || err.message, loading: false });
242
+ return false;
243
+ } finally {
244
+ set({ loading: false });
245
+ }
246
+ },
247
+
248
+ resetPassword: async (newPassword: string) => {
249
+ set({ loading: true, error: null });
250
+ try {
251
+ await authService.resetPassword(newPassword);
252
+ return true;
253
+ } catch (err: any) {
254
+ set({ error: err.response?.data?.message || err.message, loading: false });
255
+ return false;
256
+ } finally {
257
+ set({ loading: false });
258
+ }
259
+ },
260
+
261
+ changePassword: async (oldPassword: string, newPassword: string) => {
262
+ set({ loading: true, error: null });
263
+ try {
264
+ await authService.changePassword(oldPassword, newPassword);
265
+ return true;
266
+ } catch (err: any) {
267
+ set({ error: err.response?.data?.message || err.message, loading: false });
268
+ return false;
269
+ } finally {
270
+ set({ loading: false });
271
+ }
272
+ },
178
273
  }));
@@ -0,0 +1,178 @@
1
+ import { create } from "zustand";
2
+ import { notificationService } from "../services/notification.service";
3
+ import Constants from "expo-constants";
4
+ import { Platform } from "react-native";
5
+ import { getSocket } from "../services/socket.service";
6
+ import { toast } from "../utils/toast";
7
+
8
+ export interface AppNotification {
9
+ id: string;
10
+ title: string;
11
+ message: string;
12
+ type: string;
13
+ url: string | null;
14
+ isRead: boolean;
15
+ metadata: any | null;
16
+ createdAt: string;
17
+ }
18
+
19
+ interface NotificationState {
20
+ notifications: AppNotification[];
21
+ unreadCount: number;
22
+ loading: boolean;
23
+ error: string | null;
24
+
25
+ fetchNotifications: () => Promise<void>;
26
+ markAsRead: (id: string) => Promise<void>;
27
+ markAllAsRead: () => Promise<void>;
28
+ registerForPushNotificationsAsync: () => Promise<string | undefined>;
29
+ listenForSocketEvents: () => void;
30
+ }
31
+
32
+ export const useNotificationStore = create<NotificationState>((set, get) => ({
33
+ notifications: [],
34
+ unreadCount: 0,
35
+ loading: false,
36
+ error: null,
37
+
38
+ fetchNotifications: async () => {
39
+ set({ loading: true, error: null });
40
+ try {
41
+ const response = await notificationService.getNotifications();
42
+ const notifications = response.data.data;
43
+ const unreadCount = notifications.filter((n: AppNotification) => !n.isRead).length;
44
+
45
+ set({
46
+ notifications,
47
+ unreadCount,
48
+ loading: false,
49
+ });
50
+ } catch (error: any) {
51
+ set({
52
+ error: error.response?.data?.message || "Failed to fetch notifications",
53
+ loading: false,
54
+ });
55
+ }
56
+ },
57
+
58
+ markAsRead: async (id: string) => {
59
+ try {
60
+ // Optimistic update
61
+ const { notifications, unreadCount } = get();
62
+ const updated = notifications.map(n =>
63
+ n.id === id ? { ...n, isRead: true } : n
64
+ );
65
+
66
+ set({
67
+ notifications: updated,
68
+ unreadCount: Math.max(0, unreadCount - 1)
69
+ });
70
+
71
+ await notificationService.markAsRead(id);
72
+ } catch{
73
+ // Revert if failed
74
+ get().fetchNotifications();
75
+ }
76
+ },
77
+
78
+ markAllAsRead: async () => {
79
+ try {
80
+ const { notifications } = get();
81
+ const updated = notifications.map(n => ({ ...n, isRead: true }));
82
+
83
+ set({
84
+ notifications: updated,
85
+ unreadCount: 0
86
+ });
87
+
88
+ await notificationService.markAllAsRead();
89
+ } catch{
90
+ get().fetchNotifications();
91
+ }
92
+ },
93
+
94
+ registerForPushNotificationsAsync: async () => {
95
+ let token;
96
+
97
+ const isExpoGo = Constants.appOwnership === 'expo';
98
+ if (isExpoGo && Platform.OS === 'android') {
99
+ console.log('Skipping push notification registration: not supported in Expo Go on Android (SDK 53+).');
100
+ return;
101
+ }
102
+
103
+ try {
104
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
105
+ const Notifications = require("expo-notifications");
106
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
107
+ const Device = require("expo-device");
108
+
109
+ if (Platform.OS === 'android') {
110
+ await Notifications.setNotificationChannelAsync('default', {
111
+ name: 'default',
112
+ importance: Notifications.AndroidImportance.MAX,
113
+ vibrationPattern: [0, 250, 250, 250],
114
+ lightColor: '#FF231F7C',
115
+ });
116
+ }
117
+
118
+ if (Device.isDevice) {
119
+ const { status: existingStatus } = await Notifications.getPermissionsAsync();
120
+ let finalStatus = existingStatus;
121
+
122
+ if (existingStatus !== 'granted') {
123
+ const { status } = await Notifications.requestPermissionsAsync();
124
+ finalStatus = status;
125
+ }
126
+
127
+ if (finalStatus !== 'granted') {
128
+ console.log('Failed to get push token for push notification!');
129
+ return;
130
+ }
131
+
132
+ const projectId =
133
+ Constants.expoConfig?.extra?.eas?.projectId ??
134
+ Constants.easConfig?.projectId ??
135
+ "f9a7053c-bc16-4717-805b-560c5a35e974";
136
+
137
+ token = (await Notifications.getExpoPushTokenAsync({ projectId })).data;
138
+
139
+ // Send token to backend
140
+ try {
141
+ await notificationService.registerPushToken(token);
142
+ } catch (e) {
143
+ console.error("Failed to save push token to server", e);
144
+ }
145
+ } else {
146
+ console.log('Must use physical device for Push Notifications');
147
+ }
148
+ } catch (e) {
149
+ console.warn("Failed to setup push notifications dynamically:", e);
150
+ }
151
+
152
+ return token;
153
+ },
154
+
155
+ listenForSocketEvents: () => {
156
+ const socket = getSocket();
157
+ if (!socket) return;
158
+
159
+ // Remove any existing listener to prevent duplicates
160
+ socket.off("new_notification");
161
+
162
+ socket.on("new_notification", (notification: AppNotification) => {
163
+ const { notifications, unreadCount } = get();
164
+
165
+ // Ensure we don't duplicate notifications if they were fetched via API around the same time
166
+ const exists = notifications.find((n) => n.id === notification.id);
167
+ if (!exists) {
168
+ set({
169
+ notifications: [notification, ...notifications],
170
+ unreadCount: unreadCount + 1,
171
+ });
172
+
173
+ // Alert the user visually!
174
+ toast.info(notification.title, notification.message);
175
+ }
176
+ });
177
+ }
178
+ }));
@@ -0,0 +1,14 @@
1
+ export interface User {
2
+ id: string; // Updated from _id for Prisma consistency
3
+ _id?: string; // Fallback for mongo legacy if any
4
+ name: string;
5
+ email: string;
6
+ phone?: string;
7
+ role: string;
8
+ avatar?: {
9
+ url?: string;
10
+ publicId?: string;
11
+ };
12
+ createdAt?: string;
13
+ updatedAt?: string;
14
+ }
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "extends": "expo/tsconfig.base",
3
3
  "compilerOptions": {
4
+ "jsx": "react-jsx",
4
5
  "strict": true,
5
6
  "noImplicitAny": false,
6
7
  "paths": {
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -17,6 +17,7 @@ const nextConfig = {
17
17
  },
18
18
  ];
19
19
  },
20
+ turbopack: {},
20
21
  };
21
22
 
22
23
  export default withPWA(nextConfig);
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "next-template",
2
+ "name": "client",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "scripts": {
@@ -9,24 +9,25 @@
9
9
  "lint": "next lint"
10
10
  },
11
11
  "dependencies": {
12
- "react": "^18",
13
- "react-dom": "^18",
14
- "next": "14.0.3",
15
12
  "@ducanh2912/next-pwa": "latest",
13
+ "@tailwindcss/postcss": "^4.3.3",
16
14
  "axios": "^1.6.0",
17
15
  "flyonui": "^2.4.1",
18
16
  "framer-motion": "^11.0.0",
19
17
  "lenis": "^1.1.3",
20
18
  "lottie-react": "^2.4.0",
21
- "lucide-react": "^0.292.0",
19
+ "lucide-react": "^0.470.0",
20
+ "next": "^16.3.0",
21
+ "postcss": "^8.5.26",
22
+ "react": "^19.2.8",
23
+ "react-dom": "^19.2.8",
22
24
  "react-hot-toast": "^2.4.1",
23
25
  "react-icons": "^4.11.0",
24
- "tailwindcss": "^4.3.2",
25
- "@tailwindcss/postcss": "^4.3.2",
26
+ "tailwindcss": "^4.3.3",
26
27
  "zustand": "^4.5.2"
27
28
  },
28
29
  "devDependencies": {
29
- "eslint": "^8",
30
- "eslint-config-next": "14.0.3"
30
+ "eslint": "^10.8.1",
31
+ "eslint-config-next": "^16.3.0"
31
32
  }
32
33
  }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
@@ -28,6 +28,7 @@ export default function RootLayout({ children }) {
28
28
  <div className="min-h-screen bg-base-100 text-base-content font-sans">
29
29
  <Toaster position="top-right" />
30
30
  <Scroll />
31
+
31
32
  {children}
32
33
  </div>
33
34
  </body>
@@ -2,7 +2,7 @@
2
2
  import React from "react";
3
3
  import Link from "next/link";
4
4
  import { motion } from "framer-motion";
5
- import { FiZap, FiLayers, FiCpu, FiShield, FiArrowRight } from "react-icons/fi";
5
+ import { FiZap, FiLayers, FiCpu, FiShield } from "react-icons/fi";
6
6
  import appConfig from "../config/appConfig";
7
7
  import toast from "react-hot-toast";
8
8
  import { useState } from "react";
@@ -9,16 +9,16 @@ const ProtectedRoute = ({ children, role }) => {
9
9
  const router = useRouter();
10
10
 
11
11
  useEffect(() => {
12
- if (!loading) {
12
+ if (!isCheckingAuth) {
13
13
  if (!user) {
14
14
  router.replace("/login");
15
15
  } else if (role && user.role !== role) {
16
16
  router.replace("/");
17
17
  }
18
18
  }
19
- }, [user, loading, role, router]);
19
+ }, [user, isCheckingAuth, role, router]);
20
20
 
21
- if (loading || !user || (role && user.role !== role)) return <Loading />;
21
+ if (isCheckingAuth || !user || (role && user.role !== role)) return <Loading />;
22
22
 
23
23
  return <>{children}</>;
24
24
  };
@@ -1,5 +1,6 @@
1
1
  @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800;900&display=swap');
2
2
  @import "tailwindcss";
3
+ @source "./";
3
4
  @plugin "flyonui";
4
5
 
5
6
 
@@ -17,12 +17,15 @@ export const useUiStore = create((set, get) => ({
17
17
  set((state) => ({ isMobileMenuOpened: !state.isMobileMenuOpened }));
18
18
  },
19
19
 
20
- theme: localStorage.getItem("theme") || "light",
20
+ theme: typeof window !== "undefined" ? localStorage.getItem("theme") || "light" : "light",
21
21
 
22
22
  setTheme: (theme) => {
23
- document.documentElement.setAttribute("data-theme", theme);
24
-
25
- localStorage.setItem("theme", theme);
23
+ if (typeof document !== "undefined") {
24
+ document.documentElement.setAttribute("data-theme", theme);
25
+ }
26
+ if (typeof window !== "undefined") {
27
+ localStorage.setItem("theme", theme);
28
+ }
26
29
 
27
30
  set({ theme });
28
31
  },
@@ -30,9 +33,12 @@ export const useUiStore = create((set, get) => ({
30
33
  toggleTheme: () => {
31
34
  const nextTheme = get().theme === "light" ? "dark" : "light";
32
35
 
33
- document.documentElement.setAttribute("data-theme", nextTheme);
34
-
35
- localStorage.setItem("theme", nextTheme);
36
+ if (typeof document !== "undefined") {
37
+ document.documentElement.setAttribute("data-theme", nextTheme);
38
+ }
39
+ if (typeof window !== "undefined") {
40
+ localStorage.setItem("theme", nextTheme);
41
+ }
36
42
 
37
43
  set({ theme: nextTheme });
38
44
  },
File without changes
@@ -0,0 +1,37 @@
1
+ <!-- BEGIN:nextjs-agent-rules -->
2
+
3
+ # This is NOT the Next.js you know
4
+
5
+ This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
6
+
7
+ This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
8
+
9
+ <!-- END:nextjs-agent-rules -->
10
+
11
+ # React Starter Template Rules
12
+
13
+ When working on this template, adhere to the following tech stack and architectural conventions:
14
+
15
+ ## 1. Next.js 16 (App Router)
16
+ - Always use the **App Router** (`src/app/`). Do NOT create a `pages/` directory.
17
+ - Differentiate clearly between Server Components (default) and Client Components (add `"use client";` at the top). Use Client Components only when interactivity or browser APIs are required.
18
+ - Do not create custom `_document.tsx` or `_app.tsx`. Use `layout.tsx`.
19
+
20
+ ## 2. Tailwind CSS v4
21
+ - We use **Tailwind CSS v4**. Do not create or look for a `tailwind.config.js` or `tailwind.config.ts`.
22
+ - All styling configuration, theme variables, and custom CSS should be handled in `src/index.css` using the new `@theme` syntax.
23
+ - Do not use `@apply` if it can be solved with utility classes.
24
+
25
+ ## 3. FlyonUI
26
+ - **FlyonUI v2** is pre-configured and available.
27
+ - Prioritize using FlyonUI component classes (e.g., `btn`, `input`, `modal`, `card`) instead of building custom variants from scratch.
28
+ - The plugin is initialized in `src/index.css` via `@plugin "flyonui";`.
29
+
30
+ ## 4. Zustand (State Management)
31
+ - Place all global stores in `src/store/`.
32
+ - **CRITICAL**: Be very careful with Server-Side Rendering (SSR) hydration mismatches when using Zustand. Do not initialize store values directly with browser APIs (e.g., `localStorage`). Always wrap browser API access in `typeof window !== "undefined"` checks or use a standard hydration mechanism.
33
+
34
+ ## 5. Components Architecture
35
+ - Reusable, generic UI components (buttons, inputs) go in `src/components/ui/`.
36
+ - Domain-specific or common page components go in `src/components/common/`.
37
+ - Modals, layouts, and skeletons have their respective folders in `src/components/`.
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -1,24 +0,0 @@
1
- # Logs
2
- logs
3
- *.log
4
- npm-debug.log*
5
- yarn-debug.log*
6
- yarn-error.log*
7
- pnpm-debug.log*
8
- lerna-debug.log*
9
-
10
- node_modules
11
- dist
12
- dist-ssr
13
- *.local
14
-
15
- # Editor directories and files
16
- .vscode/*
17
- !.vscode/extensions.json
18
- .idea
19
- .DS_Store
20
- *.suo
21
- *.ntvs*
22
- *.njsproj
23
- *.sln
24
- *.sw?
@@ -1,5 +1,7 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
+ import "./.next/dev/types/routes.d.ts";
4
+ import "./.next/dev/types/root-params.d.ts";
3
5
 
4
6
  // NOTE: This file should not be edited
5
- // see https://nextjs.org/docs/basic-features/typescript for more information.
7
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.