From 83839a0cd74de2f784fc827aff580479f4b6b89b Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Thu, 12 Mar 2026 19:39:54 -0400 Subject: [PATCH] Add @sofa/native Expo React Native app (#7) --- .dockerignore | 1 + .github/workflows/eas-build.yml | 51 + .github/workflows/eas-submit.yml | 39 + .github/workflows/eas-update.yml | 33 + .github/workflows/test.yml | 4 + .vscode/extensions.json | 5 +- AGENTS.md | 120 + CLAUDE.md | 286 +-- README.md | 5 +- apps/native/.env.example | 2 + apps/native/.gitignore | 33 + apps/native/app.json | 138 ++ .../assets/images/android-icon-background.png | Bin 0 -> 781931 bytes .../assets/images/android-icon-foreground.png | Bin 0 -> 132020 bytes .../assets/images/android-icon-monochrome.png | Bin 0 -> 89425 bytes apps/native/assets/images/icon.png | Bin 0 -> 736650 bytes apps/native/assets/images/ios-dark.png | Bin 0 -> 736650 bytes apps/native/assets/images/ios-light.png | Bin 0 -> 79794 bytes apps/native/assets/images/ios-tinted.png | Bin 0 -> 66205 bytes .../sofa.icon/Assets/couch-with-glow.svg | 37 + apps/native/assets/images/sofa.icon/icon.json | 47 + apps/native/assets/images/splash-icon.png | Bin 0 -> 132474 bytes apps/native/eas.json | 29 + apps/native/metro.config.js | 15 + apps/native/package.json | 81 + apps/native/src/app/(auth)/_layout.tsx | 24 + apps/native/src/app/(auth)/login.tsx | 209 ++ apps/native/src/app/(auth)/register.tsx | 220 ++ apps/native/src/app/(auth)/server-url.tsx | 230 ++ .../src/app/(tabs)/(explore)/_layout.tsx | 6 + .../native/src/app/(tabs)/(explore)/index.tsx | 106 + apps/native/src/app/(tabs)/(home)/_layout.tsx | 6 + apps/native/src/app/(tabs)/(home)/index.tsx | 140 ++ .../src/app/(tabs)/(search)/_layout.tsx | 10 + apps/native/src/app/(tabs)/(search)/index.tsx | 177 ++ .../src/app/(tabs)/(settings)/_layout.tsx | 6 + .../src/app/(tabs)/(settings)/index.tsx | 522 +++++ apps/native/src/app/(tabs)/_layout.tsx | 40 + apps/native/src/app/+not-found.tsx | 43 + apps/native/src/app/_layout.tsx | 129 ++ apps/native/src/app/person/[id].tsx | 236 ++ apps/native/src/app/title/[id].tsx | 569 +++++ apps/native/src/components/auth-screen.tsx | 58 + apps/native/src/components/container.tsx | 49 + .../dashboard/continue-watching-card.tsx | 117 + .../dashboard/horizontal-poster-row.tsx | 62 + .../src/components/dashboard/stats-card.tsx | 25 + .../explore/filterable-title-row.tsx | 135 ++ .../src/components/explore/genre-chip.tsx | 29 + .../src/components/explore/hero-banner.tsx | 115 + apps/native/src/components/header-avatar.tsx | 80 + .../components/search/search-result-row.tsx | 107 + apps/native/src/components/settings/icons.tsx | 62 + .../components/settings/integration-card.tsx | 310 +++ .../settings/integration-configs.ts | 117 + .../settings/integrations-section.tsx | 55 + .../src/components/settings/settings-row.tsx | 59 + .../components/settings/settings-section.tsx | 71 + .../src/components/titles/cast-card.tsx | 71 + .../titles/continue-watching-banner.tsx | 91 + .../src/components/titles/episode-row.tsx | 53 + .../components/titles/season-accordion.tsx | 192 ++ .../titles/status-action-button.tsx | 64 + apps/native/src/components/tmdb-logo.tsx | 34 + apps/native/src/components/ui/button.tsx | 78 + apps/native/src/components/ui/empty-state.tsx | 48 + .../src/components/ui/expandable-text.tsx | 56 + apps/native/src/components/ui/image.tsx | 20 + .../src/components/ui/offline-banner.tsx | 62 + apps/native/src/components/ui/poster-card.tsx | 368 ++++ .../src/components/ui/section-header.tsx | 28 + apps/native/src/components/ui/skeleton.tsx | 50 + apps/native/src/components/ui/sofa-logo.tsx | 24 + apps/native/src/components/ui/spinner.tsx | 17 + apps/native/src/components/ui/star-rating.tsx | 46 + .../native/src/components/ui/status-badge.tsx | 53 + apps/native/src/components/ui/switch.tsx | 92 + apps/native/src/components/ui/text-field.tsx | 60 + apps/native/src/components/ui/text.tsx | 10 + .../src/components/ui/toast-provider.tsx | 42 + apps/native/src/components/ui/toast.tsx | 127 ++ apps/native/src/global.css | 37 + apps/native/src/hooks/use-debounce.ts | 10 + .../src/hooks/use-tab-screen-options.tsx | 45 + apps/native/src/lib/auth-client.ts | 40 + apps/native/src/lib/mmkv.ts | 17 + apps/native/src/lib/orpc.ts | 34 + apps/native/src/lib/posthog.ts | 44 + apps/native/src/lib/query-client.ts | 22 + apps/native/src/lib/server-url.ts | 121 ++ apps/native/src/lib/toast.ts | 68 + apps/native/src/utils/cn.ts | 5 + apps/native/src/utils/haptics.ts | 50 + apps/native/src/utils/time-ago.ts | 36 + apps/native/tsconfig.json | 17 + apps/native/uniwind-types.d.ts | 10 + apps/server/src/orpc/procedures/admin.ts | 27 +- apps/server/src/orpc/procedures/dashboard.ts | 19 +- apps/server/src/orpc/procedures/discover.ts | 11 +- apps/server/src/orpc/procedures/explore.ts | 12 +- .../src/orpc/procedures/integrations.ts | 2 +- apps/server/src/orpc/procedures/search.ts | 36 +- apps/server/src/orpc/procedures/stats.ts | 9 - apps/server/src/orpc/procedures/status.ts | 19 +- apps/server/src/orpc/procedures/titles.ts | 31 + apps/server/src/orpc/procedures/watchlist.ts | 36 - apps/server/src/orpc/router.ts | 17 +- apps/server/src/routes/backups.ts | 4 +- apps/web/package.json | 30 +- apps/web/src/components/command-palette.tsx | 12 +- .../components/dashboard/stats-display.tsx | 8 +- .../src/components/dashboard/title-grid.tsx | 3 +- .../explore/filterable-title-row.tsx | 7 +- apps/web/src/components/explore/title-row.tsx | 5 +- .../settings/system-health-section.tsx | 17 +- apps/web/src/components/title-card.tsx | 2 +- biome.json | 12 +- bun.lock | 1935 +++++++++++++---- bunfig.toml | 4 +- package.json | 13 +- packages/api/package.json | 3 +- packages/api/src/contract.ts | 125 +- packages/api/src/schemas.ts | 186 +- packages/api/src/utils.ts | 50 + packages/auth/package.json | 3 +- packages/auth/src/server.ts | 6 +- packages/core/src/discovery.ts | 22 +- packages/core/src/system-health.ts | 2 +- packages/core/test/discovery.test.ts | 22 + packages/db/package.json | 4 +- 130 files changed, 9015 insertions(+), 971 deletions(-) create mode 100644 .github/workflows/eas-build.yml create mode 100644 .github/workflows/eas-submit.yml create mode 100644 .github/workflows/eas-update.yml create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md create mode 100644 apps/native/.env.example create mode 100644 apps/native/.gitignore create mode 100644 apps/native/app.json create mode 100644 apps/native/assets/images/android-icon-background.png create mode 100644 apps/native/assets/images/android-icon-foreground.png create mode 100644 apps/native/assets/images/android-icon-monochrome.png create mode 100644 apps/native/assets/images/icon.png create mode 100644 apps/native/assets/images/ios-dark.png create mode 100644 apps/native/assets/images/ios-light.png create mode 100644 apps/native/assets/images/ios-tinted.png create mode 100644 apps/native/assets/images/sofa.icon/Assets/couch-with-glow.svg create mode 100644 apps/native/assets/images/sofa.icon/icon.json create mode 100644 apps/native/assets/images/splash-icon.png create mode 100644 apps/native/eas.json create mode 100644 apps/native/metro.config.js create mode 100644 apps/native/package.json create mode 100644 apps/native/src/app/(auth)/_layout.tsx create mode 100644 apps/native/src/app/(auth)/login.tsx create mode 100644 apps/native/src/app/(auth)/register.tsx create mode 100644 apps/native/src/app/(auth)/server-url.tsx create mode 100644 apps/native/src/app/(tabs)/(explore)/_layout.tsx create mode 100644 apps/native/src/app/(tabs)/(explore)/index.tsx create mode 100644 apps/native/src/app/(tabs)/(home)/_layout.tsx create mode 100644 apps/native/src/app/(tabs)/(home)/index.tsx create mode 100644 apps/native/src/app/(tabs)/(search)/_layout.tsx create mode 100644 apps/native/src/app/(tabs)/(search)/index.tsx create mode 100644 apps/native/src/app/(tabs)/(settings)/_layout.tsx create mode 100644 apps/native/src/app/(tabs)/(settings)/index.tsx create mode 100644 apps/native/src/app/(tabs)/_layout.tsx create mode 100644 apps/native/src/app/+not-found.tsx create mode 100644 apps/native/src/app/_layout.tsx create mode 100644 apps/native/src/app/person/[id].tsx create mode 100644 apps/native/src/app/title/[id].tsx create mode 100644 apps/native/src/components/auth-screen.tsx create mode 100644 apps/native/src/components/container.tsx create mode 100644 apps/native/src/components/dashboard/continue-watching-card.tsx create mode 100644 apps/native/src/components/dashboard/horizontal-poster-row.tsx create mode 100644 apps/native/src/components/dashboard/stats-card.tsx create mode 100644 apps/native/src/components/explore/filterable-title-row.tsx create mode 100644 apps/native/src/components/explore/genre-chip.tsx create mode 100644 apps/native/src/components/explore/hero-banner.tsx create mode 100644 apps/native/src/components/header-avatar.tsx create mode 100644 apps/native/src/components/search/search-result-row.tsx create mode 100644 apps/native/src/components/settings/icons.tsx create mode 100644 apps/native/src/components/settings/integration-card.tsx create mode 100644 apps/native/src/components/settings/integration-configs.ts create mode 100644 apps/native/src/components/settings/integrations-section.tsx create mode 100644 apps/native/src/components/settings/settings-row.tsx create mode 100644 apps/native/src/components/settings/settings-section.tsx create mode 100644 apps/native/src/components/titles/cast-card.tsx create mode 100644 apps/native/src/components/titles/continue-watching-banner.tsx create mode 100644 apps/native/src/components/titles/episode-row.tsx create mode 100644 apps/native/src/components/titles/season-accordion.tsx create mode 100644 apps/native/src/components/titles/status-action-button.tsx create mode 100644 apps/native/src/components/tmdb-logo.tsx create mode 100644 apps/native/src/components/ui/button.tsx create mode 100644 apps/native/src/components/ui/empty-state.tsx create mode 100644 apps/native/src/components/ui/expandable-text.tsx create mode 100644 apps/native/src/components/ui/image.tsx create mode 100644 apps/native/src/components/ui/offline-banner.tsx create mode 100644 apps/native/src/components/ui/poster-card.tsx create mode 100644 apps/native/src/components/ui/section-header.tsx create mode 100644 apps/native/src/components/ui/skeleton.tsx create mode 100644 apps/native/src/components/ui/sofa-logo.tsx create mode 100644 apps/native/src/components/ui/spinner.tsx create mode 100644 apps/native/src/components/ui/star-rating.tsx create mode 100644 apps/native/src/components/ui/status-badge.tsx create mode 100644 apps/native/src/components/ui/switch.tsx create mode 100644 apps/native/src/components/ui/text-field.tsx create mode 100644 apps/native/src/components/ui/text.tsx create mode 100644 apps/native/src/components/ui/toast-provider.tsx create mode 100644 apps/native/src/components/ui/toast.tsx create mode 100644 apps/native/src/global.css create mode 100644 apps/native/src/hooks/use-debounce.ts create mode 100644 apps/native/src/hooks/use-tab-screen-options.tsx create mode 100644 apps/native/src/lib/auth-client.ts create mode 100644 apps/native/src/lib/mmkv.ts create mode 100644 apps/native/src/lib/orpc.ts create mode 100644 apps/native/src/lib/posthog.ts create mode 100644 apps/native/src/lib/query-client.ts create mode 100644 apps/native/src/lib/server-url.ts create mode 100644 apps/native/src/lib/toast.ts create mode 100644 apps/native/src/utils/cn.ts create mode 100644 apps/native/src/utils/haptics.ts create mode 100644 apps/native/src/utils/time-ago.ts create mode 100644 apps/native/tsconfig.json create mode 100644 apps/native/uniwind-types.d.ts delete mode 100644 apps/server/src/orpc/procedures/stats.ts delete mode 100644 apps/server/src/orpc/procedures/watchlist.ts create mode 100644 packages/api/src/utils.ts diff --git a/.dockerignore b/.dockerignore index c197e60..2eff91b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,3 +13,4 @@ coverage .idea .turbo .tanstack +apps/native diff --git a/.github/workflows/eas-build.yml b/.github/workflows/eas-build.yml new file mode 100644 index 0000000..677eb00 --- /dev/null +++ b/.github/workflows/eas-build.yml @@ -0,0 +1,51 @@ +name: EAS Build + +on: + workflow_dispatch: + inputs: + platform: + description: Platform to build + type: choice + options: + - all + - ios + - android + default: all + profile: + description: Build profile + type: choice + options: + - production + - development + default: production + push: + branches: [main] + paths: + - apps/native/** + - packages/api/** + +jobs: + build: + name: EAS Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - uses: oven-sh/setup-bun@v2 + + - name: Setup EAS + uses: expo/expo-github-action@v8 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build + working-directory: apps/native + run: eas build --platform ${{ inputs.platform || 'all' }} --profile ${{ inputs.profile || 'production' }} --non-interactive --no-wait diff --git a/.github/workflows/eas-submit.yml b/.github/workflows/eas-submit.yml new file mode 100644 index 0000000..4a18388 --- /dev/null +++ b/.github/workflows/eas-submit.yml @@ -0,0 +1,39 @@ +name: EAS Submit + +on: + workflow_dispatch: + inputs: + platform: + description: Platform to submit + type: choice + options: + - all + - ios + - android + default: all + +jobs: + submit: + name: EAS Submit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - uses: oven-sh/setup-bun@v2 + + - name: Setup EAS + uses: expo/expo-github-action@v8 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Submit + working-directory: apps/native + run: eas submit --platform ${{ inputs.platform || 'all' }} --latest --non-interactive diff --git a/.github/workflows/eas-update.yml b/.github/workflows/eas-update.yml new file mode 100644 index 0000000..a532769 --- /dev/null +++ b/.github/workflows/eas-update.yml @@ -0,0 +1,33 @@ +name: EAS Update + +on: + pull_request: + paths: + - apps/native/** + - packages/api/** + +jobs: + update: + name: EAS Update + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + + - uses: oven-sh/setup-bun@v2 + + - name: Setup EAS + uses: expo/expo-github-action@v8 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Publish update + working-directory: apps/native + run: eas update --branch ${{ github.head_ref }} --message "${{ github.event.pull_request.title }}" --non-interactive diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd95614..fa4b71d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,6 +18,10 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile + - name: Generate Expo types + run: bunx expo customize tsconfig.json + working-directory: ./apps/native + - name: Lint run: bunx turbo run lint diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 17a9ff2..4470bfb 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,7 +2,8 @@ "recommendations": [ "biomejs.biome", "bradlc.vscode-tailwindcss", - "vitest.explorer", - "vercel.turbo-vsc" + "expo.vscode-expo-tools", + "vercel.turbo-vsc", + "vitest.explorer" ] } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..75bf3db --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,120 @@ +# CLAUDE.md + +## Commands + +```bash +# Root commands (via Turborepo) +bun run dev # Start API server + Vite dev server +bun run build # Production build (both apps) +bun run lint # Biome lint check +bun run format # Biome format (auto-fix) +bun run check-types # TypeScript type check +bun run test # Run tests + +# Database commands (run from packages/db/) +cd packages/db && bun run db:push # Push schema changes to SQLite database +cd packages/db && bun run db:generate # Generate Drizzle migration files +cd packages/db && bun run db:migrate # Run Drizzle migrations +cd packages/db && bun run db:studio # Open Drizzle Studio (visual DB browser) +``` + +**Use Bun, not Node.js** — `bun `, `bun test`, `bun install`, `bun run