diff --git a/.dockerignore b/.dockerignore index 638b55d..cffdbb4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ node_modules scaffold-tmp +mobile .next .git .gitignore diff --git a/mobile/.gitignore b/mobile/.gitignore index 60db44a..4701d6f 100644 --- a/mobile/.gitignore +++ b/mobile/.gitignore @@ -37,6 +37,10 @@ yarn-error.* .env* !.env.example +# Firebase (FCM push credentials) — project-specific, redownload from +# Firebase Console (org.pawfeed.app app) on a fresh clone instead of committing +google-services.json + # typescript *.tsbuildinfo diff --git a/mobile/app.json b/mobile/app.json index d25f4f6..9adbcf0 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -14,13 +14,17 @@ }, "android": { "package": "org.pawfeed.app", + "googleServicesFile": "./google-services.json", "adaptiveIcon": { "backgroundColor": "#fafafa", "foregroundImage": "./assets/android-icon-foreground.png", "backgroundImage": "./assets/android-icon-background.png", "monochromeImage": "./assets/android-icon-monochrome.png" }, - "predictiveBackGestureEnabled": false + "predictiveBackGestureEnabled": false, + "permissions": [ + "android.permission.RECORD_AUDIO" + ] }, "web": { "favicon": "./assets/favicon.png" @@ -47,6 +51,13 @@ "color": "#f97316" } ] - ] + ], + "extra": { + "router": {}, + "eas": { + "projectId": "e56a076a-08a2-4e4e-afa0-dfc611fba536" + } + }, + "owner": "pawfeed" } } diff --git a/mobile/src/hooks/usePushNotifications.ts b/mobile/src/hooks/usePushNotifications.ts index 4b5541e..98544a8 100644 --- a/mobile/src/hooks/usePushNotifications.ts +++ b/mobile/src/hooks/usePushNotifications.ts @@ -24,14 +24,19 @@ Notifications.setNotificationHandler({ * * Minting a real token needs an EAS project id (app.json's * extra.eas.projectId, set once via `eas init` — a free step, no EAS Build - * required). Until that's set up, this no-ops with a console warning rather + * required) plus FCM credentials (app.json's googleServicesFile) for + * Android. Until both are set up, this no-ops with a console warning rather * than crashing: push delivery is best-effort everywhere else in this stack * (a missing/expired token just means notify.ts silently skips the push). */ export function usePushNotifications(): void { const trpc = useTRPC(); const { isSignedIn } = useAuth(); - const registerMutation = useMutation(trpc.owner.registerPushToken.mutationOptions()); + const registerMutation = useMutation( + trpc.owner.registerPushToken.mutationOptions({ + onError: (err) => console.warn("[push] registerPushToken failed", err), + }) + ); useEffect(() => { if (!isSignedIn || Platform.OS === "web") return; @@ -57,7 +62,16 @@ export function usePushNotifications(): void { } try { - const { data: token } = await Notifications.getExpoPushTokenAsync({ projectId }); + // getExpoPushTokenAsync can hang indefinitely if the device can't + // reach Google's FCM registration backend (seen on some emulators + // without working Play Services network access) — a timeout turns + // that into a visible failure instead of permanent silence. + const { data: token } = await Promise.race([ + Notifications.getExpoPushTokenAsync({ projectId }), + new Promise((_, reject) => + setTimeout(() => reject(new Error("Timed out after 15s")), 15000) + ), + ]); if (!cancelled) registerMutation.mutate({ expoPushToken: token }); } catch (err) { console.warn("[push] Failed to get Expo push token", err); diff --git a/tsconfig.json b/tsconfig.json index cf9c65d..99a302a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -30,5 +30,5 @@ ".next/dev/types/**/*.ts", "**/*.mts" ], - "exclude": ["node_modules"] + "exclude": ["node_modules", "mobile"] }