fix: exclude mobile/ from the web app's TypeScript checking and Docker build

Next.js's production build type-checks the whole repo by tsconfig.json's
default include glob, which picked up mobile/'s .tsx files once the
Docker image's git checkout finally included mobile/ (first pull to
include it) — none of mobile's own dependencies (react-native, expo-router,
...) are installed in that container, so the build failed outright.
mobile/ is now excluded from tsconfig.json and .dockerignore; it's a
separate app with its own tsconfig/package.json and was never meant to be
type-checked or shipped as part of the web image.

Also completes the mobile EAS/FCM push setup (app.json's extra.eas.projectId
and googleServicesFile, google-services.json gitignored) and adds a 15s
timeout around getExpoPushTokenAsync so a device that can't reach FCM fails
visibly instead of hanging silently forever.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-06 14:07:27 +02:00
1 parent a3f19ff70f
commit d3bf94799e
5 files changed
+36 -6

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
node_modules
scaffold-tmp
mobile
.next
.git
.gitignore
+4
View File
@@ -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
+13 -2
View File
@@ -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"
}
}
+17 -3
View File
@@ -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<never>((_, 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);
+1 -1
View File
@@ -30,5 +30,5 @@
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
"exclude": ["node_modules", "mobile"]
}