diff --git a/apps/backend/src/trpc/user-apis/user.ts b/apps/backend/src/trpc/user-apis/user.ts index 1d7de74..6ef72dd 100644 --- a/apps/backend/src/trpc/user-apis/user.ts +++ b/apps/backend/src/trpc/user-apis/user.ts @@ -1,8 +1,9 @@ import { router, protectedProcedure } from '../trpc-index'; import jwt from 'jsonwebtoken'; -import { eq } from 'drizzle-orm'; +import { eq, and } from 'drizzle-orm'; +import { z } from 'zod'; import { db } from '../../db/db_index'; -import { users, userDetails, userCreds } from '../../db/schema'; +import { users, userDetails, userCreds, notifCreds } from '../../db/schema'; import { ApiError } from '../../lib/api-error'; import { jwtSecret } from 'src/lib/env-exporter'; import { generateSignedUrlFromS3Url } from '../../lib/s3-client'; @@ -107,4 +108,40 @@ export const userRouter = router({ isComplete: !!(user.name && user.email && creds), }; }), + + savePushToken: protectedProcedure + .input(z.object({ token: z.string() })) + .mutation(async ({ input, ctx }) => { + const userId = ctx.user.userId; + const { token } = input; + + if (!userId) { + throw new ApiError('User not authenticated', 401); + } + + // Check if this exact token already exists for this user + const existing = await db.query.notifCreds.findFirst({ + where: and( + eq(notifCreds.userId, userId), + eq(notifCreds.token, token) + ), + }); + + if (existing) { + // Update lastVerified timestamp + await db + .update(notifCreds) + .set({ lastVerified: new Date() }) + .where(eq(notifCreds.id, existing.id)); + } else { + // Insert new token + await db.insert(notifCreds).values({ + userId, + token, + lastVerified: new Date(), + }); + } + + return { success: true }; + }), }); \ No newline at end of file diff --git a/apps/user-ui/app/_layout.tsx b/apps/user-ui/app/_layout.tsx index e064c6a..cf34719 100755 --- a/apps/user-ui/app/_layout.tsx +++ b/apps/user-ui/app/_layout.tsx @@ -27,6 +27,7 @@ import WebViewWrapper from "@/components/WebViewWrapper"; import BackHandlerWrapper from "@/components/BackHandler"; import AddToCartDialog from "@/src/components/AddToCartDialog"; import React from "react"; +import NotifChecker from "@/services/notif-service/notif-checker"; export default function RootLayout() { const colorScheme = useColorScheme(); @@ -57,7 +58,8 @@ export default function RootLayout() { - + + diff --git a/apps/user-ui/services/notif-service/notif-checker.tsx b/apps/user-ui/services/notif-service/notif-checker.tsx index b9cc93d..ab309ad 100755 --- a/apps/user-ui/services/notif-service/notif-checker.tsx +++ b/apps/user-ui/services/notif-service/notif-checker.tsx @@ -5,7 +5,8 @@ import { MyText } from "common-ui"; import { View, Linking } from "react-native"; import { tw } from "common-ui"; import { MyButton } from "common-ui"; -import { useAuth } from "@/components/context/auth-context"; +import { useAuth } from "@/src/contexts/AuthContext"; +import { trpc } from "@/src/trpc-client"; interface Props {} @@ -13,17 +14,22 @@ function NotifChecker(props: Props) { const {} = props; const [showPermissionDialog, setShowPermissionDialog] = React.useState(false); - const {isLoggedIn} = useAuth(); - // const { data: hasPushToken, isLoading, isError } = useHasPushToken({enabled: isLoggedIn}); - const hasPushToken = false; - // const { mutate: addPushToken } = useAddPushToken(); - const addPushToken = (input:any) => {}; + const { isAuthenticated } = useAuth(); + const savePushTokenMutation = trpc.user.user.savePushToken.useMutation(); const { notifPermission, expoPushToken } = useNotification(); + React.useEffect(() => { - if(isLoggedIn && !hasPushToken && notifPermission =='granted') { - addPushToken(expoPushToken!); + if (isAuthenticated && expoPushToken && notifPermission === 'granted') { + savePushTokenMutation.mutate( + { token: expoPushToken }, + { + onError: (error) => { + console.error('Failed to save push token:', error); + }, + } + ); } - },[isLoggedIn, hasPushToken]) + }, [isAuthenticated, expoPushToken, notifPermission]); React.useEffect(() => { if (notifPermission === "denied") {