@imksh/create 1.0.25 → 1.0.27
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.
- package/package.json +1 -1
- package/src/commands/create.js +2 -1
- package/src/index.js +1 -1
- package/src/utils/askTemplate.js +1 -0
- package/templates/mern-react-native/mobile/_gitignore +43 -0
- package/templates/mern-react-native/mobile/package.json +2 -1
- package/templates/mern-react-native/mobile/src/app/(auth)/edit-profile.tsx +11 -15
- package/templates/mern-react-native/mobile/src/app/(tabs)/dashboard.tsx +2 -2
- package/templates/mern-react-native/mobile/src/app/(tabs)/search.tsx +2 -2
- package/templates/mern-react-native/mobile/src/config/sidebar.config.ts +0 -60
- package/templates/mern-react-native/mobile/src/config/tabNavigation.ts +6 -36
- package/templates/mern-react-native/mobile/src/services/notification.service.ts +22 -0
- package/templates/mern-react-native/mobile/src/store/useNotificationStore.ts +158 -33
- package/templates/next/next.config.mjs +1 -0
- package/templates/next/package.json +10 -9
- package/templates/next/postcss.config.js +5 -0
- package/templates/next/src/app/layout.js +1 -0
- package/templates/next/src/app/page.js +1 -1
- package/templates/next/src/components/layout/ProtectedRoute.jsx +3 -3
- package/templates/next/src/index.css +1 -0
- package/templates/next/src/store/useUiStore.js +13 -7
- package/templates/next-ts/.env.example +0 -0
- package/templates/next-ts/AGENTS.md +37 -0
- package/templates/next-ts/CLAUDE.md +1 -0
- package/templates/next-ts/next-env.d.ts +3 -1
- package/templates/next-ts/next.config.mjs +1 -0
- package/templates/next-ts/package.json +13 -12
- package/templates/next-ts/postcss.config.js +5 -0
- package/templates/next-ts/public/logo.png +0 -0
- package/templates/next-ts/src/app/error.tsx +41 -0
- package/templates/next-ts/src/app/layout.tsx +2 -1
- package/templates/next-ts/src/app/not-found.tsx +5 -0
- package/templates/next-ts/src/app/page.tsx +1 -1
- package/templates/next-ts/src/components/layout/ProtectedRoute.tsx +3 -3
- package/templates/next-ts/src/components/ui/Button.tsx +63 -0
- package/templates/next-ts/src/components/ui/Input.tsx +79 -0
- package/templates/next-ts/src/index.css +1 -0
- package/templates/next-ts/src/store/useUiStore.ts +13 -7
- package/templates/next-ts/tsconfig.json +19 -5
- package/templates/production-fullstack/client/_gitignore +24 -0
- package/templates/production-fullstack/client/index.html +14 -0
- package/templates/production-fullstack/client/package.json +47 -0
- package/templates/production-fullstack/client/public/_redirects +1 -0
- package/templates/production-fullstack/client/public/favicon.ico +0 -0
- package/templates/production-fullstack/client/public/favicon.svg +1 -0
- package/templates/production-fullstack/client/public/logo.png +0 -0
- package/templates/production-fullstack/client/public/manifest.json +24 -0
- package/templates/production-fullstack/client/public/sw.js +56 -0
- package/templates/production-fullstack/client/src/App.tsx +68 -0
- package/templates/production-fullstack/client/src/assets/animations/loading.json +1 -0
- package/templates/production-fullstack/client/src/assets/data/navigation.ts +29 -0
- package/templates/production-fullstack/client/src/assets/images/logo.png +0 -0
- package/templates/production-fullstack/client/src/components/layout/ProtectedRoute.tsx +23 -0
- package/templates/production-fullstack/client/src/components/layout/PublicLayout.tsx +13 -0
- package/templates/production-fullstack/client/src/components/layout/SidebarLayout.tsx +37 -0
- package/templates/production-fullstack/client/src/components/shared/Breadcrumbs.tsx +27 -0
- package/templates/production-fullstack/client/src/components/shared/LottieIcon.tsx +36 -0
- package/templates/production-fullstack/client/src/components/shared/NotFound.tsx +78 -0
- package/templates/production-fullstack/client/src/components/shared/PwaInstallPrompt.tsx +72 -0
- package/templates/production-fullstack/client/src/components/shared/SEO.tsx +67 -0
- package/templates/production-fullstack/client/src/components/shared/Scroll.tsx +25 -0
- package/templates/production-fullstack/client/src/components/shared/Unauthorized.tsx +76 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/CardSkeleton.tsx +23 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/DashboardSkeleton.tsx +19 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/ListSkeleton.tsx +24 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/PageSkeleton.tsx +26 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/ProfileSkeleton.tsx +23 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/Skeleton.tsx +18 -0
- package/templates/production-fullstack/client/src/components/shared/skeletons/common/TableSkeleton.tsx +33 -0
- package/templates/production-fullstack/client/src/components/ui/ConfirmModal.tsx +152 -0
- package/templates/production-fullstack/client/src/components/ui/Header.tsx +230 -0
- package/templates/production-fullstack/client/src/components/ui/Loading.tsx +19 -0
- package/templates/production-fullstack/client/src/components/ui/Modal.tsx +106 -0
- package/templates/production-fullstack/client/src/components/ui/SidebarHeader.tsx +34 -0
- package/templates/production-fullstack/client/src/components/ui/Table.tsx +118 -0
- package/templates/production-fullstack/client/src/components/ui/ToggleSwitch.tsx +38 -0
- package/templates/production-fullstack/client/src/components/ui/sidebar.tsx +152 -0
- package/templates/production-fullstack/client/src/config/index.ts +44 -0
- package/templates/production-fullstack/client/src/constants/navigation.ts +14 -0
- package/templates/production-fullstack/client/src/features/auth/api/authService.ts +19 -0
- package/templates/production-fullstack/client/src/features/auth/pages/Login.tsx +233 -0
- package/templates/production-fullstack/client/src/features/auth/store/useAuthStore.ts +143 -0
- package/templates/production-fullstack/client/src/features/core/pages/Home.tsx +150 -0
- package/templates/production-fullstack/client/src/features/core/pages/Profile.tsx +9 -0
- package/templates/production-fullstack/client/src/hooks/useLenis.ts +28 -0
- package/templates/production-fullstack/client/src/hooks/usePwaInstall.ts +45 -0
- package/templates/production-fullstack/client/src/hooks/useWindowSize.ts +25 -0
- package/templates/production-fullstack/client/src/index.css +158 -0
- package/templates/production-fullstack/client/src/lib/axios.ts +22 -0
- package/templates/production-fullstack/client/src/lib/dayjs.ts +12 -0
- package/templates/production-fullstack/client/src/lib/query-client.ts +11 -0
- package/templates/production-fullstack/client/src/lib/socket.ts +6 -0
- package/templates/production-fullstack/client/src/main.tsx +28 -0
- package/templates/production-fullstack/client/src/store/useUiStore.ts +74 -0
- package/templates/production-fullstack/client/src/utils/formatDate.ts +19 -0
- package/templates/production-fullstack/client/src/utils/getInitials.ts +10 -0
- package/templates/production-fullstack/client/src/vite-env.d.ts +1 -0
- package/templates/production-fullstack/client/tsconfig.json +25 -0
- package/templates/production-fullstack/client/tsconfig.node.json +10 -0
- package/templates/production-fullstack/client/vite.config.ts +8 -0
- package/templates/production-fullstack/mobile/LICENSE +21 -0
- package/templates/production-fullstack/mobile/_gitignore +43 -0
- package/templates/production-fullstack/mobile/app.json +84 -0
- package/templates/production-fullstack/mobile/assets/animations/celebrate.json +1 -0
- package/templates/production-fullstack/mobile/assets/animations/infinity.json +1 -0
- package/templates/production-fullstack/mobile/assets/animations/loading.json +1 -0
- package/templates/production-fullstack/mobile/assets/fonts/Inter_Bold.ttf +0 -0
- package/templates/production-fullstack/mobile/assets/fonts/Inter_ExtraBold.ttf +0 -0
- package/templates/production-fullstack/mobile/assets/fonts/Inter_Medium.ttf +0 -0
- package/templates/production-fullstack/mobile/assets/fonts/Inter_Regular.ttf +0 -0
- package/templates/production-fullstack/mobile/assets/fonts/Inter_SemiBold.ttf +0 -0
- package/templates/production-fullstack/mobile/assets/images/logo/logo.png +0 -0
- package/templates/production-fullstack/mobile/assets/images/logo/logo.svg +1 -0
- package/templates/production-fullstack/mobile/assets/images/logo/logoWithBg.png +0 -0
- package/templates/production-fullstack/mobile/babel.config.js +13 -0
- package/templates/production-fullstack/mobile/drizzle.config.ts +8 -0
- package/templates/production-fullstack/mobile/eas.json +24 -0
- package/templates/production-fullstack/mobile/eslint.config.js +10 -0
- package/templates/production-fullstack/mobile/expo-env.d.ts +3 -0
- package/templates/production-fullstack/mobile/metro.config.js +6 -0
- package/templates/production-fullstack/mobile/nativewind-env.d.ts +3 -0
- package/templates/production-fullstack/mobile/package.json +89 -0
- package/templates/production-fullstack/mobile/src/app/(auth)/_layout.tsx +12 -0
- package/templates/production-fullstack/mobile/src/app/(auth)/change-password.tsx +112 -0
- package/templates/production-fullstack/mobile/src/app/(auth)/edit-profile.tsx +160 -0
- package/templates/production-fullstack/mobile/src/app/(auth)/forgot-password.tsx +191 -0
- package/templates/production-fullstack/mobile/src/app/(auth)/login.tsx +253 -0
- package/templates/production-fullstack/mobile/src/app/_layout.tsx +102 -0
- package/templates/production-fullstack/mobile/src/app/global.css +82 -0
- package/templates/production-fullstack/mobile/src/components/common/AnimatedHeader.tsx +328 -0
- package/templates/production-fullstack/mobile/src/components/common/ConfirmationToast.tsx +67 -0
- package/templates/production-fullstack/mobile/src/components/common/Loading.tsx +26 -0
- package/templates/production-fullstack/mobile/src/components/common/LocationLoader.tsx +591 -0
- package/templates/production-fullstack/mobile/src/components/common/ScreenHeader.tsx +68 -0
- package/templates/production-fullstack/mobile/src/components/common/TabHeader.tsx +58 -0
- package/templates/production-fullstack/mobile/src/components/common/Typography.tsx +113 -0
- package/templates/production-fullstack/mobile/src/components/common/Welcome.tsx +55 -0
- package/templates/production-fullstack/mobile/src/components/ui/BottomModal.tsx +159 -0
- package/templates/production-fullstack/mobile/src/components/ui/ClassicTabBar.tsx +129 -0
- package/templates/production-fullstack/mobile/src/components/ui/CustomTabBar.tsx +238 -0
- package/templates/production-fullstack/mobile/src/components/ui/Sidebar.tsx +258 -0
- package/templates/production-fullstack/mobile/src/components/ui/buttons/Button.tsx +180 -0
- package/templates/production-fullstack/mobile/src/components/ui/buttons/ButtonGroup.tsx +32 -0
- package/templates/production-fullstack/mobile/src/components/ui/buttons/FloatingActionButton.tsx +72 -0
- package/templates/production-fullstack/mobile/src/components/ui/buttons/IconButton.tsx +84 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/Accordion.tsx +82 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/Avatar.tsx +47 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/Badge.tsx +104 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/Card.tsx +36 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/Image.tsx +43 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/ImageViewer.tsx +33 -0
- package/templates/production-fullstack/mobile/src/components/ui/data-display/SwipeableRow.tsx +94 -0
- package/templates/production-fullstack/mobile/src/components/ui/feedback/CircularProgress.tsx +38 -0
- package/templates/production-fullstack/mobile/src/components/ui/feedback/GestureWrapper.tsx +114 -0
- package/templates/production-fullstack/mobile/src/components/ui/feedback/ProgressBar.tsx +51 -0
- package/templates/production-fullstack/mobile/src/components/ui/feedback/Skeleton.tsx +84 -0
- package/templates/production-fullstack/mobile/src/components/ui/feedback/Spinner.tsx +50 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/Checkbox.tsx +54 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/DatePicker.tsx +186 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/ImagePickerModal.tsx +129 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/Input.tsx +158 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/LocationPicker.tsx +211 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/OTPInput.tsx +83 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/PasswordInput.tsx +16 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/Radio.tsx +54 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/SearchBar.tsx +53 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/Slider.tsx +49 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/Switch.tsx +75 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/TextArea.tsx +15 -0
- package/templates/production-fullstack/mobile/src/components/ui/inputs/WebLocationPicker.tsx +321 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Container.tsx +23 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Divider.tsx +20 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Grid.tsx +62 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/KeyboardAvoidingViewWrapper.tsx +16 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/ScrollContainer.tsx +21 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Section.tsx +51 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Spacer.tsx +6 -0
- package/templates/production-fullstack/mobile/src/components/ui/layout/Stack.tsx +34 -0
- package/templates/production-fullstack/mobile/src/components/ui/navigation/Pagination.tsx +61 -0
- package/templates/production-fullstack/mobile/src/components/ui/navigation/ProgressStepper.tsx +66 -0
- package/templates/production-fullstack/mobile/src/components/ui/navigation/Tabs.tsx +173 -0
- package/templates/production-fullstack/mobile/src/config/sidebar.config.ts +72 -0
- package/templates/production-fullstack/mobile/src/config/tabNavigation.ts +64 -0
- package/templates/production-fullstack/mobile/src/constants/Colors.ts +71 -0
- package/templates/production-fullstack/mobile/src/db/index.ts +9 -0
- package/templates/production-fullstack/mobile/src/db/schema.ts +14 -0
- package/templates/production-fullstack/mobile/src/features/auth/api/auth.service.ts +35 -0
- package/templates/production-fullstack/mobile/src/features/auth/store/useAuthStore.ts +273 -0
- package/templates/production-fullstack/mobile/src/features/auth/types/auth.type.ts +14 -0
- package/templates/production-fullstack/mobile/src/hooks/useDebounce.ts +17 -0
- package/templates/production-fullstack/mobile/src/lib/axios.ts +27 -0
- package/templates/production-fullstack/mobile/src/lib/query-client.ts +11 -0
- package/templates/production-fullstack/mobile/src/lib/socket.ts +36 -0
- package/templates/production-fullstack/mobile/src/lib/storage.ts +55 -0
- package/templates/production-fullstack/mobile/src/services/permission.service.ts +214 -0
- package/templates/production-fullstack/mobile/src/store/localStore.ts +7 -0
- package/templates/production-fullstack/mobile/src/store/useNotificationStore.ts +53 -0
- package/templates/production-fullstack/mobile/src/types/common.type.ts +6 -0
- package/templates/production-fullstack/mobile/src/types/images.d.ts +24 -0
- package/templates/production-fullstack/mobile/src/utils/toast.ts +26 -0
- package/templates/production-fullstack/mobile/tailwind.config.js +71 -0
- package/templates/production-fullstack/mobile/tsconfig.json +23 -0
- package/templates/production-fullstack/server/.env.example +63 -0
- package/templates/production-fullstack/server/README.md +75 -0
- package/templates/production-fullstack/server/_gitignore +24 -0
- package/templates/production-fullstack/server/eslint.config.js +13 -0
- package/templates/production-fullstack/server/package.json +58 -0
- package/templates/production-fullstack/server/prisma/schema/core/attachment.prisma +14 -0
- package/templates/production-fullstack/server/prisma/schema/core/notification.prisma +18 -0
- package/templates/production-fullstack/server/prisma/schema/core/permission.prisma +26 -0
- package/templates/production-fullstack/server/prisma/schema/core/role.prisma +25 -0
- package/templates/production-fullstack/server/prisma/schema/core/user.prisma +56 -0
- package/templates/production-fullstack/server/prisma/schema/enums/common.prisma +13 -0
- package/templates/production-fullstack/server/prisma/schema/enums/notification.prisma +6 -0
- package/templates/production-fullstack/server/prisma/schema/enums/user.prisma +11 -0
- package/templates/production-fullstack/server/prisma/schema/schema.prisma +7 -0
- package/templates/production-fullstack/server/prisma.config.ts +14 -0
- package/templates/production-fullstack/server/src/app.ts +36 -0
- package/templates/production-fullstack/server/src/common/middlewares/auth.middleware.ts +45 -0
- package/templates/production-fullstack/server/src/common/middlewares/errorHandler.ts +16 -0
- package/templates/production-fullstack/server/src/common/middlewares/multer.ts +20 -0
- package/templates/production-fullstack/server/src/common/middlewares/rateLimiter.ts +53 -0
- package/templates/production-fullstack/server/src/common/services/email.service.ts +28 -0
- package/templates/production-fullstack/server/src/common/services/push.service.ts +65 -0
- package/templates/production-fullstack/server/src/common/services/storage.service.ts +9 -0
- package/templates/production-fullstack/server/src/common/types/express.d.ts +10 -0
- package/templates/production-fullstack/server/src/common/utils/cloudinaryUpload.ts +44 -0
- package/templates/production-fullstack/server/src/common/utils/emailOtp.ts +30 -0
- package/templates/production-fullstack/server/src/common/utils/genOtpToken.ts +22 -0
- package/templates/production-fullstack/server/src/common/utils/generateVapidKeys.ts +12 -0
- package/templates/production-fullstack/server/src/common/utils/jwt.ts +27 -0
- package/templates/production-fullstack/server/src/common/utils/pushHelper.ts +22 -0
- package/templates/production-fullstack/server/src/config/env.ts +2 -0
- package/templates/production-fullstack/server/src/config/logger.ts +58 -0
- package/templates/production-fullstack/server/src/config/prisma.ts +26 -0
- package/templates/production-fullstack/server/src/features/attachments/upload.controller.ts +22 -0
- package/templates/production-fullstack/server/src/features/attachments/upload.routes.ts +11 -0
- package/templates/production-fullstack/server/src/features/auth/auth.controller.ts +124 -0
- package/templates/production-fullstack/server/src/features/auth/auth.routes.ts +22 -0
- package/templates/production-fullstack/server/src/features/auth/auth.service.ts +155 -0
- package/templates/production-fullstack/server/src/features/notifications/push.controller.ts +55 -0
- package/templates/production-fullstack/server/src/features/notifications/push.routes.ts +11 -0
- package/templates/production-fullstack/server/src/index.ts +17 -0
- package/templates/production-fullstack/server/src/routes/index.ts +12 -0
- package/templates/production-fullstack/server/src/sockets/auth.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/connection.ts +31 -0
- package/templates/production-fullstack/server/src/sockets/emitters/assignment.emitter.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/emitters/attendance.emitter.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/emitters/exam.emitter.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/emitters/notification.emitter.ts +17 -0
- package/templates/production-fullstack/server/src/sockets/events.ts +27 -0
- package/templates/production-fullstack/server/src/sockets/handlers/attendance.handler.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/handlers/chat.handler.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/handlers/index.ts +15 -0
- package/templates/production-fullstack/server/src/sockets/handlers/lms.handler.ts +0 -0
- package/templates/production-fullstack/server/src/sockets/handlers/notification.handler.ts +39 -0
- package/templates/production-fullstack/server/src/sockets/index.ts +39 -0
- package/templates/production-fullstack/server/src/sockets/middleware.ts +54 -0
- package/templates/production-fullstack/server/src/sockets/rooms.ts +11 -0
- package/templates/production-fullstack/server/src/sockets/types.ts +32 -0
- package/templates/production-fullstack/server/tsconfig.json +14 -0
- package/templates/react/src/assets/animations/loading.json +1 -0
- package/templates/react-native/_gitignore +43 -0
- package/templates/react-native/package.json +2 -1
- package/templates/react-native/src/app/(auth)/edit-profile.tsx +11 -15
- package/templates/react-native/src/app/(tabs)/dashboard.tsx +2 -2
- package/templates/react-native/src/app/(tabs)/search.tsx +2 -2
- package/templates/react-native/src/config/sidebar.config.ts +0 -60
- package/templates/react-native/src/config/tabNavigation.ts +6 -36
- package/templates/react-native/src/services/notification.service.ts +22 -0
- package/templates/react-native/src/store/useNotificationStore.ts +158 -33
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { getSocket } from '../lib/socket';
|
|
3
|
+
import * as Notifications from 'expo-notifications';
|
|
4
|
+
|
|
5
|
+
export interface NotificationState {
|
|
6
|
+
notifications: any[];
|
|
7
|
+
pushToken: string | null;
|
|
8
|
+
listenForSocketEvents: () => void;
|
|
9
|
+
registerForPushNotificationsAsync: () => Promise<void>;
|
|
10
|
+
fetchNotifications: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useNotificationStore = create<NotificationState>((set, get) => ({
|
|
14
|
+
notifications: [],
|
|
15
|
+
pushToken: null,
|
|
16
|
+
|
|
17
|
+
listenForSocketEvents: () => {
|
|
18
|
+
const socket = getSocket();
|
|
19
|
+
if (!socket) return;
|
|
20
|
+
|
|
21
|
+
socket.on('new_notification', (data) => {
|
|
22
|
+
set((state) => ({ notifications: [data, ...state.notifications] }));
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
registerForPushNotificationsAsync: async () => {
|
|
27
|
+
try {
|
|
28
|
+
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
|
29
|
+
let finalStatus = existingStatus;
|
|
30
|
+
if (existingStatus !== 'granted') {
|
|
31
|
+
const { status } = await Notifications.requestPermissionsAsync();
|
|
32
|
+
finalStatus = status;
|
|
33
|
+
}
|
|
34
|
+
if (finalStatus !== 'granted') {
|
|
35
|
+
console.log('Failed to get push token for push notification!');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Note: projectId is required for Expo Go and EAS.
|
|
39
|
+
const token = (await Notifications.getExpoPushTokenAsync()).data;
|
|
40
|
+
set({ pushToken: token });
|
|
41
|
+
|
|
42
|
+
// Here you would typically send the pushToken to your backend
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.warn("Failed to register for push notifications", e);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
fetchNotifications: async () => {
|
|
49
|
+
// API call to fetch notifications could go here
|
|
50
|
+
// e.g., const data = await api.get('/notifications');
|
|
51
|
+
set({ notifications: [] });
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare module "*.png" {
|
|
2
|
+
const value: any;
|
|
3
|
+
export default value;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
declare module "*.jpg" {
|
|
7
|
+
const value: any;
|
|
8
|
+
export default value;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module "*.jpeg" {
|
|
12
|
+
const value: any;
|
|
13
|
+
export default value;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare module "*.gif" {
|
|
17
|
+
const value: any;
|
|
18
|
+
export default value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare module "*.svg" {
|
|
22
|
+
const value: any;
|
|
23
|
+
export default value;
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// utils/toast.ts
|
|
2
|
+
|
|
3
|
+
import Toast from "react-native-toast-message";
|
|
4
|
+
|
|
5
|
+
export const toast = {
|
|
6
|
+
success: (title: string, message?: string) =>
|
|
7
|
+
Toast.show({
|
|
8
|
+
type: "success",
|
|
9
|
+
text1: title,
|
|
10
|
+
text2: message,
|
|
11
|
+
}),
|
|
12
|
+
|
|
13
|
+
error: (title: string, message?: string) =>
|
|
14
|
+
Toast.show({
|
|
15
|
+
type: "error",
|
|
16
|
+
text1: title,
|
|
17
|
+
text2: message,
|
|
18
|
+
}),
|
|
19
|
+
|
|
20
|
+
info: (title: string, message?: string) =>
|
|
21
|
+
Toast.show({
|
|
22
|
+
type: "info",
|
|
23
|
+
text1: title,
|
|
24
|
+
text2: message,
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
darkMode: "class",
|
|
4
|
+
content: ["./src/app/**/*.{js,jsx,ts,tsx}", "./src/components/**/*.{js,jsx,ts,tsx}"],
|
|
5
|
+
presets: [require("nativewind/preset")],
|
|
6
|
+
theme: {
|
|
7
|
+
extend: {
|
|
8
|
+
keyframes: {
|
|
9
|
+
bounce: {
|
|
10
|
+
"0%, 100%": {
|
|
11
|
+
transform: "translateY(-25%)",
|
|
12
|
+
animationTimingFunction: "cubic-bezier(0.8,0,1,1)",
|
|
13
|
+
},
|
|
14
|
+
"50%": {
|
|
15
|
+
transform: "translateY(0)",
|
|
16
|
+
animationTimingFunction: "cubic-bezier(0,0,0.2,1)",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
floatUp: {
|
|
20
|
+
"0%": { transform: "translateY(50%)", opacity: "0" },
|
|
21
|
+
"50%": { transform: "translateY(-50%)", opacity: "1" },
|
|
22
|
+
"100%": { transform: "translateY(-100%)", opacity: "0" },
|
|
23
|
+
},
|
|
24
|
+
dice: {
|
|
25
|
+
"0%": { transform: "rotate(0deg)"},
|
|
26
|
+
"100%": { transform: "rotate(360deg)" },
|
|
27
|
+
},
|
|
28
|
+
flip: {
|
|
29
|
+
"0%": { transform: "rotatey(0deg)"},
|
|
30
|
+
"100%": { transform: "rotatey(360deg)" },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
animation: {
|
|
34
|
+
bounce: "bounce 1s infinite",
|
|
35
|
+
"float-up": "floatUp 2s ease-in-out forwards",
|
|
36
|
+
"dice1": "dice 0.3s ease-in-out forwards infinite",
|
|
37
|
+
"dice2": "dice 0.3s ease-in-out forwards infinite",
|
|
38
|
+
"flip": "dice 0.8s ease-in-out forwards infinite",
|
|
39
|
+
},
|
|
40
|
+
colors: {
|
|
41
|
+
base: {
|
|
42
|
+
100: "rgb(var(--color-base-100) / <alpha-value>)",
|
|
43
|
+
200: "rgb(var(--color-base-200) / <alpha-value>)",
|
|
44
|
+
300: "rgb(var(--color-base-300) / <alpha-value>)",
|
|
45
|
+
content: "rgb(var(--color-base-content) / <alpha-value>)",
|
|
46
|
+
},
|
|
47
|
+
primary: {
|
|
48
|
+
DEFAULT: "rgb(var(--color-primary) / <alpha-value>)",
|
|
49
|
+
content: "rgb(var(--color-primary-content) / <alpha-value>)",
|
|
50
|
+
},
|
|
51
|
+
secondary: {
|
|
52
|
+
DEFAULT: "rgb(var(--color-secondary) / <alpha-value>)",
|
|
53
|
+
content: "rgb(var(--color-secondary-content) / <alpha-value>)",
|
|
54
|
+
},
|
|
55
|
+
accent: {
|
|
56
|
+
DEFAULT: "rgb(var(--color-accent) / <alpha-value>)",
|
|
57
|
+
content: "rgb(var(--color-accent-content) / <alpha-value>)",
|
|
58
|
+
},
|
|
59
|
+
neutral: {
|
|
60
|
+
DEFAULT: "rgb(var(--color-neutral) / <alpha-value>)",
|
|
61
|
+
content: "rgb(var(--color-neutral-content) / <alpha-value>)",
|
|
62
|
+
},
|
|
63
|
+
info: "rgb(var(--color-info) / <alpha-value>)",
|
|
64
|
+
success: "rgb(var(--color-success) / <alpha-value>)",
|
|
65
|
+
warning: "rgb(var(--color-warning) / <alpha-value>)",
|
|
66
|
+
error: "rgb(var(--color-error) / <alpha-value>)",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
plugins: [],
|
|
71
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "expo/tsconfig.base",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsx": "react-jsx",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"noImplicitAny": false,
|
|
7
|
+
"paths": {
|
|
8
|
+
"@/*": [
|
|
9
|
+
"./src/*"
|
|
10
|
+
],
|
|
11
|
+
"@/assets/*": [
|
|
12
|
+
"./assets/*"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"**/*.ts",
|
|
18
|
+
"**/*.tsx",
|
|
19
|
+
".expo/types/**/*.ts",
|
|
20
|
+
"expo-env.d.ts",
|
|
21
|
+
"nativewind-env.d.ts"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ==========================
|
|
2
|
+
# Application
|
|
3
|
+
# ==========================
|
|
4
|
+
NODE_ENV=development
|
|
5
|
+
PORT=5000
|
|
6
|
+
|
|
7
|
+
APP_NAME=My App
|
|
8
|
+
APP_URL=http://localhost:5173
|
|
9
|
+
APP_EMAIL=noreply@example.com
|
|
10
|
+
APP_PRIMARY_COLOR=#2563eb
|
|
11
|
+
|
|
12
|
+
# ==========================
|
|
13
|
+
# Database
|
|
14
|
+
# ==========================
|
|
15
|
+
|
|
16
|
+
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
|
|
17
|
+
|
|
18
|
+
# ==========================
|
|
19
|
+
# JWT
|
|
20
|
+
# ==========================
|
|
21
|
+
JWT_SECRET=
|
|
22
|
+
JWT_EXPIRES_IN=7d
|
|
23
|
+
|
|
24
|
+
# ==========================
|
|
25
|
+
# Cloudinary
|
|
26
|
+
# ==========================
|
|
27
|
+
CLOUDINARY_CLOUD_NAME=
|
|
28
|
+
CLOUDINARY_API_KEY=
|
|
29
|
+
CLOUDINARY_API_SECRET=
|
|
30
|
+
|
|
31
|
+
# ==========================
|
|
32
|
+
# Email (SMTP)
|
|
33
|
+
# ==========================
|
|
34
|
+
SMTP_HOST=smtp.gmail.com
|
|
35
|
+
SMTP_PORT=587
|
|
36
|
+
SMTP_SECURE=false
|
|
37
|
+
SMTP_USER=
|
|
38
|
+
SMTP_PASS=
|
|
39
|
+
SMTP_FROM="My App <noreply@example.com>"
|
|
40
|
+
|
|
41
|
+
# ==========================
|
|
42
|
+
# CORS
|
|
43
|
+
# ==========================
|
|
44
|
+
CLIENT_URL=http://localhost:5173
|
|
45
|
+
|
|
46
|
+
# ==========================
|
|
47
|
+
# Cookie
|
|
48
|
+
# ==========================
|
|
49
|
+
COOKIE_NAME=token
|
|
50
|
+
COOKIE_EXPIRES_IN=7d
|
|
51
|
+
|
|
52
|
+
# ==========================
|
|
53
|
+
# Rate Limiting
|
|
54
|
+
# ==========================
|
|
55
|
+
RATE_LIMIT_WINDOW=15
|
|
56
|
+
RATE_LIMIT_MAX=100
|
|
57
|
+
|
|
58
|
+
# ==========================
|
|
59
|
+
# Rate Limiting
|
|
60
|
+
# ==========================
|
|
61
|
+
VAPID_PRIVATE_KEY=
|
|
62
|
+
VAPID_PUBLIC_KEY=
|
|
63
|
+
VAPID_SUBJECT=mailto:noreply@example.com
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Node.js TypeScript Prisma Backend Boilerplate
|
|
2
|
+
|
|
3
|
+
A production-ready, strongly-typed Node.js & Express boilerplate project with best-practice architectures, modular routing, Prisma ORM, and TSX engine compilation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ⚙️ **Modular Architecture:** Express application setup decoupled into `app.ts` (middleware + router wiring) and `index.ts` (server initialization & db connection).
|
|
8
|
+
- 🗄️ **Prisma ORM:** Built-in PostgreSQL datasource configuration and schema mapping for `User`, `Otp`, and `PushSubscription` models.
|
|
9
|
+
- 📝 **Colorized Logging:** Zero-dependency custom logger with timestamped success, warning, info, and error layouts.
|
|
10
|
+
- 🛡️ **Security Out-of-the-Box:** Pre-configured with Helmet headers, CORS policies, and global rate limiters (`apiLimiter`, `authLimiter`, `uploadLimiter`).
|
|
11
|
+
- 🔑 **Authentication & JWT:** Custom middlewares for route protection, sign-ups, and log-ins with HTTP-only cookie-based tokens.
|
|
12
|
+
- 📧 **SMTP Mailer & OTP:** Standard mailer transport using Gmail NodeMailer wrapper, integrated with an OTP generator and email template.
|
|
13
|
+
- 🖼️ **File Uploads:** Cloudinary integration utilizing Multer memory buffers for secure, single or multi-file uploads.
|
|
14
|
+
- 🔌 **Socket.io Setup:** Pre-installed Socket.io hooks mapping connected user sessions to active sockets.
|
|
15
|
+
- ✉️ **Web Push:** Push notifications integration powered by VAPID key generators and web-push subscriptions.
|
|
16
|
+
- 📦 **TSX Engine:** Fast TS runner with native ESM specifier resolution support.
|
|
17
|
+
|
|
18
|
+
## Getting Started
|
|
19
|
+
|
|
20
|
+
### 1. Configure Environment Variables
|
|
21
|
+
|
|
22
|
+
Create a `.env` file in the root directory (based on `.env.example`):
|
|
23
|
+
|
|
24
|
+
```env
|
|
25
|
+
PORT=5002
|
|
26
|
+
JWT_SECRET=your_super_secret_jwt_key
|
|
27
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/db_name
|
|
28
|
+
|
|
29
|
+
# Cloudinary
|
|
30
|
+
CLOUDINARY_CLOUD_NAME=your_cloud_name
|
|
31
|
+
CLOUDINARY_API_KEY=your_api_key
|
|
32
|
+
CLOUDINARY_API_SECRET=your_api_secret
|
|
33
|
+
|
|
34
|
+
# SMTP Settings
|
|
35
|
+
SMTP_USER=your_email@gmail.com
|
|
36
|
+
SMTP_PASS=your_app_password
|
|
37
|
+
|
|
38
|
+
# Web Push
|
|
39
|
+
VAPID_SUBJECT=mailto:your_email@example.com
|
|
40
|
+
VAPID_PUBLIC_KEY=your_vapid_public_key
|
|
41
|
+
VAPID_PRIVATE_KEY=your_vapid_private_key
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Install & Sync Schema
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install dependencies
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Push database schema changes locally
|
|
51
|
+
npm run db:push
|
|
52
|
+
|
|
53
|
+
# Generate Prisma Client types
|
|
54
|
+
npm run db:generate
|
|
55
|
+
|
|
56
|
+
# Start development server with reload (via tsx)
|
|
57
|
+
npm run dev
|
|
58
|
+
|
|
59
|
+
# Build the project to JS
|
|
60
|
+
npm run build
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## API Endpoints
|
|
64
|
+
|
|
65
|
+
### Auth Routes (`/api/auth`)
|
|
66
|
+
|
|
67
|
+
- `POST /signup` - Registers a new user session
|
|
68
|
+
- `POST /login` - Log in user and write token cookie
|
|
69
|
+
- `POST /logout` - Clear token session cookies
|
|
70
|
+
- `GET /me` - Returns logged-in user profile (requires auth)
|
|
71
|
+
- `PUT /me` - Edit profile info and upload avatars (requires auth)
|
|
72
|
+
|
|
73
|
+
### Upload Routes (`/api/upload`)
|
|
74
|
+
|
|
75
|
+
- `POST /` - Securely uploads image/file to Cloudinary (requires auth)
|
|
@@ -0,0 +1,24 @@
|
|
|
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?
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
|
|
4
|
+
export default tseslint.config(
|
|
5
|
+
eslint.configs.recommended,
|
|
6
|
+
...tseslint.configs.recommended,
|
|
7
|
+
{
|
|
8
|
+
rules: {
|
|
9
|
+
'no-console': 'error',
|
|
10
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "src/index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "tsx src/index.ts",
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"db:push": "prisma db push",
|
|
11
|
+
"db:generate": "prisma generate",
|
|
12
|
+
"generate:vapid": "node ./src/utils/generateVapidKeys.js",
|
|
13
|
+
"lint": "eslint src/**/*.ts"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@prisma/adapter-pg": "^7.9.1",
|
|
17
|
+
"@prisma/client": "^7.9.1",
|
|
18
|
+
"@prisma/config": "^7.9.1",
|
|
19
|
+
"bcrypt": "^5.1.1",
|
|
20
|
+
"cloudinary": "^2.0.0",
|
|
21
|
+
"compression": "^1.7.4",
|
|
22
|
+
"cookie-parser": "^1.4.6",
|
|
23
|
+
"cors": "^2.8.5",
|
|
24
|
+
"dotenv": "^16.3.1",
|
|
25
|
+
"expo-server-sdk": "^3.11.0",
|
|
26
|
+
"express": "^4.18.2",
|
|
27
|
+
"express-rate-limit": "^7.1.4",
|
|
28
|
+
"helmet": "^7.1.0",
|
|
29
|
+
"jsonwebtoken": "^9.0.2",
|
|
30
|
+
"morgan": "^1.10.0",
|
|
31
|
+
"multer": "^1.4.5-lts.1",
|
|
32
|
+
"nodemailer": "^6.9.7",
|
|
33
|
+
"pg": "^8.22.0",
|
|
34
|
+
"socket.io": "^4.7.2",
|
|
35
|
+
"web-push": "^3.6.6"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^10.0.1",
|
|
39
|
+
"@types/bcrypt": "^5.0.2",
|
|
40
|
+
"@types/compression": "^1.7.5",
|
|
41
|
+
"@types/cookie-parser": "^1.4.6",
|
|
42
|
+
"@types/cors": "^2.8.17",
|
|
43
|
+
"@types/express": "^4.17.21",
|
|
44
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
45
|
+
"@types/morgan": "^1.9.9",
|
|
46
|
+
"@types/multer": "^1.4.11",
|
|
47
|
+
"@types/node": "^20.9.0",
|
|
48
|
+
"@types/nodemailer": "^6.4.14",
|
|
49
|
+
"@types/web-push": "^3.6.3",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^8.66.0",
|
|
51
|
+
"@typescript-eslint/parser": "^8.66.0",
|
|
52
|
+
"eslint": "^10.8.0",
|
|
53
|
+
"prisma": "^7.9.1",
|
|
54
|
+
"tsx": "^4.23.1",
|
|
55
|
+
"typescript": "^5.2.2",
|
|
56
|
+
"typescript-eslint": "^8.66.0"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
model Attachment {
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
provider StorageProvider
|
|
4
|
+
publicId String // Cloudinary public_id, S3 key, or local path
|
|
5
|
+
url String
|
|
6
|
+
fileName String
|
|
7
|
+
mimeType String
|
|
8
|
+
extension String
|
|
9
|
+
size Int // File size in bytes
|
|
10
|
+
type AttachmentType
|
|
11
|
+
createdAt DateTime @default(now())
|
|
12
|
+
updatedAt DateTime @updatedAt
|
|
13
|
+
deletedAt DateTime?
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
model Notification {
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
userId String
|
|
4
|
+
title String
|
|
5
|
+
message String
|
|
6
|
+
type NotificationType
|
|
7
|
+
actionUrl String?
|
|
8
|
+
metadata Json?
|
|
9
|
+
isRead Boolean @default(false)
|
|
10
|
+
createdAt DateTime @default(now())
|
|
11
|
+
updatedAt DateTime @updatedAt
|
|
12
|
+
deletedAt DateTime?
|
|
13
|
+
|
|
14
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
15
|
+
|
|
16
|
+
@@index([userId])
|
|
17
|
+
@@index([isRead])
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
model Permission {
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
action String // e.g., "CREATE_USER", "VIEW_REPORTS"
|
|
4
|
+
module String // e.g., "USER_MANAGEMENT", "FINANCE"
|
|
5
|
+
description String?
|
|
6
|
+
createdAt DateTime @default(now())
|
|
7
|
+
updatedAt DateTime @updatedAt
|
|
8
|
+
|
|
9
|
+
roles RolePermission[]
|
|
10
|
+
|
|
11
|
+
@@unique([action])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
model RolePermission {
|
|
15
|
+
id String @id @default(uuid())
|
|
16
|
+
roleId String
|
|
17
|
+
permissionId String
|
|
18
|
+
createdAt DateTime @default(now())
|
|
19
|
+
|
|
20
|
+
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
21
|
+
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
|
|
22
|
+
|
|
23
|
+
@@unique([roleId, permissionId])
|
|
24
|
+
@@index([roleId])
|
|
25
|
+
@@index([permissionId])
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
model Role {
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
name String @unique
|
|
4
|
+
description String?
|
|
5
|
+
createdAt DateTime @default(now())
|
|
6
|
+
updatedAt DateTime @updatedAt
|
|
7
|
+
deletedAt DateTime?
|
|
8
|
+
|
|
9
|
+
permissions RolePermission[]
|
|
10
|
+
users UserRole[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
model UserRole {
|
|
14
|
+
id String @id @default(uuid())
|
|
15
|
+
userId String
|
|
16
|
+
roleId String
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
|
|
19
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
20
|
+
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
|
21
|
+
|
|
22
|
+
@@unique([userId, roleId])
|
|
23
|
+
@@index([userId])
|
|
24
|
+
@@index([roleId])
|
|
25
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
model User {
|
|
2
|
+
id String @id @default(uuid())
|
|
3
|
+
email String @unique
|
|
4
|
+
password String
|
|
5
|
+
phone String?
|
|
6
|
+
firstName String
|
|
7
|
+
lastName String
|
|
8
|
+
avatar String?
|
|
9
|
+
status UserStatus @default(ACTIVE)
|
|
10
|
+
emailVerified Boolean @default(false)
|
|
11
|
+
lastLogin DateTime?
|
|
12
|
+
createdAt DateTime @default(now())
|
|
13
|
+
updatedAt DateTime @updatedAt
|
|
14
|
+
deletedAt DateTime?
|
|
15
|
+
|
|
16
|
+
// Relations
|
|
17
|
+
roles UserRole[]
|
|
18
|
+
pushSubscriptions PushSubscription[]
|
|
19
|
+
notifications Notification[]
|
|
20
|
+
|
|
21
|
+
@@index([email])
|
|
22
|
+
@@index([status])
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
model Otp {
|
|
26
|
+
id String @id @default(uuid())
|
|
27
|
+
identifier String // Can be email or phone
|
|
28
|
+
otp String
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
createdAt DateTime @default(now())
|
|
31
|
+
|
|
32
|
+
@@index([identifier])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
model PushSubscription {
|
|
36
|
+
id String @id @default(uuid())
|
|
37
|
+
type PushSubscriptionType @default(WEB)
|
|
38
|
+
|
|
39
|
+
// For Web Push
|
|
40
|
+
endpoint String?
|
|
41
|
+
keys Json?
|
|
42
|
+
|
|
43
|
+
// For Expo
|
|
44
|
+
token String?
|
|
45
|
+
|
|
46
|
+
userId String
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
|
|
49
|
+
createdAt DateTime @default(now())
|
|
50
|
+
updatedAt DateTime @updatedAt
|
|
51
|
+
deletedAt DateTime?
|
|
52
|
+
|
|
53
|
+
@@index([userId])
|
|
54
|
+
@@index([token])
|
|
55
|
+
@@index([endpoint])
|
|
56
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { defineConfig } from '@prisma/config'
|
|
3
|
+
import 'dotenv/config'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
schema: 'prisma/schema',
|
|
7
|
+
migrations: {
|
|
8
|
+
path: 'prisma/migrations',
|
|
9
|
+
seed: 'npx tsx prisma/seed.ts',
|
|
10
|
+
},
|
|
11
|
+
datasource: {
|
|
12
|
+
url: process.env.DATABASE_URL,
|
|
13
|
+
},
|
|
14
|
+
})
|