diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml index e56e3ae9e4..94d416d627 100644 --- a/.github/actions/install-deps/action.yml +++ b/.github/actions/install-deps/action.yml @@ -1,13 +1,11 @@ name: 'Install Dependencies' description: 'Install Node.js dependencies' - runs: using: 'composite' steps: - name: Checkout code uses: actions/checkout@v2 - # Cache yarn packages to speed up installation - name: Cache Yarn packages uses: actions/cache@v2 with: @@ -16,7 +14,6 @@ runs: restore-keys: | ${{ runner.os }}-yarn- - # Install dependencies - name: Install dependencies run: yarn install --immutable - shell: bash + shell: bash \ No newline at end of file diff --git a/.github/actions/setup-js-runtime/action.yml b/.github/actions/setup-js-runtime/action.yml new file mode 100644 index 0000000000..112383ba1b --- /dev/null +++ b/.github/actions/setup-js-runtime/action.yml @@ -0,0 +1,22 @@ +name: 'Setup JS Runtime Environment' +description: 'Sets up Node.js and caches Node modules' +runs: + using: 'composite' + steps: + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: '20.x' + cache: 'yarn' + + - name: Cache Yarn packages + uses: actions/cache@v2 + with: + path: ~/.yarn/cache + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + run: yarn install --immutable + shell: bash diff --git a/.github/labeler.yml b/.github/labeler.yml index 18635eeb6f..f74326c8ad 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,77 +1,61 @@ -# Add 'root' label to any root file changes -# Quotation marks are required for the leading asterisk root: -- changed-files: - - any-glob-to-any-file: '*' + - changed-files: + - any-glob-to-any-file: '*' -## Equivalent of the above mentioned configuration using another syntax docs: -- changed-files: - - any-glob-to-any-file: ['docs/*', 'guides/*', '**/*.md'] + - changed-files: + - any-glob-to-any-file: '{docs/**/*,guides/**/*,**/*.md}' -# Add 'feature' label to any PR where the head branch name starts with `feature` or has a `feature` section in the name feature: - - head-branch: ['^feature', 'feature'] + - head-branch: ['^feature', 'feature'] -# Add 'release' label to any PR that is opened against the `main` branch release: - - base-branch: 'main' + - base-branch: 'main' -# Add 'test' label to any change to *.spec.ts, *.spec.js, *.test.ts, *.test.js files within the entire repository test: -- changed-files: - - any-glob-to-any-file: - - '**/*.spec.ts' - - '**/*.spec.js' - - '**/*.test.ts' - - '**/*.test.js' - - '**/tests/**/*.ts' - - '**/tests/**/*.js' + - changed-files: + - any-glob-to-any-file: + - '**/*.spec.ts' + - '**/*.spec.js' + - '**/*.test.ts' + - '**/*.test.js' + - '**/tests/**/*.ts' + - '**/tests/**/*.js' -# Add 'frontend' label to any change in the 'client' directory frontend: -- changed-files: - - any-glob-to-any-file: - - 'apps/**/*.{ts,js}' - - any: 'apps/**/*.ts' - - any: 'apps/**/*.js' - - all-globs-to-all-files: - - '!apps/src/main.ts' - - '!apps/src/main.js' + - changed-files: + - any-glob-to-any-file: 'apps/**/*.{ts,js, jsx, tsx}' -# Add 'backend' label to any change in the 'server' directory backend: -- changed-files: - - any-glob-to-any-file: 'server/**/*.{ts,js}' + - changed-files: + - any-glob-to-any-file: 'server/**/*.{ts,js}' -# Add the 'AnyChange' label to any changes within the entire repository AnyChange: -- changed-files: - - any-glob-to-any-file: '**' + - changed-files: + - any-glob-to-any-file: '*' -# Add 'client' label to any change in the 'apps' directory client: -- changed-files: - - any-glob-to-any-file: 'apps/**/*' + - changed-files: + - any-glob-to-any-file: 'apps/**/*' -# Add 'expo' label to any changes in the 'apps/expo' directory expo: -- changed-files: - - any-glob-to-any-file: 'apps/expo/**/*' + - changed-files: + - any-glob-to-any-file: 'apps/expo/**/*' -# Add 'next' label to any changes in the 'apps/next' directory next: -- changed-files: - - any-glob-to-any-file: 'apps/next/**/*' + - changed-files: + - any-glob-to-any-file: 'apps/next/**/*' -# Add 'vite' label to any changes in the 'apps/vite' directory vite: -- changed-files: - - any-glob-to-any-file: 'apps/vite/**/*' + - changed-files: + - any-glob-to-any-file: 'apps/vite/**/*' -# Add 'api' label to any changes in the 'api' or 'server' directories api: -- changed-files: - - any-glob-to-any-file: - - 'api/**/*' - - 'server/**/*' + - changed-files: + - any-glob-to-any-file: + - 'api/**/*' + - 'server/**/*' + +github: + - changed-files: + - any-glob-to-any-file: '.github/**/*' \ No newline at end of file diff --git a/.github/scripts/env.ts b/.github/scripts/env.ts index ce02a6c1af..b168d2b054 100644 --- a/.github/scripts/env.ts +++ b/.github/scripts/env.ts @@ -88,4 +88,23 @@ const viteFileContent = envFileContent .join('\n'); fs.writeFileSync(viteOutputPath, `${autogeneratedComment}\n${viteFileContent}`); -// TODO: Add wrangler env generation \ No newline at end of file +// TODO: Add wrangler env generation +/** + * Generate Cloudflare Wrangler .dev.vars file content + */ +// const wranglerOutputPath = path.join(__dirname, '..', '..', 'packages', 'api', '.dev.vars') +// // Remove public variables from output +// const wranglerFileContent = envFileContent +// .split('\n') +// .map((line) => { +// if (line.startsWith('PUBLIC_APP_URL')) return line.replace(/^PUBLIC_APP_URL/, 'APP_URL') +// if (!line.startsWith('PUBLIC_')) { +// return line +// } +// }) +// .join('\n') +// const noD1Warning = 'NO_D1_WARNING=true' +// fs.writeFileSync( +// wranglerOutputPath, +// `${autogeneratedComment}\n${wranglerFileContent}\n${noD1Warning}` +// ) \ No newline at end of file diff --git a/.github/workflows/android-preview-build-local.yml b/.github/workflows/android-preview-build-local.yml index 56e8b3699f..5f97a9cfe3 100644 --- a/.github/workflows/android-preview-build-local.yml +++ b/.github/workflows/android-preview-build-local.yml @@ -1,9 +1,9 @@ name: android-preview-build-local on: push: - branches: [ "**" ] + branches: ['**'] pull_request: - branches: [ "**" ] + branches: ['**'] jobs: update: @@ -65,7 +65,7 @@ jobs: echo "apk_path=${apk_path}" >> $GITHUB_ENV working-directory: apps/expo env: - DEBUG: "true" + DEBUG: 'true' continue-on-error: true - name: Upload APK @@ -74,10 +74,58 @@ jobs: name: android-apk path: /home/runner/work/PackRat/PackRat/apps/expo/build-*.apk - - name: Create Commit Comment - if: github.event_name == 'push' - uses: peter-evans/commit-comment@v2 + - name: Find or create comment + if: github.event_name == 'pull_request' + uses: actions/github-script@v6 + id: find_or_create_comment with: - body: | - Android APK build ${{ steps.build.outcome == 'success' && 'completed' || 'failed' }}! - ${{ steps.build.outcome == 'success' && format('You can download the APK file from the following link:\nhttps://github.com/{0}/actions/runs/{1}#artifacts', github.repository, github.run_id) || 'Please check the workflow logs for more details on the build failure.' }} \ No newline at end of file + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const commentIdentifier = ''; + const comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + const existingComment = comments.data.find(comment => comment.body.startsWith(commentIdentifier)); + + if (existingComment) { + core.setOutput('comment_id', existingComment.id); + } else { + const commentBody = `${commentIdentifier}\nšŸš€ Android APK build started... Please wait for the results! šŸ•`; + const { data: { id: commentId } } = await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); + core.setOutput('comment_id', commentId); + } + + - name: Update PR comment + if: always() && github.event_name == 'pull_request' + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const commentIdentifier = ''; + const commentId = '${{ steps.find_or_create_comment.outputs.comment_id }}'; + const buildOutcome = '${{ steps.build.outcome }}'; + const buildStatus = buildOutcome == 'success' ? 'completed' : 'failed'; + const workflowUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + + let commentBody = `${commentIdentifier}\nAndroid APK build ${buildStatus}!`; + + if (buildOutcome == 'success') { + commentBody += `\nYou can download the APK file from the following link:\n${workflowUrl}#artifacts`; + } else { + commentBody += '\nPlease check the workflow logs for more details on the build failure.'; + } + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: commentBody + }); diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5634a5e352..8b2a6d48aa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,31 +1,51 @@ name: android-build-apk on: push: - branches: [ "**" ] + branches: ['**'] pull_request: - branches: [ "**" ] + branches: ['**'] jobs: install-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Install yarn dependencies - run: | - yarn install + + - name: Install dependencies + uses: ./.github/actions/install-deps build-android: needs: install-and-test runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Install yarn dependencies + + - name: Setup Java + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 20.x + cache: yarn + + - name: Install dependencies + uses: ./.github/actions/install-deps + + - name: Prebuild run: | - yarn install + echo "Using Mapbox Token: $MAPBOX_DOWNLOADS_TOKEN" + export MAPBOX_DOWNLOADS_TOKEN=${{ secrets.MAPBOX_DOWNLOADS_TOKEN }} + yarn run prebuild:expo + - name: Build Android Release run: | cd apps/expo/android && ./gradlew assembleRelease + - name: Upload Artifact uses: actions/upload-artifact@v1 with: name: app-release.apk - path: android/app/build/outputs/apk/release/ \ No newline at end of file + path: android/app/build/outputs/apk/release/ diff --git a/.github/workflows/deployments/backend.yml b/.github/workflows/deployments/backend.yml new file mode 100644 index 0000000000..5b970dd886 --- /dev/null +++ b/.github/workflows/deployments/backend.yml @@ -0,0 +1,54 @@ +name: 'Backend Deployment' + +on: + workflow_dispatch: + push: + branches: + - master + paths: + - 'packages/api/**' + - 'server/**' + +jobs: + deploy: + name: Deploy to Cloudflare Workers + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 1 + + - name: Setup JS Runtime environment + uses: ./.github/actions/setup-js-runtime + + - name: Install dependencies + uses: ./.github/actions/install-deps + + - name: Migrate database + # run: cd packages/api && bun run migrate + run: cd server && yarn run migrate:prod + env: + NO_D1_WARNING: true + CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }} + + - name: Deploy + uses: cloudflare/wrangler-action@v3.3.2 + with: + wranglerVersion: '3.15.0' + apiToken: ${{ secrets.CF_API_TOKEN }} + # workingDirectory: packages/api + workingDirectory: server + command: yarn run deploy:prod + packageManager: bun + secrets: | + APP_URL + JWT_VERIFICATION_KEY + CI + env: + APP_URL: ${{ secrets.NEXT_PUBLIC_APP_URL }} + JWT_VERIFICATION_KEY: ${{ secrets.JWT_VERIFICATION_KEY }} + CI: true + NO_D1_WARNING: true \ No newline at end of file diff --git a/.github/workflows/ios-build-local.yml b/.github/workflows/ios-build-local.yml index c3425d8752..a696a89d70 100644 --- a/.github/workflows/ios-build-local.yml +++ b/.github/workflows/ios-build-local.yml @@ -40,6 +40,7 @@ jobs: yarn run prebuild:expo - name: Build iOS app + id: build run: | echo "Using Mapbox Token: $MAPBOX_DOWNLOADS_TOKEN" export MAPBOX_DOWNLOADS_TOKEN=${{ secrets.MAPBOX_DOWNLOADS_TOKEN }} @@ -54,10 +55,57 @@ jobs: name: app-release path: ${{ github.workspace }}/app-release.ipa - - name: Create Commit Comment - if: github.event_name == 'push' - uses: peter-evans/commit-comment@v2 + - name: Find or create comment + if: github.event_name == 'pull_request' + uses: actions/github-script@v6 + id: find_or_create_comment with: - body: | - iOS app build ${{ steps.build.outcome == 'success' && 'completed' || 'failed' }}! - ${{ steps.build.outcome == 'success' && format('You can download the IPA file from the following link:\nhttps://github.com/{0}/actions/runs/{1}#artifacts', github.repository, github.run_id) || 'Please check the workflow logs for more details on the build failure.' }} + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const commentIdentifier = ''; + const comments = await github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + const existingComment = comments.data.find(comment => comment.body.startsWith(commentIdentifier)); + + if (existingComment) { + core.setOutput('comment_id', existingComment.id); + } else { + const commentBody = `${commentIdentifier}\nšŸš€ iOS app build started... Please wait for the results! šŸ•`; + const { data: { id: commentId } } = await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); + core.setOutput('comment_id', commentId); + } + - name: Update PR comment + if: always() && github.event_name == 'pull_request' + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const commentIdentifier = ''; + const commentId = '${{ steps.find_or_create_comment.outputs.comment_id }}'; + const buildOutcome = '${{ steps.build.outcome }}'; + const buildStatus = buildOutcome == 'success' ? 'completed' : 'failed'; + const workflowUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + + let commentBody = `${commentIdentifier}\niOS app build ${buildStatus}!`; + + if (buildOutcome == 'success') { + commentBody += `\nYou can download the IPA file from the following link:\n${workflowUrl}#artifacts`; + } else { + commentBody += '\nPlease check the workflow logs for more details on the build failure.'; + } + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: commentId, + body: commentBody + }); diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 80d7979334..fe26a89eff 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -6,7 +6,8 @@ # https://github.com/actions/labeler name: Pull request labeler -on: [ pull_request_target ] +on: + - pull_request jobs: label: @@ -22,5 +23,6 @@ jobs: - name: Labeler uses: actions/labeler@v5 + continue-on-error: true with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/node.js.dev.yml b/.github/workflows/node.js.dev.yml index 04b0e3b47b..58da816fae 100644 --- a/.github/workflows/node.js.dev.yml +++ b/.github/workflows/node.js.dev.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] # Operating systems - node-version: [18.x, 20.x, 21.x] # Node.js versions + node-version: [20.x, 22.x] # Node.js versions steps: - name: Checkout Repository diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 93b54380ef..6a54330363 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] # Operating systems - node-version: [18.x, 20.x, 21.x] # Node.js versions + node-version: [20.x, 22.x] # Node.js versions steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 52165f25b2..480e938a25 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,13 +63,16 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | + const commentIdentifier = ''; const commentId = process.env.COMMENT_ID; const testLogs = `${{ steps.run_tests.outputs.stdout }}\n${{ steps.run_tests.outputs.stderr }}`; const testStatus = `${{ steps.run_tests.outcome }}`; + const workflowUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; - let commentBody = '\n'; - let emoji = ''; + const includeTestLogs = false; // Set this to true when you want to include the test logs + let commentBody = `${commentIdentifier}\n`; + let emoji = ''; if (testStatus === 'success') { commentBody += 'āœ… Tests passed successfully! šŸŽ‰\n\n'; emoji = 'šŸ’š'; @@ -78,7 +81,11 @@ jobs: emoji = 'ā¤ļø'; } - commentBody += `
Test Logs\n\n\`\`\`\n${testLogs}\n\`\`\`\n
`; + commentBody += `[View Test Workflow](${workflowUrl})\n\n`; + + if (includeTestLogs) { + commentBody += `
Test Logs\n\n\`\`\`\n${testLogs}\n\`\`\`\n
`; + } await github.rest.issues.updateComment({ owner: context.repo.owner, diff --git a/apps/next/package.json b/apps/next/package.json index b2bb2d0664..90f62dfe52 100644 --- a/apps/next/package.json +++ b/apps/next/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev -p 4000", + "dev": "next dev -p 4200", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/package.json b/package.json index 5a4b600548..f010d85995 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "upgrade:hono": "yarn up '@hono/*'@latest 'hono'@latest", "upgrade:tamagui:canary": "yarn up '*tamagui*'@canary '@tamagui/*'@canary", "upgrade:tamagui": "yarn up '*tamagui*'@latest '@tamagui/*'@latest", + "upgrade:drizzle": "yarn up 'drizzle-*'@latest", "web": "cd apps/next && yarn dev" }, "engines": { diff --git a/packages/app/components/PlacesAutocomplete/PlacesAutocomplete.tsx b/packages/app/components/PlacesAutocomplete/PlacesAutocomplete.tsx index 7e3b8a01d2..82715aaae4 100644 --- a/packages/app/components/PlacesAutocomplete/PlacesAutocomplete.tsx +++ b/packages/app/components/PlacesAutocomplete/PlacesAutocomplete.tsx @@ -1,39 +1,40 @@ -import { forwardRef, useImperativeHandle, useRef } from 'react'; -import { TextInput } from 'react-native'; +import React, { forwardRef, useImperativeHandle, useRef } from 'react'; +import { type TextInput } from 'react-native'; import { SearchInput } from '../SearchInput'; import { RStack, RText } from '@packrat/ui'; import useTheme from 'app/hooks/useTheme'; import { usePlacesAutoComplete } from './usePlacesAutoComplete'; -export const PlacesAutocomplete = forwardRef( - ({ onSelect, placeholder }, ref) => { - const { data, handleSelect, search, setSearch } = - usePlacesAutoComplete(onSelect); - const inputRef = useRef(); +export const PlacesAutocomplete = forwardRef(function PlacesAutoComplete( + { onSelect, placeholder }, + ref, +) { + const { data, handleSelect, search, setSearch } = + usePlacesAutoComplete(onSelect); + const inputRef = useRef(); - useImperativeHandle( - ref, - () => ({ - searchText: search, - focus: () => inputRef.current?.focus(), - }), - [search], - ); + useImperativeHandle( + ref, + () => ({ + searchText: search, + focus: () => inputRef.current?.focus(), + }), + [search], + ); - return ( - } - onChange={setSearch} - searchString={search} - ref={inputRef} - /> - ); - }, -); + return ( + } + onChange={setSearch} + searchString={search} + ref={inputRef} + /> + ); +}); const PlaceItem = ({ item }) => { const { currentTheme } = useTheme(); diff --git a/packages/app/components/PlacesAutocomplete/usePlacesAutoComplete.ts b/packages/app/components/PlacesAutocomplete/usePlacesAutoComplete.ts index b4b7f677fa..7707bf7e40 100644 --- a/packages/app/components/PlacesAutocomplete/usePlacesAutoComplete.ts +++ b/packages/app/components/PlacesAutocomplete/usePlacesAutoComplete.ts @@ -9,7 +9,7 @@ export const usePlacesAutoComplete = (onSelect) => { const handleSelect = (result) => { onSelect(result); - + setSearch(''); // return new value of the input return result.properties.name; }; diff --git a/packages/app/components/SearchInput/SearchInput.tsx b/packages/app/components/SearchInput/SearchInput.tsx index f6d9ad4320..04a50b9e03 100644 --- a/packages/app/components/SearchInput/SearchInput.tsx +++ b/packages/app/components/SearchInput/SearchInput.tsx @@ -1,5 +1,5 @@ -import React, { cloneElement, ReactNode, forwardRef } from 'react'; -import { Platform, TextInput } from 'react-native'; +import React, { cloneElement, type ReactNode, forwardRef } from 'react'; +import { Platform, type TextInput } from 'react-native'; import { MaterialIcons, MaterialCommunityIcons } from '@expo/vector-icons'; import useSearchInput from './useSearchInput'; import useTheme from 'app/hooks/useTheme'; @@ -25,7 +25,7 @@ interface SearchInputProps { } export const SearchInput = forwardRef( - ( + function SearchInput( { onSelect, placeholder, @@ -35,7 +35,7 @@ export const SearchInput = forwardRef( searchString, }, inputRef, - ) => { + ) { const { handleClearSearch, handleSearchResultClick, @@ -243,5 +243,8 @@ const loadStyles = () => ({ marginBottom: 15, maxWidth: 400, width: '100%', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', }, }); diff --git a/packages/app/components/carousel/ScrollButton.tsx b/packages/app/components/carousel/ScrollButton.tsx index 0e8a58aa4a..f8a576ce30 100644 --- a/packages/app/components/carousel/ScrollButton.tsx +++ b/packages/app/components/carousel/ScrollButton.tsx @@ -10,6 +10,7 @@ import { ViewStyle, } from 'react-native'; import useCustomStyles from 'app/hooks/useCustomStyles'; +import useTheme from 'app/hooks/useTheme'; interface ScrollButtonProps { direction: 'left' | 'right'; @@ -19,6 +20,7 @@ interface ScrollButtonProps { const ScrollButton = ({ direction, onPress, disabled }: ScrollButtonProps) => { const styles = useCustomStyles(loadStyles); + const { isDark } = useTheme(); return ( { style={styles.scrollButton} disabled={disabled} > - {direction === 'left' && } - {direction != 'left' && } + {direction === 'left' && } + {direction != 'left' && } ); }; diff --git a/packages/app/components/itemtable/itemTable.tsx b/packages/app/components/itemtable/itemTable.tsx index 18da5ab77e..ceb30136b6 100644 --- a/packages/app/components/itemtable/itemTable.tsx +++ b/packages/app/components/itemtable/itemTable.tsx @@ -147,7 +147,9 @@ export const ItemsTable = ({ * * @return {undefined} This function doesn't return anything. */ - const handleNextPage = () => {}; + const handleNextPage = () => { + setPage(page + 1) + }; /** * Handles the action of going to the previous page. * diff --git a/packages/app/components/pack/AddPack.tsx b/packages/app/components/pack/AddPack.tsx index d4f5a3f47f..6fee06511f 100644 --- a/packages/app/components/pack/AddPack.tsx +++ b/packages/app/components/pack/AddPack.tsx @@ -8,45 +8,50 @@ import { FormSelect, FormInput, SubmitButton, + useModal, } from '@packrat/ui'; import { BaseModal } from '@packrat/ui'; import useTheme from '../../hooks/useTheme'; import useCustomStyles from 'app/hooks/useCustomStyles'; -import { useAddNewPack } from 'app/hooks/packs'; +import { useAddNewPack, usePackId } from 'app/hooks/packs'; import { useRouter } from 'app/hooks/router'; import { addPackSchema } from '@packrat/validations'; -export const AddPack = ({ isCreatingTrip = false }) => { +export const AddPack = ({ isCreatingTrip = false, onSuccess }) => { // Hooks const { enableDarkMode, enableLightMode, isDark, isLight, currentTheme } = useTheme(); const styles = useCustomStyles(loadStyles); const router = useRouter(); + const [_, setPackIdParam] = usePackId(); const { - addNewPack, - isSuccess, - isError, + addNewPackAsync, response, - error, + isError, isLoading, - name, setIsPublic, - isPublic, - setName, packSelectOptions, } = useAddNewPack(); - // routing - if (isSuccess && !isCreatingTrip && response) { - router.push(`/pack/${response.id}`); - } /** * Handles the addition of a pack. * @return {void} */ - const handleAddPack = (data) => { - addNewPack(data); + const handleAddPack = async (data) => { + try { + await addNewPackAsync(data); + onSuccess?.(); + if (!response?.id) { + return; + } + if (!isCreatingTrip) { + router.push(`/pack/${response.id}`); + return; + } + + setPackIdParam(response.id); + } catch {} }; const handleonValueChange = (itemValue) => { @@ -77,7 +82,7 @@ export const AddPack = ({ isCreatingTrip = false }) => { placeholder={'Is Public'} /> @@ -95,11 +100,21 @@ export const AddPack = ({ isCreatingTrip = false }) => { export const AddPackContainer = ({ isCreatingTrip }) => { return ( - + ); }; +const PackModalContent = ({ isCreatingTrip }: { isCreatingTrip?: boolean }) => { + const { setIsModalOpen } = useModal(); + return ( + setIsModalOpen(false)} + /> + ); +}; + const loadStyles = (theme, appTheme) => { const { isDark, currentTheme } = theme; return { diff --git a/packages/app/components/pack/PackDetails.tsx b/packages/app/components/pack/PackDetails.tsx index 4f29e9f5f3..ba31f36556 100644 --- a/packages/app/components/pack/PackDetails.tsx +++ b/packages/app/components/pack/PackDetails.tsx @@ -75,10 +75,10 @@ export function PackDetails() { error={error} additionalComps={ <> - + val} renderItem={({ item }) => { { @@ -93,16 +93,14 @@ export function PackDetails() { ); case SECTION.CTA: return isAuthUserPack ? ( - - setRefetch((prev) => !prev)} - /> - + setRefetch((prev) => !prev)} + /> ) : null; case SECTION.SCORECARD: return ( @@ -152,7 +150,6 @@ const loadStyles = (theme) => { packsContainer: { flexDirection: 'column', minHeight: '100vh', - padding: 25, fontSize: 26, }, @@ -160,10 +157,10 @@ const loadStyles = (theme) => { backgroundColor: currentTheme.colors.white, }, boxStyle: { - padding: 10, + padding: 5, borderRadius: 10, width: '100%', - minHeight: 100, + minHeight: 400, }, }; }; diff --git a/packages/app/hooks/geojson/useGEOLocationSearch.ts b/packages/app/hooks/geojson/useGEOLocationSearch.ts index f9e5f8a95b..fe85057999 100644 --- a/packages/app/hooks/geojson/useGEOLocationSearch.ts +++ b/packages/app/hooks/geojson/useGEOLocationSearch.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { createParam } from '@packrat/crosspath'; interface GeoSearchParams { - osmId?: string; + osmId?: number; osmType?: string; name?: string; } @@ -31,5 +31,13 @@ export const useGEOLocationSearch = (): [ setParams(newSearchParams); }; - return [osm, setGEOLocation]; + const formattedOSM = useMemo( + () => ({ + ...osm, + osmId: Number(osm.osmId), + }), + [osm], + ); + + return [formattedOSM, setGEOLocation]; }; diff --git a/packages/app/hooks/packs/useAddNewPack.ts b/packages/app/hooks/packs/useAddNewPack.ts index 05300ff414..3ec3f737ba 100644 --- a/packages/app/hooks/packs/useAddNewPack.ts +++ b/packages/app/hooks/packs/useAddNewPack.ts @@ -22,6 +22,15 @@ export const useAddNewPack = () => { }); }; + // TODO Refactor pack creation + const addNewPackAsync = (data) => { + return mutation.mutateAsync({ + name: data.name, + is_public: data.isPublic === packSelectOptions[0].value, + owner_id: user?.id, + }); + }; + const mutation = queryTrpc.addPack.useMutation({ onMutate: async (packData) => { utils.getPacks.cancel({ @@ -76,6 +85,7 @@ export const useAddNewPack = () => { return { mutation, addNewPack, + addNewPackAsync, isLoading: mutation.isLoading, isError: mutation.isError, isSuccess: mutation.isSuccess, diff --git a/packages/app/hooks/trips/useCreateTripForm.ts b/packages/app/hooks/trips/useCreateTripForm.ts index ab45511d65..4034d5e1e0 100644 --- a/packages/app/hooks/trips/useCreateTripForm.ts +++ b/packages/app/hooks/trips/useCreateTripForm.ts @@ -21,8 +21,8 @@ export const useCreateTripForm = ( formatCreateTripValuesForAPI, ); - const togglePlace = (value: any) => { - setTripValue('destination', value); + const togglePlace = (name: 'trail' | 'park', value: any) => { + setTripValue(name, store[name] !== value ? value : ''); }; const createTripFormValues = useMemo>>( diff --git a/packages/app/hooks/weather/useFetchWeather.ts b/packages/app/hooks/weather/useFetchWeather.ts index d36c9be6ea..fb31640db2 100644 --- a/packages/app/hooks/weather/useFetchWeather.ts +++ b/packages/app/hooks/weather/useFetchWeather.ts @@ -1,6 +1,4 @@ import { queryTrpc } from '../../trpc'; -import { store } from '../../store/store'; -import { useState, useEffect } from 'react'; export const useFetchWeather = (latLng, isDisabled = false) => { const { lat, lon } = latLng || {}; diff --git a/packages/app/hooks/weather/useFetchWeatherWeek.ts b/packages/app/hooks/weather/useFetchWeatherWeek.ts index 65c6bc7bbf..379df11f5d 100644 --- a/packages/app/hooks/weather/useFetchWeatherWeek.ts +++ b/packages/app/hooks/weather/useFetchWeatherWeek.ts @@ -3,6 +3,7 @@ import { queryTrpc } from '../../trpc'; export const useFetchWeatherWeak = (latLng, isDisabled = false) => { const { lat, lon } = latLng || {}; const isEnabled = !isDisabled && Boolean(lat && lon); + const { refetch, data, error, isLoading, isError } = queryTrpc.getWeatherWeek.useQuery( { lat, lon }, diff --git a/packages/app/screens/about/AboutContent.tsx b/packages/app/screens/about/AboutContent.tsx index d0c1cf678b..6fe73a80d4 100644 --- a/packages/app/screens/about/AboutContent.tsx +++ b/packages/app/screens/about/AboutContent.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { View, Text } from 'react-native'; +import { View, Text , ScrollView} from 'react-native'; import { FontAwesome, MaterialCommunityIcons } from '@expo/vector-icons'; import { RButton, RStack } from '@packrat/ui'; import useTheme from '../../hooks/useTheme'; @@ -22,7 +22,7 @@ const AboutContent = ({ desktopContainer, isMobile }: AboutContentProps) => { const { handleGithubLink, handleDiscordLink, aboutSections } = useAbout(); return ( - + @@ -67,7 +67,7 @@ const AboutContent = ({ desktopContainer, isMobile }: AboutContentProps) => { - + ); }; diff --git a/packages/app/screens/trip/createTrip.tsx b/packages/app/screens/trip/createTrip.tsx index 2b411b7336..e94c7cce53 100644 --- a/packages/app/screens/trip/createTrip.tsx +++ b/packages/app/screens/trip/createTrip.tsx @@ -65,13 +65,13 @@ export default function Trips() { )} togglePlace('trail', trail)} + selectedValue={tripStore.trail} /> togglePlace('park', park)} + selectedValue={tripStore.park} /> diff --git a/packages/validations/src/validations/tripRoutesValidator.ts b/packages/validations/src/validations/tripRoutesValidator.ts index a53732dfc1..180be8c363 100644 --- a/packages/validations/src/validations/tripRoutesValidator.ts +++ b/packages/validations/src/validations/tripRoutesValidator.ts @@ -48,6 +48,8 @@ export const addTripDetails = z.object({ start_date: z.string(), end_date: z.string(), destination: z.string(), + park: z.string().optional(), + trail: z.string().optional(), geoJSON: z.object({ type: z.literal('FeatureCollection'), features: z.array(featureSchema), diff --git a/server/migrations/0001_same_iron_patriot.sql b/server/migrations/0001_same_iron_patriot.sql new file mode 100644 index 0000000000..ab10bdc3cb --- /dev/null +++ b/server/migrations/0001_same_iron_patriot.sql @@ -0,0 +1,10 @@ +-- This is a dummy migration +-- It does nothing +SELECT 1;--> statement-breakpoint +/* + SQLite does not support "Creating foreign key on existing column" out of the box, we do not generate automatic migration for that, so it has to be done manually + Please refer to: https://www.techonthenet.com/sqlite/tables/alter_table.php + https://www.sqlite.org/lang_altertable.html + + Due to that we don't generate migration automatically and it has to be done manually +*/ \ No newline at end of file diff --git a/server/migrations/0003_conversation_schema_update.sql b/server/migrations/0003_conversation_schema_update.sql index d6647c4ab8..9e13a3eff4 100644 --- a/server/migrations/0003_conversation_schema_update.sql +++ b/server/migrations/0003_conversation_schema_update.sql @@ -1,24 +1 @@ -BEGIN TRANSACTION; --- Create a new table with the desired schema -CREATE TABLE conversation_new ( - id TEXT PRIMARY KEY NOT NULL, - user_id TEXT NOT NULL, - history TEXT, - itemTypeId TEXT NOT NULL, - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP -); --- Copy all data from the old table to the new table -INSERT INTO conversation_new (id, user_id, history, created_at, updated_at) -SELECT id, - user_id, - history, - created_at, - updated_at -FROM conversation; --- Drop the old table -DROP TABLE conversation; --- Rename the new table to the old table's name -ALTER TABLE conversation_new - RENAME TO conversation; -COMMIT; \ No newline at end of file +select 1; \ No newline at end of file diff --git a/server/package.json b/server/package.json index 703a16018a..ac5ffeff20 100644 --- a/server/package.json +++ b/server/package.json @@ -17,15 +17,14 @@ "test:expect": "mocha 'generated/test/**/*.spec.js'", "test:generate": "npx openapi-generator url http://localhost:3000/swagger.json -d ./generated -t javascript", "test": "vitest", - "prisma:format": "npx prisma format --schema=src/prisma/schema.prisma", - "prisma:generate": "npx prisma generate --schema=src/prisma/schema.prisma --data-proxy", - "prisma:validate": "npx prisma validate --schema=src/prisma/schema.prisma", - "prisma:pull": "npx prisma db pull --schema=src/prisma/schema.prisma", "wrangler:dev": "npx wrangler dev --port 8787 --local", "wrangler:dev2": "npx wrangler pages dev --proxy 3001 --local --persist-to=./db.sqlite --d1=DB -- npm run dev", "generate": "drizzle-kit generate:sqlite --schema=./src/db/schema.ts --out=./migrations", - "migrate": "wrangler d1 migrations apply production", + "migrate": "yarn run migrate:local", + "migrate:prod": "wrangler d1 migrations apply production --remote", "migrate:local": "wrangler d1 migrations apply production --local", + "migrate:down": "yarn run migrate:down:local", + "migrate:down:local": "drizzle-kit drop", "seed": "wrangler d1 execute production --file=./seed/seed.sql", "seed:local": "wrangler d1 execute production --local --file=./seed/seed.sql", "studio": "drizzle-kit studio", @@ -67,17 +66,17 @@ "cors": "^2.8.5", "csurf": "^1.11.0", "dotenv": "^16.0.3", - "drizzle-orm": "^0.30.7", + "drizzle-orm": "^0.30.10", "drizzle-zod": "^0.5.1", "eslint-plugin-drizzle": "^0.2.3", - "express": "^4.18.2", + "express": "^4.19.2", "express-rate-limit": "^6.9.0", "firebase": "^9.19.1", "firebase-admin": "^11.5.0", "google-auth-library": "^8.8.0", "googleapis": "^118.0.0", "helmet": "^7.0.0", - "hono": "^4.2.6", + "hono": "^4.2.7", "http2": "^3.3.7", "i": "^0.3.7", "joi": "^17.9.2", @@ -118,7 +117,7 @@ "@types/jest": "^29.5.11", "@typescript-eslint/eslint-plugin": "^6.21.0", "cross-env": "^7.0.3", - "drizzle-kit": "^0.20.14", + "drizzle-kit": "^0.20.17", "eslint": "^8.56.0", "eslint-config-prettier": "^9.0.0", "eslint-config-standard-with-typescript": "^38.0.0", diff --git a/yarn.lock b/yarn.lock index 44b460211f..320aa21730 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16571,7 +16571,7 @@ __metadata: languageName: node linkType: hard -"drizzle-kit@npm:^0.20.14": +"drizzle-kit@npm:^0.20.17": version: 0.20.17 resolution: "drizzle-kit@npm:0.20.17" dependencies: @@ -16598,7 +16598,7 @@ __metadata: languageName: node linkType: hard -"drizzle-orm@npm:^0.30.7": +"drizzle-orm@npm:^0.30.10": version: 0.30.10 resolution: "drizzle-orm@npm:0.30.10" peerDependencies: @@ -19513,7 +19513,7 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.17.3, express@npm:^4.18.2, express@npm:^4.19.2": +"express@npm:^4.17.3, express@npm:^4.19.2": version: 4.19.2 resolution: "express@npm:4.19.2" dependencies: @@ -21342,14 +21342,7 @@ __metadata: languageName: node linkType: hard -"hono@npm:^4.1.4, hono@npm:^4.2.6": - version: 4.2.9 - resolution: "hono@npm:4.2.9" - checksum: 10/b35ab755b84dbb649138b16889b5e7b752391cadb4a73f658af9e2c0133a6db28f472125f6ba996d3353e25b4d85d15ed724c3fe0f178b969e65d7324c108731 - languageName: node - linkType: hard - -"hono@npm:^4.2.7": +"hono@npm:^4.1.4, hono@npm:^4.2.7": version: 4.2.9 resolution: "hono@npm:4.2.9" checksum: 10/b35ab755b84dbb649138b16889b5e7b752391cadb4a73f658af9e2c0133a6db28f472125f6ba996d3353e25b4d85d15ed724c3fe0f178b969e65d7324c108731 @@ -31395,8 +31388,8 @@ __metadata: cross-env: "npm:^7.0.3" csurf: "npm:^1.11.0" dotenv: "npm:^16.0.3" - drizzle-kit: "npm:^0.20.14" - drizzle-orm: "npm:^0.30.7" + drizzle-kit: "npm:^0.20.17" + drizzle-orm: "npm:^0.30.10" drizzle-zod: "npm:^0.5.1" eslint: "npm:^8.56.0" eslint-config-prettier: "npm:^9.0.0" @@ -31408,14 +31401,14 @@ __metadata: eslint-plugin-prettier: "npm:^5.0.0" eslint-plugin-promise: "npm:^6.1.1" expect.js: "npm:^0.3.1" - express: "npm:^4.18.2" + express: "npm:^4.19.2" express-rate-limit: "npm:^6.9.0" firebase: "npm:^9.19.1" firebase-admin: "npm:^11.5.0" google-auth-library: "npm:^8.8.0" googleapis: "npm:^118.0.0" helmet: "npm:^7.0.0" - hono: "npm:^4.2.6" + hono: "npm:^4.2.7" http2: "npm:^3.3.7" i: "npm:^0.3.7" jest: "npm:^29.7.0"