From a4777e442efcd760202499adcb559c3c6e495ffe Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 11:40:24 +0100 Subject: [PATCH 01/27] chore: metadata --- README.md | 71 +--------------------------------------------------- package.json | 2 +- 2 files changed, 2 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index bf54fc5..d512e09 100644 --- a/README.md +++ b/README.md @@ -65,75 +65,6 @@ To add a new package, simply run `pnpm turbo gen init` in the monorepo root. Thi The generator sets up the `package.json`, `tsconfig.json` and a `index.ts`, as well as configures all the necessary configurations for tooling around your package such as formatting, linting and typechecking. When the package is created, you're ready to go build out the package. -## Deployment - -### Expo - -Deploying your Expo application works slightly differently compared to Next.js on the web. Instead of "deploying" your app online, you need to submit production builds of your app to app stores, like [Apple App Store](https://www.apple.com/app-store) and [Google Play](https://play.google.com/store/apps). You can read the full [guide to distributing your app](https://docs.expo.dev/distribution/introduction), including best practices, in the Expo docs. - -1. Make sure to modify the `getBaseUrl` function to point to your backend's production URL: - - - -2. Let's start by setting up [EAS Build](https://docs.expo.dev/build/introduction), which is short for Expo Application Services. The build service helps you create builds of your app, without requiring a full native development setup. The commands below are a summary of [Creating your first build](https://docs.expo.dev/build/setup). - - ```bash - # Install the EAS CLI - pnpm add -g eas-cli - - # Log in with your Expo account - eas login - - # Configure your Expo app - cd apps/expo - eas build:configure - ``` - -3. After the initial setup, you can create your first build. You can build for Android and iOS platforms and use different [`eas.json` build profiles](https://docs.expo.dev/build-reference/eas-json) to create production builds or development, or test builds. Let's make a production build for iOS. - - ```bash - eas build --platform ios --profile production - ``` - - > If you don't specify the `--profile` flag, EAS uses the `production` profile by default. - -4. Now that you have your first production build, you can submit this to the stores. [EAS Submit](https://docs.expo.dev/submit/introduction) can help you send the build to the stores. - - ```bash - eas submit --platform ios --latest - ``` - - > You can also combine build and submit in a single command, using `eas build ... --auto-submit`. - -5. Before you can get your app in the hands of your users, you'll have to provide additional information to the app stores. This includes screenshots, app information, privacy policies, etc. _While still in preview_, [EAS Metadata](https://docs.expo.dev/eas/metadata) can help you with most of this information. - -6. Once everything is approved, your users can finally enjoy your app. Let's say you spotted a small typo; you'll have to create a new build, submit it to the stores, and wait for approval before you can resolve this issue. In these cases, you can use EAS Update to quickly send a small bugfix to your users without going through this long process. Let's start by setting up EAS Update. - - The steps below summarize the [Getting started with EAS Update](https://docs.expo.dev/eas-update/getting-started/#configure-your-project) guide. - - ```bash - # Add the `expo-updates` library to your Expo app - cd apps/expo - pnpm expo install expo-updates - - # Configure EAS Update - eas update:configure - ``` - -7. Before we can send out updates to your app, you have to create a new build and submit it to the app stores. For every change that includes native APIs, you have to rebuild the app and submit the update to the app stores. See steps 2 and 3. - -8. Now that everything is ready for updates, let's create a new update for `production` builds. With the `--auto` flag, EAS Update uses your current git branch name and commit message for this update. See [How EAS Update works](https://docs.expo.dev/eas-update/how-eas-update-works/#publishing-an-update) for more information. - - ```bash - cd apps/expo - eas update --auto - ``` - - > Your OTA (Over The Air) updates must always follow the app store's rules. You can't change your app's primary functionality without getting app store approval. But this is a fast way to update your app for minor changes and bug fixes. - -9. Done! Now that you have created your production build, submitted it to the stores, and installed EAS Update, you are ready for anything! - ### References + This app is based on [create-t3-turbo](https://github.com/t3-oss/create-t3-turbo) and [Turborepo](https://turborepo.org). - - diff --git a/package.json b/package.json index 25ec2ba..412b339 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "create-t3-turbo", + "name": "@movie-web/native", "private": true, "engines": { "node": ">=20.11.0" From 6e53e007570ee697a22b0f015e57c2f59d720898 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 11:57:24 +0100 Subject: [PATCH 02/27] feat: ci builds --- .github/workflows/build-mobile.yml | 143 +++++++++++++++++++++++++++++ apps/expo/package.json | 5 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-mobile.yml diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml new file mode 100644 index 0000000..e722494 --- /dev/null +++ b/.github/workflows/build-mobile.yml @@ -0,0 +1,143 @@ +name: build mobile app + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: write + +jobs: + bump-version: + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Automated Version Bump + uses: phips28/gh-action-bump-version@v10.1.1 + with: + skip-tag: 'true' + commit-message: 'chore: bump mobile version to {{version}} [skip ci]' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-android: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 21 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install dependencies + run: pnpm install + + - name: Build Android app + run: cd apps/expo && pnpm apk + + - name: Rename apk + run: mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/movie-web.apk + + - name: Upload imagilink.apk as artifact + uses: actions/upload-artifact@v4 + with: + name: apk + path: ./android/app/build/outputs/apk/release/movie-web.apk + + build-ios: + runs-on: macos-14 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Xcode Select Version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15.1.0' + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 21 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Install dependencies + run: pnpm install + + - name: Build iOS app + run: cd apps/expo && pnpm ipa + + - name: Export .ipa from .app + run: | + mkdir -p ios/build/Build/Products/Release-iphoneos/Payload + mv ios/build/Build/Products/Release-iphoneos/imagilink.app ios/build/Build/Products/Release-iphoneos/Payload/ + cd ios/build/Build/Products/Release-iphoneos + zip -r ../../../movie-web.ipa Payload + + - name: Upload movie-web.ipa as artifact + uses: actions/upload-artifact@v4 + with: + name: ipa + path: ./ios/build/movie-web.ipa + + release-app: + runs-on: ubuntu-latest + needs: [build-android, build-ios] + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Get package version + id: package-version + uses: martinbeentjes/npm-get-version-action@v1.3.1 + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ steps.package-version.outputs.current-version }} + files: | + movie-web.apk + movie-web.ipa + fail_on_unmatched_files: true + token: ${{ env.GITHUB_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/apps/expo/package.json b/apps/expo/package.json index edb2fe3..7bbcc10 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -1,5 +1,5 @@ { - "name": "@movie-web/mobile", + "name": "movie-web", "version": "0.1.0", "private": true, "main": "expo-router/entry", @@ -10,6 +10,9 @@ "dev:ios": "expo start --ios", "android": "expo run:android", "ios": "expo run:ios", + "apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease", + "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movie-web.xcworkspace -scheme movie-web -sdk iphoneos -configuration Release -derivedDataPath build -destination generic/platform=iOS CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", + "ipa:sim": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movie-web.xcworkspace -scheme movie-web -sdk iphonesimulator -configuration Release -derivedDataPath build -destination \"generic/platform=iOS Simulator\" CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint .", "typecheck": "tsc --noEmit" From b800574a26cf4de6d0a8a94421284d8b2b074a31 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:03:06 +0100 Subject: [PATCH 03/27] fix: additional ci build config stuffs --- .github/workflows/build-mobile.yml | 4 ++-- .gitignore | 2 ++ apps/expo/package.json | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index e722494..b647ded 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -59,7 +59,7 @@ jobs: run: pnpm install - name: Build Android app - run: cd apps/expo && pnpm apk + run: cd apps/expo && pnpm run apk - name: Rename apk run: mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/movie-web.apk @@ -97,7 +97,7 @@ jobs: run: pnpm install - name: Build iOS app - run: cd apps/expo && pnpm ipa + run: cd apps/expo && pnpm run ipa - name: Export .ipa from .app run: | diff --git a/.gitignore b/.gitignore index 95c83c2..7774961 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ coverage dist/ expo-env.d.ts apps/expo/.gitignore +ios/ +android/ # production build diff --git a/apps/expo/package.json b/apps/expo/package.json index 7bbcc10..c9fcf85 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -11,8 +11,8 @@ "android": "expo run:android", "ios": "expo run:ios", "apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease", - "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movie-web.xcworkspace -scheme movie-web -sdk iphoneos -configuration Release -derivedDataPath build -destination generic/platform=iOS CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", - "ipa:sim": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movie-web.xcworkspace -scheme movie-web -sdk iphonesimulator -configuration Release -derivedDataPath build -destination \"generic/platform=iOS Simulator\" CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", + "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -sdk iphoneos -configuration Release -derivedDataPath build -destination generic/platform=iOS CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", + "ipa:sim": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -sdk iphonesimulator -configuration Release -derivedDataPath build -destination \"generic/platform=iOS Simulator\" CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint .", "typecheck": "tsc --noEmit" From 0c1e67291aa02f94ecb80a81ced037c9de152c33 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:17:59 +0100 Subject: [PATCH 04/27] chore: run prettier --- apps/expo/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/expo/package.json b/apps/expo/package.json index c9fcf85..7cbe603 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -10,7 +10,7 @@ "dev:ios": "expo start --ios", "android": "expo run:android", "ios": "expo run:ios", - "apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease", + "apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease", "ipa": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -sdk iphoneos -configuration Release -derivedDataPath build -destination generic/platform=iOS CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", "ipa:sim": "expo prebuild --platform=ios && cd ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -sdk iphonesimulator -configuration Release -derivedDataPath build -destination \"generic/platform=iOS Simulator\" CODE_SIGN_IDENTITY=\"\" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO", "format": "prettier --check . --ignore-path ../../.gitignore", From 94ef89a95f98b2f2c7de11ab5cf2d08138dbc032 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:26:33 +0100 Subject: [PATCH 05/27] chore: use actual name of the built executable --- .github/workflows/build-mobile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index b647ded..dc4d2e9 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -102,7 +102,7 @@ jobs: - name: Export .ipa from .app run: | mkdir -p ios/build/Build/Products/Release-iphoneos/Payload - mv ios/build/Build/Products/Release-iphoneos/imagilink.app ios/build/Build/Products/Release-iphoneos/Payload/ + mv ios/build/Build/Products/Release-iphoneos/movieweb.app ios/build/Build/Products/Release-iphoneos/Payload/ cd ios/build/Build/Products/Release-iphoneos zip -r ../../../movie-web.ipa Payload From 1a9f955a37bceee4aa41034a09831df0e6c37df5 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:30:09 +0100 Subject: [PATCH 06/27] feat: init tmdb package --- packages/tmdb/package.json | 33 +++++++++++++++++++++++++++++++++ packages/tmdb/src/index.ts | 1 + packages/tmdb/tsconfig.json | 8 ++++++++ pnpm-lock.yaml | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 packages/tmdb/package.json create mode 100644 packages/tmdb/src/index.ts create mode 100644 packages/tmdb/tsconfig.json diff --git a/packages/tmdb/package.json b/packages/tmdb/package.json new file mode 100644 index 0000000..3d926ea --- /dev/null +++ b/packages/tmdb/package.json @@ -0,0 +1,33 @@ +{ + "name": "@movie-web/tmdb", + "private": true, + "version": "0.1.0", + "type": "module", + "exports": { + ".": "./src/index.ts" + }, + "license": "MIT", + "scripts": { + "clean": "rm -rf .turbo node_modules", + "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@movie-web/eslint-config": "workspace:^0.2.0", + "@movie-web/prettier-config": "workspace:^0.1.0", + "@movie-web/tsconfig": "workspace:^0.1.0", + "eslint": "^8.56.0", + "prettier": "^3.1.1", + "typescript": "^5.3.3" + }, + "eslintConfig": { + "extends": [ + "@movie-web/eslint-config/base" + ] + }, + "prettier": "@movie-web/prettier-config", + "dependencies": { + "tmdb-ts": "^1.6.1" + } +} diff --git a/packages/tmdb/src/index.ts b/packages/tmdb/src/index.ts new file mode 100644 index 0000000..21ae657 --- /dev/null +++ b/packages/tmdb/src/index.ts @@ -0,0 +1 @@ +export const name = "tmdb"; diff --git a/packages/tmdb/tsconfig.json b/packages/tmdb/tsconfig.json new file mode 100644 index 0000000..12305a4 --- /dev/null +++ b/packages/tmdb/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@movie-web/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", + }, + "include": ["*.ts", "src"], + "exclude": ["node_modules"], +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc74054..c73a6c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,6 +135,31 @@ importers: specifier: ^5.3.3 version: 5.3.3 + packages/tmdb: + dependencies: + tmdb-ts: + specifier: ^1.6.1 + version: 1.6.1 + devDependencies: + '@movie-web/eslint-config': + specifier: workspace:^0.2.0 + version: link:../../tooling/eslint + '@movie-web/prettier-config': + specifier: workspace:^0.1.0 + version: link:../../tooling/prettier + '@movie-web/tsconfig': + specifier: workspace:^0.1.0 + version: link:../../tooling/typescript + eslint: + specifier: ^8.56.0 + version: 8.56.0 + prettier: + specifier: ^3.1.1 + version: 3.2.4 + typescript: + specifier: ^5.3.3 + version: 5.3.3 + tooling/eslint: dependencies: '@typescript-eslint/eslint-plugin': @@ -9537,6 +9562,14 @@ packages: upper-case: 1.1.3 dev: true + /tmdb-ts@1.6.1: + resolution: {integrity: sha512-TJQYQctzky03z8bhlJtZ9ZjFHNvLhpow3qKHMMZj2LEOvlqcJ/Dyy33IyuBROrhzWLelkmGraAA718B0ENP1Fg==} + dependencies: + cross-fetch: 3.1.8 + transitivePeerDependencies: + - encoding + dev: false + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} From 360bdf4f2339a07a5e0d765dd5b18e40cf8f36e3 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:32:07 +0100 Subject: [PATCH 07/27] fix: adjust workflow paths --- .github/workflows/build-mobile.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index dc4d2e9..fd899db 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -62,13 +62,13 @@ jobs: run: cd apps/expo && pnpm run apk - name: Rename apk - run: mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/movie-web.apk + run: cd apps/expo && mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/movie-web.apk - - name: Upload imagilink.apk as artifact + - name: Upload movie-web.apk as artifact uses: actions/upload-artifact@v4 with: name: apk - path: ./android/app/build/outputs/apk/release/movie-web.apk + path: ./apps/expo/android/app/build/outputs/apk/release/movie-web.apk build-ios: runs-on: macos-14 @@ -101,6 +101,7 @@ jobs: - name: Export .ipa from .app run: | + cd apps/expo mkdir -p ios/build/Build/Products/Release-iphoneos/Payload mv ios/build/Build/Products/Release-iphoneos/movieweb.app ios/build/Build/Products/Release-iphoneos/Payload/ cd ios/build/Build/Products/Release-iphoneos @@ -110,12 +111,12 @@ jobs: uses: actions/upload-artifact@v4 with: name: ipa - path: ./ios/build/movie-web.ipa + path: ./apps/expo/ios/build/movie-web.ipa release-app: runs-on: ubuntu-latest needs: [build-android, build-ios] - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name == 'push' && github.ref == 'refs/heads/master' steps: - name: Checkout code From c2b6b6a5559b13473b167ccc9e8a0e7840b9fefd Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:43:08 +0100 Subject: [PATCH 08/27] chore: bump setup node action version --- .github/workflows/build-mobile.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index fd899db..69d09eb 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -36,7 +36,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 21 @@ -83,7 +83,7 @@ jobs: xcode-version: '15.1.0' - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 21 From 3a4df634cf1fc6b2a4486022962b6545538efce9 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:58:33 +0100 Subject: [PATCH 09/27] feat: implement tmdb package --- packages/tmdb/src/index.ts | 1 + packages/tmdb/src/search.ts | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 packages/tmdb/src/search.ts diff --git a/packages/tmdb/src/index.ts b/packages/tmdb/src/index.ts index 21ae657..e2ba79d 100644 --- a/packages/tmdb/src/index.ts +++ b/packages/tmdb/src/index.ts @@ -1 +1,2 @@ export const name = "tmdb"; +export * from './search'; \ No newline at end of file diff --git a/packages/tmdb/src/search.ts b/packages/tmdb/src/search.ts new file mode 100644 index 0000000..6442d3a --- /dev/null +++ b/packages/tmdb/src/search.ts @@ -0,0 +1,46 @@ +import type { MovieDetails, TvShowDetails } from 'tmdb-ts'; +import { TMDB } from 'tmdb-ts'; + +const TMDB_API_KEY = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc'; +const tmdb = new TMDB(TMDB_API_KEY); + +export async function searchTitle(query: string): Promise { + try { + const rawResults = await tmdb.search.multi({ query, page: 1, include_adult: false }); + const results = rawResults.results.filter((result) => result.media_type === 'tv' || result.media_type === 'movie'); + + if (!results.length) throw new Error('No results found'); + + return results; + } catch (ex) { + throw new Error(`Error searching for title: ${(ex as Error).message}`); + } +} + +export async function fetchMediaDetails( + id: string, type: 'movie' | 'tv' + ): Promise<{ type: 'movie' | 'tv'; result: TvShowDetails | MovieDetails } | undefined> { + try { + let result: TvShowDetails | MovieDetails; + + switch (type) { + case 'tv': + result = await tmdb.tvShows.details(parseInt(id, 10)); + break; + case 'movie': + result = await tmdb.movies.details(parseInt(id, 10)); + break; + default: + return undefined; + } + + return { type, result }; + } catch (ex) { + return undefined; + } + } + + export function getMediaPoster(posterPath: string): string { + return `https://image.tmdb.org/t/p/w185/${posterPath}`; + } + \ No newline at end of file From c4a56c1a2a6df34b4880c4b1fd7d84fd34dff63f Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:00:12 +0100 Subject: [PATCH 10/27] chore: run prettier --- packages/tmdb/src/index.ts | 2 +- packages/tmdb/src/search.ts | 79 +++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/packages/tmdb/src/index.ts b/packages/tmdb/src/index.ts index e2ba79d..732fb25 100644 --- a/packages/tmdb/src/index.ts +++ b/packages/tmdb/src/index.ts @@ -1,2 +1,2 @@ export const name = "tmdb"; -export * from './search'; \ No newline at end of file +export * from "./search"; diff --git a/packages/tmdb/src/search.ts b/packages/tmdb/src/search.ts index 6442d3a..43452e6 100644 --- a/packages/tmdb/src/search.ts +++ b/packages/tmdb/src/search.ts @@ -1,46 +1,55 @@ -import type { MovieDetails, TvShowDetails } from 'tmdb-ts'; -import { TMDB } from 'tmdb-ts'; +import type { MovieDetails, TvShowDetails } from "tmdb-ts"; +import { TMDB } from "tmdb-ts"; -const TMDB_API_KEY = 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc'; +const TMDB_API_KEY = + "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc"; const tmdb = new TMDB(TMDB_API_KEY); export async function searchTitle(query: string): Promise { - try { - const rawResults = await tmdb.search.multi({ query, page: 1, include_adult: false }); - const results = rawResults.results.filter((result) => result.media_type === 'tv' || result.media_type === 'movie'); + try { + const rawResults = await tmdb.search.multi({ + query, + page: 1, + include_adult: false, + }); + const results = rawResults.results.filter( + (result) => result.media_type === "tv" || result.media_type === "movie", + ); - if (!results.length) throw new Error('No results found'); + if (!results.length) throw new Error("No results found"); - return results; - } catch (ex) { - throw new Error(`Error searching for title: ${(ex as Error).message}`); - } + return results; + } catch (ex) { + throw new Error(`Error searching for title: ${(ex as Error).message}`); + } } export async function fetchMediaDetails( - id: string, type: 'movie' | 'tv' - ): Promise<{ type: 'movie' | 'tv'; result: TvShowDetails | MovieDetails } | undefined> { - try { - let result: TvShowDetails | MovieDetails; - - switch (type) { - case 'tv': - result = await tmdb.tvShows.details(parseInt(id, 10)); - break; - case 'movie': - result = await tmdb.movies.details(parseInt(id, 10)); - break; - default: - return undefined; - } - - return { type, result }; - } catch (ex) { - return undefined; - } - } + id: string, + type: "movie" | "tv", +): Promise< + { type: "movie" | "tv"; result: TvShowDetails | MovieDetails } | undefined +> { + try { + let result: TvShowDetails | MovieDetails; - export function getMediaPoster(posterPath: string): string { - return `https://image.tmdb.org/t/p/w185/${posterPath}`; + switch (type) { + case "tv": + result = await tmdb.tvShows.details(parseInt(id, 10)); + break; + case "movie": + result = await tmdb.movies.details(parseInt(id, 10)); + break; + default: + return undefined; + } + + return { type, result }; + } catch (ex) { + return undefined; } - \ No newline at end of file +} + +export function getMediaPoster(posterPath: string): string { + return `https://image.tmdb.org/t/p/w185/${posterPath}`; +} From b4e9ff50863a829c5a09140d1081684e839ab187 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:52:10 +0100 Subject: [PATCH 11/27] chore: stuff --- apps/expo/app.config.ts | 2 +- apps/expo/package.json | 1 + pnpm-lock.yaml | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/expo/app.config.ts b/apps/expo/app.config.ts index bd785ab..223d040 100644 --- a/apps/expo/app.config.ts +++ b/apps/expo/app.config.ts @@ -4,7 +4,7 @@ const defineConfig = (): ExpoConfig => ({ name: "movie-web", slug: "mw-mobile", scheme: "dev.movieweb.app", - version: "1.0.0", + version: "0.1.0", orientation: "portrait", icon: "./assets/images/icon.png", userInterfaceStyle: "automatic", diff --git a/apps/expo/package.json b/apps/expo/package.json index 7cbe603..c763762 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@expo/metro-config": "^0.17.3", + "@movie-web/tmdb": "*", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "expo": "~50.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c73a6c9..c0b255e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ importers: '@expo/metro-config': specifier: ^0.17.3 version: 0.17.3(@react-native/babel-preset@0.73.20) + '@movie-web/tmdb': + specifier: '*' + version: link:../../packages/tmdb class-variance-authority: specifier: ^0.7.0 version: 0.7.0 From e3f74aac09e794f33a4a3386461a08771dead3aa Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:14:16 +0100 Subject: [PATCH 12/27] feat: implement search via tmdb package --- apps/expo/src/app/(tabs)/search/Searchbar.tsx | 9 ++- apps/expo/src/app/(tabs)/search/_layout.tsx | 65 +++++++++++++++---- apps/expo/src/app/components/item/item.tsx | 14 ++-- packages/tmdb/package.json | 1 + packages/tmdb/src/search.ts | 2 +- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/apps/expo/src/app/(tabs)/search/Searchbar.tsx b/apps/expo/src/app/(tabs)/search/Searchbar.tsx index fef0b7a..20229a0 100644 --- a/apps/expo/src/app/(tabs)/search/Searchbar.tsx +++ b/apps/expo/src/app/(tabs)/search/Searchbar.tsx @@ -5,7 +5,7 @@ import { FontAwesome5 } from "@expo/vector-icons"; import Colors from "@movie-web/tailwind-config/colors"; -export default function Searchbar() { +export default function Searchbar({ onSearchChange }: { onSearchChange: (text: string) => void }) { const [keyword, setKeyword] = useState(""); const inputRef = useRef(null); @@ -22,6 +22,11 @@ export default function Searchbar() { }, []), ); + const handleChange = (text: string) => { + setKeyword(text); + onSearchChange(text); + }; + return ( @@ -29,7 +34,7 @@ export default function Searchbar() { setKeyword(text)} + onChangeText={handleChange} ref={inputRef} placeholder="What are you looking for?" placeholderTextColor={Colors.secondary[200]} diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 8ea2af4..2de62b6 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -1,11 +1,24 @@ -import { ScrollView, View } from "react-native"; +import React, { useState } from 'react'; +import { ScrollView, View } from 'react-native'; -import Item from "~/components/item/item"; -import ScreenLayout from "~/components/layout/ScreenLayout"; +import Item from '~/components/item/item'; import { Text } from "~/components/ui/Text"; -import Searchbar from "./Searchbar"; +import ScreenLayout from '~/components/layout/ScreenLayout'; +import Searchbar from './Searchbar'; +import { searchTitle, getMediaPoster } from '@movie-web/tmdb'; export default function SearchScreen() { +const [searchResults, setSearchResults] = useState<{ title: string; posterUrl: string; year: number; type: "movie" | "tv"; }[]>([]); + +const handleSearchChange = async (query: string) => { + if (query.length > 0) { + const results = await fetchSearchResults(query); + setSearchResults(results); + } else { + setSearchResults([]); + } +}; + return ( - + - - - - - - - - - + {searchResults.map((item, index) => ( + + + + ))} ); } + +async function fetchSearchResults(query: string): Promise<{ title: string; posterUrl: string; year: number; type: "movie" | "tv"; }[]> { + console.log('Fetching results for:', query); + const results = await searchTitle(query); + + return results.map((result) => { + switch (result.media_type) { + case 'movie': + return { + title: result.title, + posterUrl: getMediaPoster(result.poster_path), + year: new Date(result.release_date).getFullYear(), + type: result.media_type as "movie", + }; + case 'tv': + return { + title: result.name, + posterUrl: getMediaPoster(result.poster_path), + year: new Date(result.first_air_date).getFullYear(), + type: result.media_type as "tv", + }; + default: + return undefined; + } + }).filter((item): item is { title: string; posterUrl: string; year: number; type: "movie" | "tv"; } => item !== undefined); + } + + \ No newline at end of file diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index e175f7b..f251cc2 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -1,25 +1,25 @@ import { Image, View } from "react-native"; - -import { TMDB_POSTER_PATH } from "~/app/constants/General"; import { Text } from "~/components/ui/Text"; -export default function Item() { +export default function Item({ data }: { data: { title: string, type: string, year: number, posterUrl: string } }) { + const { title, type, year, posterUrl } = data; + return ( - Hamilton + {title} - Movie + {type} - 2023 + {year} ); diff --git a/packages/tmdb/package.json b/packages/tmdb/package.json index 3d926ea..a768004 100644 --- a/packages/tmdb/package.json +++ b/packages/tmdb/package.json @@ -3,6 +3,7 @@ "private": true, "version": "0.1.0", "type": "module", + "main": "./src/index.ts", "exports": { ".": "./src/index.ts" }, diff --git a/packages/tmdb/src/search.ts b/packages/tmdb/src/search.ts index 43452e6..37f482d 100644 --- a/packages/tmdb/src/search.ts +++ b/packages/tmdb/src/search.ts @@ -5,7 +5,7 @@ const TMDB_API_KEY = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc"; const tmdb = new TMDB(TMDB_API_KEY); -export async function searchTitle(query: string): Promise { +export async function searchTitle(query: string) { try { const rawResults = await tmdb.search.multi({ query, From dc6e3f5a7f61d5f0deff22eab5f65e2d91d06219 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:15:21 +0100 Subject: [PATCH 13/27] chore: run prettier --- apps/expo/package.json | 2 +- apps/expo/src/app/(tabs)/search/Searchbar.tsx | 8 +- apps/expo/src/app/(tabs)/search/_layout.tsx | 100 ++++++++++-------- apps/expo/src/app/components/item/item.tsx | 7 +- 4 files changed, 71 insertions(+), 46 deletions(-) diff --git a/apps/expo/package.json b/apps/expo/package.json index c763762..8742f70 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@expo/metro-config": "^0.17.3", - "@movie-web/tmdb": "*", + "@movie-web/tmdb": "*", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "expo": "~50.0.5", diff --git a/apps/expo/src/app/(tabs)/search/Searchbar.tsx b/apps/expo/src/app/(tabs)/search/Searchbar.tsx index 20229a0..5de78f4 100644 --- a/apps/expo/src/app/(tabs)/search/Searchbar.tsx +++ b/apps/expo/src/app/(tabs)/search/Searchbar.tsx @@ -5,7 +5,11 @@ import { FontAwesome5 } from "@expo/vector-icons"; import Colors from "@movie-web/tailwind-config/colors"; -export default function Searchbar({ onSearchChange }: { onSearchChange: (text: string) => void }) { +export default function Searchbar({ + onSearchChange, +}: { + onSearchChange: (text: string) => void; +}) { const [keyword, setKeyword] = useState(""); const inputRef = useRef(null); @@ -34,7 +38,7 @@ export default function Searchbar({ onSearchChange }: { onSearchChange: (text: s ([]); + const [searchResults, setSearchResults] = useState< + { title: string; posterUrl: string; year: number; type: "movie" | "tv" }[] + >([]); -const handleSearchChange = async (query: string) => { - if (query.length > 0) { - const results = await fetchSearchResults(query); - setSearchResults(results); - } else { - setSearchResults([]); - } -}; + const handleSearchChange = async (query: string) => { + if (query.length > 0) { + const results = await fetchSearchResults(query); + setSearchResults(results); + } else { + setSearchResults([]); + } + }; return ( @@ -42,30 +45,43 @@ const handleSearchChange = async (query: string) => { ); } -async function fetchSearchResults(query: string): Promise<{ title: string; posterUrl: string; year: number; type: "movie" | "tv"; }[]> { - console.log('Fetching results for:', query); - const results = await searchTitle(query); - - return results.map((result) => { - switch (result.media_type) { - case 'movie': - return { - title: result.title, - posterUrl: getMediaPoster(result.poster_path), - year: new Date(result.release_date).getFullYear(), - type: result.media_type as "movie", - }; - case 'tv': - return { - title: result.name, - posterUrl: getMediaPoster(result.poster_path), - year: new Date(result.first_air_date).getFullYear(), - type: result.media_type as "tv", - }; - default: - return undefined; - } - }).filter((item): item is { title: string; posterUrl: string; year: number; type: "movie" | "tv"; } => item !== undefined); - } - - \ No newline at end of file +async function fetchSearchResults( + query: string, +): Promise< + { title: string; posterUrl: string; year: number; type: "movie" | "tv" }[] +> { + console.log("Fetching results for:", query); + const results = await searchTitle(query); + + return results + .map((result) => { + switch (result.media_type) { + case "movie": + return { + title: result.title, + posterUrl: getMediaPoster(result.poster_path), + year: new Date(result.release_date).getFullYear(), + type: result.media_type as "movie", + }; + case "tv": + return { + title: result.name, + posterUrl: getMediaPoster(result.poster_path), + year: new Date(result.first_air_date).getFullYear(), + type: result.media_type as "tv", + }; + default: + return undefined; + } + }) + .filter( + ( + item, + ): item is { + title: string; + posterUrl: string; + year: number; + type: "movie" | "tv"; + } => item !== undefined, + ); +} diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index f251cc2..5710d01 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -1,7 +1,12 @@ import { Image, View } from "react-native"; + import { Text } from "~/components/ui/Text"; -export default function Item({ data }: { data: { title: string, type: string, year: number, posterUrl: string } }) { +export default function Item({ + data, +}: { + data: { title: string; type: string; year: number; posterUrl: string }; +}) { const { title, type, year, posterUrl } = data; return ( From 7c9247dc2c05039570b13bda2e81537fcd5281de Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:25:36 +0100 Subject: [PATCH 14/27] chore: cleanup --- apps/expo/src/app/(tabs)/search/_layout.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 678b834..166732e 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -50,7 +50,6 @@ async function fetchSearchResults( ): Promise< { title: string; posterUrl: string; year: number; type: "movie" | "tv" }[] > { - console.log("Fetching results for:", query); const results = await searchTitle(query); return results From 271cca3cd53273ad38ce2d565670e8a1a241f020 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:34:21 +0100 Subject: [PATCH 15/27] chore: cleanup --- apps/expo/src/app/_layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/expo/src/app/_layout.tsx b/apps/expo/src/app/_layout.tsx index 3238d56..623f4b3 100644 --- a/apps/expo/src/app/_layout.tsx +++ b/apps/expo/src/app/_layout.tsx @@ -21,7 +21,7 @@ export { export const unstable_settings = { // Ensure that reloading on `/modal` keeps a back button present. - initialRouteName: "(tabs)/index", + initialRouteName: "(tabs)", }; // Prevent the splash screen from auto-hiding before asset loading is complete. From aa0e374bca0d8e40a051958523168cd252c7e521 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:44:55 +0100 Subject: [PATCH 16/27] chore: more cleanup --- apps/expo/src/app/components/item/item.tsx | 2 +- apps/expo/src/app/constants/.gitkeep | 0 apps/expo/src/app/constants/General.ts | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100644 apps/expo/src/app/constants/.gitkeep delete mode 100644 apps/expo/src/app/constants/General.ts diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index 5710d01..6d9ab01 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -22,7 +22,7 @@ export default function Item({ {title} - {type} + {type === 'tv' ? 'Show' : 'Movie'} {year} diff --git a/apps/expo/src/app/constants/.gitkeep b/apps/expo/src/app/constants/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/expo/src/app/constants/General.ts b/apps/expo/src/app/constants/General.ts deleted file mode 100644 index e12b028..0000000 --- a/apps/expo/src/app/constants/General.ts +++ /dev/null @@ -1 +0,0 @@ -export const TMDB_POSTER_PATH = `https://image.tmdb.org/t/p`; From e88b7d2051f93ee4929655709ec68ac89d4e5c03 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:52:27 +0100 Subject: [PATCH 17/27] chore: run prettier --- apps/expo/src/app/components/item/item.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index 6d9ab01..f3bc637 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -22,7 +22,9 @@ export default function Item({ {title} - {type === 'tv' ? 'Show' : 'Movie'} + + {type === "tv" ? "Show" : "Movie"} + {year} From 1b9fbb41207bd903eb418a82bb452fe7dce66afb Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:38:03 +0100 Subject: [PATCH 18/27] chore: use typedef instead of inline type --- apps/expo/src/app/(tabs)/search/_layout.tsx | 24 ++++++--------------- apps/expo/src/app/components/item/item.tsx | 14 +++++++----- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 166732e..46d401c 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -3,15 +3,14 @@ import { ScrollView, View } from "react-native"; import { getMediaPoster, searchTitle } from "@movie-web/tmdb"; +import type { ItemData } from "~/components/item/item"; import Item from "~/components/item/item"; import ScreenLayout from "~/components/layout/ScreenLayout"; import { Text } from "~/components/ui/Text"; import Searchbar from "./Searchbar"; export default function SearchScreen() { - const [searchResults, setSearchResults] = useState< - { title: string; posterUrl: string; year: number; type: "movie" | "tv" }[] - >([]); + const [searchResults, setSearchResults] = useState([]); const handleSearchChange = async (query: string) => { if (query.length > 0) { @@ -45,11 +44,7 @@ export default function SearchScreen() { ); } -async function fetchSearchResults( - query: string, -): Promise< - { title: string; posterUrl: string; year: number; type: "movie" | "tv" }[] -> { +async function fetchSearchResults(query: string): Promise { const results = await searchTitle(query); return results @@ -57,6 +52,7 @@ async function fetchSearchResults( switch (result.media_type) { case "movie": return { + id: result.id.toString(), title: result.title, posterUrl: getMediaPoster(result.poster_path), year: new Date(result.release_date).getFullYear(), @@ -64,6 +60,7 @@ async function fetchSearchResults( }; case "tv": return { + id: result.id.toString(), title: result.name, posterUrl: getMediaPoster(result.poster_path), year: new Date(result.first_air_date).getFullYear(), @@ -73,14 +70,5 @@ async function fetchSearchResults( return undefined; } }) - .filter( - ( - item, - ): item is { - title: string; - posterUrl: string; - year: number; - type: "movie" | "tv"; - } => item !== undefined, - ); + .filter((item): item is ItemData => item !== undefined); } diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index f3bc637..e2bb3c2 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -2,11 +2,15 @@ import { Image, View } from "react-native"; import { Text } from "~/components/ui/Text"; -export default function Item({ - data, -}: { - data: { title: string; type: string; year: number; posterUrl: string }; -}) { +export interface ItemData { + id: string; + title: string; + type: "movie" | "tv"; + year: number; + posterUrl: string; +} + +export default function Item({ data }: { data: ItemData }) { const { title, type, year, posterUrl } = data; return ( From ef78cc34474165035e1743c51bf79eb6cf869cfc Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:38:57 +0100 Subject: [PATCH 19/27] chore: cleanup --- apps/expo/src/app/(tabs)/search/_layout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 46d401c..0be1603 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -56,7 +56,7 @@ async function fetchSearchResults(query: string): Promise { title: result.title, posterUrl: getMediaPoster(result.poster_path), year: new Date(result.release_date).getFullYear(), - type: result.media_type as "movie", + type: result.media_type, }; case "tv": return { @@ -64,7 +64,7 @@ async function fetchSearchResults(query: string): Promise { title: result.name, posterUrl: getMediaPoster(result.poster_path), year: new Date(result.first_air_date).getFullYear(), - type: result.media_type as "tv", + type: result.media_type, }; default: return undefined; From cf4076d613ebd712f277dbca5775168d9d3cdfb1 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:46:26 +0100 Subject: [PATCH 20/27] chore: catch search --- apps/expo/src/app/(tabs)/search/_layout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 0be1603..2060fb9 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -14,7 +14,7 @@ export default function SearchScreen() { const handleSearchChange = async (query: string) => { if (query.length > 0) { - const results = await fetchSearchResults(query); + const results = await fetchSearchResults(query).catch(() => []); setSearchResults(results); } else { setSearchResults([]); @@ -45,7 +45,7 @@ export default function SearchScreen() { } async function fetchSearchResults(query: string): Promise { - const results = await searchTitle(query); + const results = await searchTitle(query) return results .map((result) => { From 54e270bf17687c8b58a39fce39548da254b698ff Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:48:04 +0100 Subject: [PATCH 21/27] chore: run prettier --- apps/expo/src/app/(tabs)/search/_layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index 2060fb9..b09df2a 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -45,7 +45,7 @@ export default function SearchScreen() { } async function fetchSearchResults(query: string): Promise { - const results = await searchTitle(query) + const results = await searchTitle(query); return results .map((result) => { From 4478366855beb0723ae744ec3d62998f2bd2b6b9 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 18:36:21 +0100 Subject: [PATCH 22/27] refactor: address code review --- apps/expo/package.json | 2 +- apps/expo/src/app/(tabs)/search/_layout.tsx | 33 +++++------------ packages/tmdb/src/details.ts | 29 +++++++++++++++ packages/tmdb/src/index.ts | 2 ++ packages/tmdb/src/search.ts | 39 ++------------------- packages/tmdb/src/util.ts | 9 +++++ 6 files changed, 53 insertions(+), 61 deletions(-) create mode 100644 packages/tmdb/src/details.ts create mode 100644 packages/tmdb/src/util.ts diff --git a/apps/expo/package.json b/apps/expo/package.json index 8742f70..acd6aaf 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -1,5 +1,5 @@ { - "name": "movie-web", + "name": "@movie-web/mobile", "version": "0.1.0", "private": true, "main": "expo-router/entry", diff --git a/apps/expo/src/app/(tabs)/search/_layout.tsx b/apps/expo/src/app/(tabs)/search/_layout.tsx index b09df2a..63937ac 100644 --- a/apps/expo/src/app/(tabs)/search/_layout.tsx +++ b/apps/expo/src/app/(tabs)/search/_layout.tsx @@ -47,28 +47,13 @@ export default function SearchScreen() { async function fetchSearchResults(query: string): Promise { const results = await searchTitle(query); - return results - .map((result) => { - switch (result.media_type) { - case "movie": - return { - id: result.id.toString(), - title: result.title, - posterUrl: getMediaPoster(result.poster_path), - year: new Date(result.release_date).getFullYear(), - type: result.media_type, - }; - case "tv": - return { - id: result.id.toString(), - title: result.name, - posterUrl: getMediaPoster(result.poster_path), - year: new Date(result.first_air_date).getFullYear(), - type: result.media_type, - }; - default: - return undefined; - } - }) - .filter((item): item is ItemData => item !== undefined); + return results.map((result) => ({ + id: result.id.toString(), + title: result.media_type === "tv" ? result.name : result.title, + posterUrl: getMediaPoster(result.poster_path), + year: new Date( + result.media_type === "tv" ? result.first_air_date : result.release_date, + ).getFullYear(), + type: result.media_type, + })); } diff --git a/packages/tmdb/src/details.ts b/packages/tmdb/src/details.ts new file mode 100644 index 0000000..d5a26c3 --- /dev/null +++ b/packages/tmdb/src/details.ts @@ -0,0 +1,29 @@ +import type { MovieDetails, TvShowDetails } from "tmdb-ts"; + +import { tmdb } from "./util"; + +export async function fetchMediaDetails( + id: string, + type: "movie" | "tv", +): Promise< + { type: "movie" | "tv"; result: TvShowDetails | MovieDetails } | undefined +> { + try { + let result: TvShowDetails | MovieDetails; + + switch (type) { + case "tv": + result = await tmdb.tvShows.details(parseInt(id, 10)); + break; + case "movie": + result = await tmdb.movies.details(parseInt(id, 10)); + break; + default: + return undefined; + } + + return { type, result }; + } catch (ex) { + return undefined; + } +} diff --git a/packages/tmdb/src/index.ts b/packages/tmdb/src/index.ts index 732fb25..fec6c9f 100644 --- a/packages/tmdb/src/index.ts +++ b/packages/tmdb/src/index.ts @@ -1,2 +1,4 @@ export const name = "tmdb"; export * from "./search"; +export * from "./details"; +export * from "./util"; diff --git a/packages/tmdb/src/search.ts b/packages/tmdb/src/search.ts index 37f482d..3f99ee7 100644 --- a/packages/tmdb/src/search.ts +++ b/packages/tmdb/src/search.ts @@ -1,9 +1,6 @@ -import type { MovieDetails, TvShowDetails } from "tmdb-ts"; -import { TMDB } from "tmdb-ts"; +import type { MovieWithMediaType, TVWithMediaType } from "tmdb-ts"; -const TMDB_API_KEY = - "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc"; -const tmdb = new TMDB(TMDB_API_KEY); +import { tmdb } from "./util"; export async function searchTitle(query: string) { try { @@ -18,38 +15,8 @@ export async function searchTitle(query: string) { if (!results.length) throw new Error("No results found"); - return results; + return results as unknown as MovieWithMediaType[] | TVWithMediaType[]; } catch (ex) { throw new Error(`Error searching for title: ${(ex as Error).message}`); } } - -export async function fetchMediaDetails( - id: string, - type: "movie" | "tv", -): Promise< - { type: "movie" | "tv"; result: TvShowDetails | MovieDetails } | undefined -> { - try { - let result: TvShowDetails | MovieDetails; - - switch (type) { - case "tv": - result = await tmdb.tvShows.details(parseInt(id, 10)); - break; - case "movie": - result = await tmdb.movies.details(parseInt(id, 10)); - break; - default: - return undefined; - } - - return { type, result }; - } catch (ex) { - return undefined; - } -} - -export function getMediaPoster(posterPath: string): string { - return `https://image.tmdb.org/t/p/w185/${posterPath}`; -} diff --git a/packages/tmdb/src/util.ts b/packages/tmdb/src/util.ts new file mode 100644 index 0000000..9558c2f --- /dev/null +++ b/packages/tmdb/src/util.ts @@ -0,0 +1,9 @@ +import { TMDB } from "tmdb-ts"; + +const TMDB_API_KEY = + "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkYTM1ZTgyMzE4OTc0NTgxNDJmZjljZTE4ODExNWRlNiIsInN1YiI6IjY0OTM0ZDQ1ODliNTYxMDExYzliZDVhMiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.AzWnIcxPNgDwGdzeIZ_C3mRC_5_qy-Z-SRPglLjzlNc"; +export const tmdb = new TMDB(TMDB_API_KEY); + +export function getMediaPoster(posterPath: string): string { + return `https://image.tmdb.org/t/p/w185/${posterPath}`; +} From 0134c0ff929277e24e0aeb399aa2d75b5a511232 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:18:24 +0100 Subject: [PATCH 23/27] refactor: abstract build and release workflows into seperate workflows --- .github/workflows/build-mobile.yml | 54 +--------- .github/workflows/release-mobile.yml | 143 +++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/release-mobile.yml diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index 69d09eb..6ffd7d0 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -1,33 +1,13 @@ name: build mobile app on: - push: - branches: - - master + pull_request: workflow_dispatch: permissions: contents: write -jobs: - bump-version: - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Automated Version Bump - uses: phips28/gh-action-bump-version@v10.1.1 - with: - skip-tag: 'true' - commit-message: 'chore: bump mobile version to {{version}} [skip ci]' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - +jobs: build-android: runs-on: ubuntu-latest @@ -112,33 +92,3 @@ jobs: with: name: ipa path: ./apps/expo/ios/build/movie-web.ipa - - release-app: - runs-on: ubuntu-latest - needs: [build-android, build-ios] - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - merge-multiple: true - - - name: Get package version - id: package-version - uses: martinbeentjes/npm-get-version-action@v1.3.1 - - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 - with: - tag_name: v${{ steps.package-version.outputs.current-version }} - files: | - movie-web.apk - movie-web.ipa - fail_on_unmatched_files: true - token: ${{ env.GITHUB_TOKEN }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release-mobile.yml b/.github/workflows/release-mobile.yml new file mode 100644 index 0000000..d3fd8d5 --- /dev/null +++ b/.github/workflows/release-mobile.yml @@ -0,0 +1,143 @@ +name: release mobile app + +on: + push: + branches: + - master + +permissions: + contents: write + +jobs: + bump-version: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Automated Version Bump + uses: phips28/gh-action-bump-version@v10.1.1 + with: + skip-tag: 'true' + commit-message: 'chore: bump mobile version to {{version}} [skip ci]' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-android: + runs-on: ubuntu-latest + needs: [bump-version] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 21 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install dependencies + run: pnpm install + + - name: Build Android app + run: cd apps/expo && pnpm run apk + + - name: Rename apk + run: cd apps/expo && mv android/app/build/outputs/apk/release/app-release.apk android/app/build/outputs/apk/release/movie-web.apk + + - name: Upload movie-web.apk as artifact + uses: actions/upload-artifact@v4 + with: + name: apk + path: ./apps/expo/android/app/build/outputs/apk/release/movie-web.apk + + build-ios: + runs-on: macos-14 + needs: [bump-version] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Xcode Select Version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15.1.0' + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 21 + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Install dependencies + run: pnpm install + + - name: Build iOS app + run: cd apps/expo && pnpm run ipa + + - name: Export .ipa from .app + run: | + cd apps/expo + mkdir -p ios/build/Build/Products/Release-iphoneos/Payload + mv ios/build/Build/Products/Release-iphoneos/movieweb.app ios/build/Build/Products/Release-iphoneos/Payload/ + cd ios/build/Build/Products/Release-iphoneos + zip -r ../../../movie-web.ipa Payload + + - name: Upload movie-web.ipa as artifact + uses: actions/upload-artifact@v4 + with: + name: ipa + path: ./apps/expo/ios/build/movie-web.ipa + + release-app: + runs-on: ubuntu-latest + needs: [build-android, build-ios] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Get package version + id: package-version + uses: martinbeentjes/npm-get-version-action@v1.3.1 + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ steps.package-version.outputs.current-version }} + files: | + movie-web.apk + movie-web.ipa + fail_on_unmatched_files: true + token: ${{ env.GITHUB_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 519c85a3acf62795d11fc001b5bcb62f5720dd4a Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:30:46 +0100 Subject: [PATCH 24/27] chore: clean stuff in item component --- apps/expo/src/app/components/item/item.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/expo/src/app/components/item/item.tsx b/apps/expo/src/app/components/item/item.tsx index e2bb3c2..f146621 100644 --- a/apps/expo/src/app/components/item/item.tsx +++ b/apps/expo/src/app/components/item/item.tsx @@ -19,9 +19,8 @@ export default function Item({ data }: { data: ItemData }) { {title} From 7941a351117e48c93182502ff8e275fc2be03d1c Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:34:50 +0100 Subject: [PATCH 25/27] chore: don't run this for all pr events --- .github/workflows/build-mobile.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index 6ffd7d0..862a1e6 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -2,6 +2,7 @@ name: build mobile app on: pull_request: + types: [opened, ready_for_review] workflow_dispatch: permissions: From 4e60002bac2191d769d948e7a2f657a547cb0355 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:46:41 +0100 Subject: [PATCH 26/27] fix: search button css on ios is a round boi now --- apps/expo/src/app/(tabs)/_layout.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/expo/src/app/(tabs)/_layout.tsx b/apps/expo/src/app/(tabs)/_layout.tsx index 8e94be1..48a098f 100644 --- a/apps/expo/src/app/(tabs)/_layout.tsx +++ b/apps/expo/src/app/(tabs)/_layout.tsx @@ -1,3 +1,4 @@ +import { View } from "react-native"; import { Tabs } from "expo-router"; import Colors from "@movie-web/tailwind-config/colors"; @@ -55,11 +56,9 @@ export default function TabLayout() { title: "Search", tabBarLabel: "", tabBarIcon: () => ( - + + + ), }} /> From 450ef4dc90be23941b387184248991454c091a57 Mon Sep 17 00:00:00 2001 From: Jorrin Date: Sun, 4 Feb 2024 19:53:45 +0100 Subject: [PATCH 27/27] add no cache option and cleanup --- apps/expo/package.json | 4 ++-- packages/tmdb/src/details.ts | 21 ++++++++------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/expo/package.json b/apps/expo/package.json index acd6aaf..215186c 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -6,8 +6,8 @@ "scripts": { "clean": "git clean -xdf .expo .turbo node_modules", "dev": "expo start", - "dev:android": "expo start --android", - "dev:ios": "expo start --ios", + "dev:android": "expo start -c --android", + "dev:ios": "expo start -c --ios", "android": "expo run:android", "ios": "expo run:ios", "apk": "expo prebuild --platform=android && cd android && ./gradlew assembleRelease", diff --git a/packages/tmdb/src/details.ts b/packages/tmdb/src/details.ts index d5a26c3..d91b048 100644 --- a/packages/tmdb/src/details.ts +++ b/packages/tmdb/src/details.ts @@ -9,20 +9,15 @@ export async function fetchMediaDetails( { type: "movie" | "tv"; result: TvShowDetails | MovieDetails } | undefined > { try { - let result: TvShowDetails | MovieDetails; + const result = + type === "movie" + ? await tmdb.movies.details(parseInt(id, 10)) + : await tmdb.tvShows.details(parseInt(id, 10)); - switch (type) { - case "tv": - result = await tmdb.tvShows.details(parseInt(id, 10)); - break; - case "movie": - result = await tmdb.movies.details(parseInt(id, 10)); - break; - default: - return undefined; - } - - return { type, result }; + return { + type, + result, + }; } catch (ex) { return undefined; }