feat: expo upgrade, fix config, enhance ui, add animations#49
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds many Expo skill docs and references; upgrades frontend to Expo/React/React Native SDK 55; applies entrance animations across UI; consolidates email+OTP login flow with configurable resend sender; adds CI/CD tooling (fetch cache + YAML validator); updates backend auth config and sender validation; redesigns screens/components and routing to a tabs layout. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant LoginScreen
participant Convex
participant ResendAPI as Resend API
participant Email
User->>LoginScreen: Submit email
LoginScreen->>Convex: create OTP request
Convex->>Convex: validate AUTH_RESEND_FROM & API key
Convex->>ResendAPI: POST email payload (sender = AUTH_RESEND_FROM)
ResendAPI->>Email: Deliver OTP
Email-->>User: OTP received
User->>LoginScreen: Submit OTP
LoginScreen->>Convex: verify OTP
Convex-->>LoginScreen: auth session/token
LoginScreen->>User: navigate into app
sequenceDiagram
participant Component
participant Hook as useEntranceAnimation
participant NativeDriver as Animated Native Driver
Component->>Hook: call useEntranceAnimation(delay,distance)
Hook->>NativeDriver: create opacity & translateY animated values (native driver)
Component->>NativeDriver: start parallel animation (320ms, cubic, delay)
NativeDriver->>Component: update animated styles each frame
Component->>Component: render with animated style applied
Component->>NativeDriver: on unmount -> stop animations
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
98ebfde to
a002909
Compare
There was a problem hiding this comment.
Actionable comments posted: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
frontend/app/auth/login.tsx (2)
55-71:⚠️ Potential issue | 🟡 MinorEnforce numeric OTP format, not only length
Current validation accepts any 8-character string. Since the UI asks for an 8-digit code, validate digits explicitly before submit.
Suggested fix
const handleVerifyCode = async () => { - if (!code.trim() || code.trim().length !== 8) { + const normalizedCode = code.trim(); + if (!/^\d{8}$/.test(normalizedCode)) { setError('Please enter the 8-digit code'); return; } @@ try { - await signIn('resend-otp', { email: step.email, code: code.trim() }); + await signIn('resend-otp', { email: step.email, code: normalizedCode }); // On success, redirect to home router.replace('/');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 55 - 71, The OTP validation in handleVerifyCode currently only checks length and non-empty; update the validation to require exactly 8 numeric digits (e.g., test code against /^\d{8}$/) before calling signIn('resend-otp'); if the check fails setError('Please enter the 8-digit numeric code') and return. Locate the handler function handleVerifyCode and the variables code and step to implement this stricter validation and keep subsequent flow (setIsLoading, setError(null), try/await signIn(...)) unchanged.
41-43:⚠️ Potential issue | 🟡 MinorClear stale success state when changing auth actions
successMessageis not cleared in send/verify/back handlers, so old success text can persist into unrelated states (including alongside new errors).Suggested fix
const handleSendCode = async () => { @@ setIsLoading(true); setError(null); + setSuccessMessage(null); @@ const handleVerifyCode = async () => { @@ setIsLoading(true); setError(null); + setSuccessMessage(null); @@ const handleBack = () => { setStep('email'); setCode(''); setError(null); + setSuccessMessage(null); };Also applies to: 66-68, 100-104
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 41 - 43, Old success text can persist because successMessage isn't cleared; wherever you set loading or clear errors (the spots calling setIsLoading(true) and setError(null)) also call the success setter (e.g., setSuccessMessage(null) or setSuccessMessage('')) so the success state is reset. Update the send, verify and back handlers (the functions handling send/verify/back actions) to clear successMessage at the start, mirroring the setIsLoading/setError calls so no stale success text remains when switching actions.frontend/app/(tabs)/index.tsx (1)
92-105:⚠️ Potential issue | 🟠 MajorAvoid one-time gating for initial cursor updates.
Like the search screen, this block can lock first-page data after first render because the initial cursor is marked processed and never reapplied.
🔧 Suggested fix
- if (!processedCursorsRef.current.has(cursorId)) { - if (cursor === null) { - // First page - replace all listings - setAllListings(listingsResult.page); - } else { - // Subsequent pages - append to existing listings - setAllListings((prev) => [...prev, ...listingsResult.page]); - } - setIsDone(listingsResult.isDone); - setIsLoadingMore(false); - - // Mark this cursor as processed - processedCursorsRef.current.add(cursorId); - } + if (cursor === null) { + // Keep initial page reactive for live updates. + setAllListings(listingsResult.page); + setIsDone(listingsResult.isDone); + setIsLoadingMore(false); + return; + } + + if (!processedCursorsRef.current.has(cursorId)) { + setAllListings((prev) => [...prev, ...listingsResult.page]); + setIsDone(listingsResult.isDone); + setIsLoadingMore(false); + processedCursorsRef.current.add(cursorId); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/`(tabs)/index.tsx around lines 92 - 105, The current logic uses processedCursorsRef.current.add(cursorId) to permanently skip reapplying the same cursorId, which can lock the initial page and prevent updates when the first-page data changes; modify the handling in the block around processedCursorsRef, cursorId, cursor, setAllListings and listingsResult.page so that initial cursor updates are not one-time gated — for example only treat cursorId as processed for pagination loads (when cursor !== null) or use a more specific key (e.g., include a version/timestamp) before adding to processedCursorsRef, and ensure setIsDone and setIsLoadingMore are still updated on new first-page responses rather than skipping when cursorId was seen before.
🟡 Minor comments (23)
.agents/skills/expo-dev-client/SKILL.md-93-99 (1)
93-99:⚠️ Potential issue | 🟡 MinorAdd simulator build profile prerequisite to iOS simulator installation instructions.
The simulator installation steps extract a
.appfrom a.tar.gz, but the earlier documentation states that iOS local builds output.ipaby default. The.app-in-.tar.gzoutput only occurs when building withios.simulator: true. Without this prerequisite, users will fail to find the expected.appartifact. Add a note clarifying the required build profile:Proposed fix
Install iOS build on simulator: ```bash -# Find the .app in the .tar.gz output +# Requires a simulator build profile (e.g., `"ios": { "simulator": true }`) +# Find the .app in the .tar.gz output tar -xzf build-*.tar.gz xcrun simctl install booted ./path/to/App.app</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/expo-dev-client/SKILL.md around lines 93 - 99, Add a
prerequisite note to the "Install iOS build on simulator" instructions
clarifying that the .app inside a .tar.gz is produced only for simulator builds
(e.g., set ios.simulator: true) so users know to use a simulator build profile;
update the explanatory text immediately above the tar/xcrun commands in the same
code block (the lines starting with "tar -xzf build-*.tar.gz" and "xcrun simctl
install booted ./path/to/App.app") to include this requirement.</details> </blockquote></details> <details> <summary>.agents/skills/use-dom/SKILL.md-198-205 (1)</summary><blockquote> `198-205`: _⚠️ Potential issue_ | _🟡 Minor_ **Fix mismatch between CSS import path and comment.** Line 204 says “CSS file in same directory,” but `@/styles.css` typically points to an alias/root path, not same directory. Update either the comment or import path to avoid confusion. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/use-dom/SKILL.md around lines 198 - 205, The comment next to
the CSS import in components/styled-component.tsx is misleading: it says “CSS
file in same directory” but the import uses the root alias '@/styles.css';
either change the import to a relative path (e.g., './styles.css') to match the
comment or update the comment to reflect that '@/styles.css' is a root/alias
path; edit the 'use dom' component file and adjust either the import statement
or the comment so they consistently describe the file location.</details> </blockquote></details> <details> <summary>.agents/skills/use-dom/SKILL.md-63-75 (1)</summary><blockquote> `63-75`: _⚠️ Potential issue_ | _🟡 Minor_ **Make `dom` prop guidance consistent across examples.** Line 63 says “Always type it,” but examples alternate between required and optional `dom`. Please standardize the rule (required vs optional) and align all snippets to it. Also applies to: 129-133, 160-161, 180-181, 294-295, 316-317 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/use-dom/SKILL.md around lines 63 - 75, The docs alternate
between making the dom prop optional and required—standardize to a required dom
prop: update every example (including the snippet with interface Props and
MyComponent and the other occurrences at the noted ranges) to include dom:
import('expo/dom').DOMProps in the Props interface and to destructure dom from
the component parameters (e.g., function MyComponent({ content, dom }: Props)),
and ensure the prose (“Always type it”) and all code examples consistently show
dom as a required prop rather than optional.</details> </blockquote></details> <details> <summary>.agents/skills/upgrading-expo/references/react-19.md-22-22 (1)</summary><blockquote> `22-22`: _⚠️ Potential issue_ | _🟡 Minor_ **Tighten sentence grammar.** Line 22 should read “This simplifies…” instead of a comma splice. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/upgrading-expo/references/react-19.md at line 22, The
sentence "usecan be called conditionally, this simplifies components that
consume multiple contexts." contains a comma splice; change it to two sentences
by replacing the comma with a period and capitalizing "This" so it reads "use
can be called conditionally. This simplifies components that consume multiple
contexts." Ensure the exact phrase is updated wherever it appears in the
referenced markdown.</details> </blockquote></details> <details> <summary>frontend/tsconfig.json-18-18 (1)</summary><blockquote> `18-18`: _⚠️ Potential issue_ | _🟡 Minor_ **Verify that Expo-generated type includes won't be needed if generated files are created.** Line 18 restricts the include to `["**/*.ts", "**/*.tsx"]`. While `expo-env.d.ts` and `.expo/` directory don't currently exist, the codebase actively uses `EXPO_PUBLIC_*` environment variables and Expo Router's typed route parameters (`useLocalSearchParams<>`). If Expo generates ambient type files via `expo prebuild` or similar tooling, the current tsconfig won't pick them up because those generated files would fall outside the narrowed include pattern. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@frontend/tsconfig.jsonat line 18, The tsconfig "include" is currently
limited to ["/*.ts","/.tsx"] so Expo-generated ambient declaration files
(e.g., expo-env.d.ts or files under .expo/) and other .d.ts files (needed for
EXPO_PUBLIC_ env types and useLocalSearchParams<> route types) won't be picked
up; update the tsconfig include to also capture declaration and Expo-generated
files—e.g., add patterns like "/*.d.ts" and ".expo/" or explicitly include
"expo-env.d.ts"—so TypeScript will load those ambient types used by
EXPO_PUBLIC_* and useLocalSearchParams.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/gradients.md-111-111 (1)</summary><blockquote> `111-111`: _⚠️ Potential issue_ | _🟡 Minor_ **Soften the absolute prohibition on `expo-linear-gradient` to reflect it as a preference.** The package is not deprecated and remains officially supported in Expo SDKs. Line 111's "Do NOT use" language is too absolute. Reframe as: "Prefer CSS gradients when they align with your target platform requirements and New Architecture compatibility goals." <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/gradients.md at line 111,
Update the phrasing at the line currently saying "Do NOT use
expo-linear-gradient— use CSS gradients instead" to soften the prohibition:
replace it with guidance such as "Prefer CSS gradients when they align with your
target platform requirements and New Architecture compatibility goals;
expo-linear-gradientremains supported and may be used when appropriate."
Ensure the new sentence explicitly framesexpo-linear-gradientas a supported
option rather than deprecated while still recommending CSS gradients as the
preferred approach for stated goals.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/zoom-transitions.md-155-155 (1)</summary><blockquote> `155-155`: _⚠️ Potential issue_ | _🟡 Minor_ **Fix hyphenation typo.** Line 155 should use “off-screen” for correct compound adjective usage. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/zoom-transitions.md at line
155, Replace the phrase "scrolled off screen" in the sentence "When source is
unavailable (e.g., scrolled off screen), the transition zooms from the center of
the screen" with the hyphenated compound adjective "off-screen" so the line
reads "When source is unavailable (e.g., scrolled off-screen), the transition
zooms from the center of the screen"; update the text in the zoom-transitions.md
file accordingly.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/search.md-164-173 (1)</summary><blockquote> `164-173`: _⚠️ Potential issue_ | _🟡 Minor_ **Update this NativeTabs example to match the SDK 55 syntax documented in tabs.md.** Lines 167-172 use standalone `<Label>` and `<Icon>` components, but this conflicts with the SDK 55 pattern established in your tabs.md reference guide, which documents these as `NativeTabs.Trigger.Label` and `NativeTabs.Trigger.Icon`. Align search.md with your documented API for consistency. <details> <summary>Proposed doc fix</summary> ```diff <NativeTabs> <NativeTabs.Trigger name="(home)"> - <Label>Home</Label> - <Icon sf="house.fill" /> + <NativeTabs.Trigger.Label>Home</NativeTabs.Trigger.Label> + <NativeTabs.Trigger.Icon sf="house.fill" md="home" /> </NativeTabs.Trigger> <NativeTabs.Trigger name="(search)" role="search"> - <Label>Search</Label> + <NativeTabs.Trigger.Label>Search</NativeTabs.Trigger.Label> </NativeTabs.Trigger> </NativeTabs>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/search.md around lines 164 - 173, The NativeTabs example uses standalone Label and Icon components which conflict with SDK 55 API; update the app/_layout.tsx example to use the nested SDK 55 form by replacing the standalone components inside NativeTabs.Trigger with NativeTabs.Trigger.Label and NativeTabs.Trigger.Icon so the triggers read NativeTabs.Trigger.Label and NativeTabs.Trigger.Icon (keep NativeTabs and NativeTabs.Trigger as-is)..agents/skills/building-native-ui/SKILL.md-14-30 (1)
14-30:⚠️ Potential issue | 🟡 MinorSpecify code-block languages for the two plain fenced blocks.
Both blocks currently trigger
MD040and may fail markdown lint checks.🛠 Suggested patch
-``` +```text references/ animations.md Reanimated: entering, exiting, layout, scroll-driven, gestures controls.md Native iOS: Switch, Slider, SegmentedControl, DateTimePicker, Picker ... -``` +``` ... -``` +```text app/ _layout.tsx — <NativeTabs /> (index,search)/ _layout.tsx — <Stack /> index.tsx — Main list search.tsx — Search view -``` +```Also applies to: 249-256
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/SKILL.md around lines 14 - 30, The fenced code blocks in SKILL.md (the "references/" list block and the "app/" list block around the example sections) are plain fences and trigger MD040; update both fenced blocks to specify a language (e.g., change the opening ``` to ```text) so the markdown linter accepts them, ensuring you modify the block that contains the references/ list and the block that contains the app/ layout example (also apply the same change at the other occurrence around lines 249-256)..agents/skills/building-native-ui/SKILL.md-24-25 (1)
24-25:⚠️ Potential issue | 🟡 MinorResolve conflicting storage guidance.
This reference line says
storage.mdcovers AsyncStorage, but the storage reference explicitly says to never use AsyncStorage. Please align this to one recommendation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/SKILL.md around lines 24 - 25, The SKILL.md index currently lists "storage.md SQLite, AsyncStorage, SecureStore" which conflicts with the storage guidance that forbids AsyncStorage; update the SKILL.md entry to match the canonical guidance by removing AsyncStorage and listing only approved options (e.g., "storage.md SQLite, SecureStore" or whichever approved set your storage reference mandates). Make the change to the SKILL.md line that mentions storage.md so the index and storage.md guidance are consistent..agents/skills/expo-api-routes/SKILL.md-35-43 (1)
35-43:⚠️ Potential issue | 🟡 MinorAdd a language identifier to the fenced directory-tree block.
This currently violates
MD040and can fail docs lint checks.🛠 Suggested patch
-``` +```text app/ api/ hello+api.ts → GET /api/hello users+api.ts → /api/users users/[id]+api.ts → /api/users/:id (tabs)/ index.tsx</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/expo-api-routes/SKILL.md around lines 35 - 43, The fenced
directory-tree block that begins withand contains the lines starting with "app/", "api/", and the file listings should include a language identifier to satisfy MD040; change the opening fence fromtotext so the block becomes a labeled code block (e.g., replace the existingbefore the directory tree
with ```text).</details> </blockquote></details> <details> <summary>frontend/components/PriceRangePicker.tsx-36-36 (1)</summary><blockquote> `36-36`: _⚠️ Potential issue_ | _🟡 Minor_ **Entrance animation likely runs only once per component mount.** Because the hook animation starts on mount, reopening the modal may skip the entrance transition. Please trigger/restart animation on `visible` transitions. <details> <summary>🎬 Suggested direction</summary> ```diff - const entranceStyle = useEntranceAnimation(40, 8); + const entranceStyle = useEntranceAnimation(visible, 40, 8); ``` ```ts // frontend/hooks/useEntranceAnimation.ts export function useEntranceAnimation(visible: boolean, delay = 0, distance = 16) { // reset values and start animation when `visible` becomes true } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/components/PriceRangePicker.tsx` at line 36, The entrance animation currently only runs on mount because useEntranceAnimation is called without the modal visibility state; update PriceRangePicker to pass the modal `visible` (or `isOpen`) boolean into useEntranceAnimation (e.g., useEntranceAnimation(visible, 40, 8)) and modify the hook signature useEntranceAnimation(visible: boolean, delay = 0, distance = 16) so the hook resets animation values and re-triggers the animation whenever `visible` becomes true (reset internal animated values/timers on visible transitions and start the entrance animation). ``` </details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/tabs.md-305-309 (1)</summary><blockquote> `305-309`: _⚠️ Potential issue_ | _🟡 Minor_ **Add a language tag to the route-structure fenced block.** This block triggers `MD040` and can fail docs lint checks. <details> <summary>🛠 Suggested patch</summary> ```diff -``` +```text app/ _layout.tsx # NativeTabs for iOS/Android _layout.web.tsx # Headless tabs for web (expo-router/ui) -``` +``` ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/tabs.md around lines 305 - 309,
The fenced route-structure block containing the lines "_layout.tsx #
NativeTabs for iOS/Android" and "_layout.web.tsx # Headless tabs for web
(expo-router/ui)" needs a language tag to satisfy MD040; update the opening
fence fromtotext so the block is explicitly marked as plain text (leave
the closing fence unchanged) to fix the lint error in tabs.md.</details> </blockquote></details> <details> <summary>.agents/skills/native-data-fetching/SKILL.md-16-20 (1)</summary><blockquote> `16-20`: _⚠️ Potential issue_ | _🟡 Minor_ **Specify fence languages for code blocks (MD040).** Line 16 and Line 415 should label fenced blocks for markdownlint compliance. <details> <summary>📝 Proposed fix</summary> ```diff -``` +```text references/ expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+) ``` ```diff -``` +```text User asks about networking |-- Route-level data loading (web, SDK 55+)? @@ \-- Cancellation -> AbortController or React Query ``` ``` </details> Also applies to: 415-449 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/native-data-fetching/SKILL.md around lines 16 - 20, Add
explicit fence languages to the two unlabeled fenced code blocks in
.agents/skills/native-data-fetching/SKILL.md (the block around the "references/"
listing near the top and the larger example block around lines ~415-449). Change
the triple-backtick lines to include a language token (e.g., ```text) so both
fenced blocks are labeled for markdownlint MD040; update both occurrences (the
brief "references/" block and the longer example block) to use the same or
appropriate language label.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/webgpu-three.md-492-503 (1)</summary><blockquote> `492-503`: _⚠️ Potential issue_ | _🟡 Minor_ **Add language tags to fenced code blocks to satisfy lint.** Line 492 and Line 507 use unlabeled fenced blocks; markdownlint MD040 flags these. <details> <summary>📝 Proposed fix</summary> ```diff -``` +```text src/ ├── app/ │ └── index.tsx # Entry point with lazy loading @@ └── complex scenes → LOD (Level of Detail) -``` +``` ``` ```diff -``` +```text Need 3D graphics? ├── Simple shapes → mesh + geometry + material @@ └── Complex scenes → LOD (Level of Detail) -``` +``` ``` </details> Also applies to: 507-523 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/webgpu-three.md around lines
492 - 503, The markdown has unlabeled fenced code blocks in
.agents/skills/building-native-ui/references/webgpu-three.md (the block starting
with "src/" and the block starting with "Need 3D graphics?") which trigger
markdownlint MD040; add a language tag (e.g.,text) to both opening fences for those two blocks so they are labeled, ensuring the closing fences remain
and no block content changes; update the instances around the "src/" tree and
the "Need 3D graphics?" list accordingly.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/media.md-5-5 (1)</summary><blockquote> `5-5`: _⚠️ Potential issue_ | _🟡 Minor_ **Hyphenate compound adjective for clarity.** At Line 5, use “full-screen camera” instead of “full screen camera.” <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/media.md at line 5, Edit the phrase in the markdown content where it currently reads "full screen camera" and change it to the hyphenated compound adjective "full-screen camera" (e.g., update the line that says "Hide navigation headers when there's a full screen camera" to "Hide navigation headers when there's a full-screen camera") to improve clarity. ``` </details> </blockquote></details> <details> <summary>.agents/skills/native-data-fetching/SKILL.md-497-500 (1)</summary><blockquote> `497-500`: _⚠️ Potential issue_ | _🟡 Minor_ **Fix env var name typo in examples.** Line 497 and Line 500 use `EXPO*PUBLIC*`; this should be `EXPO_PUBLIC_` to avoid confusion. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/native-data-fetching/SKILL.md around lines 497 - 500, Replace the incorrect env var prefix `EXPO*PUBLIC*` used in the examples and explanatory text with the correct `EXPO_PUBLIC_` prefix (e.g., `EXPO_PUBLIC_MY_API_KEY`) across the SKILL.md examples that mention .env.development and .env.production, and update any surrounding guidance so client-safe keys are shown using `EXPO_PUBLIC_` while secret keys remain unprefixed for API routes. ``` </details> </blockquote></details> <details> <summary>.agents/skills/expo-cicd-workflows/scripts/validate.js-59-64 (1)</summary><blockquote> `59-64`: _⚠️ Potential issue_ | _🟡 Minor_ **Return success exit code for explicit help.** At Line 59–Line 64, `--help` currently exits with code `1` when no files are supplied. Help output should exit `0`. <details> <summary>✅ Proposed fix</summary> ```diff - if (files.length === 0 || args.includes('--help') || args.includes('-h')) { + const showHelp = args.includes('--help') || args.includes('-h'); + if (files.length === 0 || showHelp) { console.log(`Usage: validate <workflow.yml> [workflow2.yml ...] Validates EAS workflow YAML files against the official schema.`); - process.exit(files.length === 0 ? 1 : 0); + process.exit(showHelp ? 0 : 1); } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 59 - 64, Change the exit logic in the help/usage branch so explicit help always returns success: in the if block that checks (files.length === 0 || args.includes('--help') || args.includes('-h')), update the process.exit(...) call to return 0 when args includes '--help' or '-h' and only return 1 when files.length === 0 and help flags are not present; reference the existing variables/expressions files, args.includes('--help'), args.includes('-h'), and the process.exit(...) invocation to locate and adjust the conditional. ``` </details> </blockquote></details> <details> <summary>.agents/skills/expo-deployment/SKILL.md-123-125 (1)</summary><blockquote> `123-125`: _⚠️ Potential issue_ | _🟡 Minor_ **Fix broken internal links (`reference` → `references`)** Later cross-links use a non-existent folder name and will break navigation. <details> <summary>Suggested fix</summary> ```diff -- See ./reference/testflight.md for credential setup -- See ./reference/ios-app-store.md for App Store submission +- See ./references/testflight.md for credential setup +- See ./references/ios-app-store.md for App Store submission @@ -- See ./reference/play-store.md for detailed setup +- See ./references/play-store.md for detailed setup @@ -- See ./reference/workflows.md for CI/CD automation +- See ./references/workflows.md for CI/CD automation @@ -See ./reference/workflows.md for more workflow examples. +See ./references/workflows.md for more workflow examples. ``` </details> Also applies to: 130-137, 165-165 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/SKILL.md around lines 123 - 125, The markdown links use the incorrect folder name "reference" and should be updated to "references": replace occurrences of "./reference/testflight.md" and "./reference/ios-app-store.md" (and the other instances at the same pattern, e.g., any "./reference/..." links found later) with "./references/testflight.md" and "./references/ios-app-store.md" respectively so all internal cross-links point to the existing references directory in SKILL.md. ``` </details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/route-structure.md-18-24 (1)</summary><blockquote> `18-24`: _⚠️ Potential issue_ | _🟡 Minor_ **Add fenced code languages to satisfy markdownlint (MD040)** Several code fences are missing a language identifier. Add `text` (or `plaintext`) for directory-tree examples to keep lint clean. <details> <summary>Suggested fix pattern</summary> ```diff -``` +```text app/ users/ [id].tsx # Matches /users/123, /users/abc [id]/ posts.tsx # Matches /users/123/posts ``` ``` </details> Also applies to: 30-34, 69-77, 95-106, 112-119, 155-169 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/route-structure.md around lines
18 - 24, The markdown code fences in route-structure.md containing
directory-tree examples (for example the block showing "app/ users/ [id].tsx
[id]/ posts.tsx") are missing language identifiers which triggers MD040; update
each of those fenced code blocks (including the ones at the other ranges noted:
30-34, 69-77, 95-106, 112-119, 155-169) by adding a language token such as
"text" or "plaintext" after the openingso the directory-tree examples (e.g., the block with "app/", "users/", "[id].tsx", "[id]/", "posts.tsx") becometext ... ``` to satisfy markdownlint.</details> </blockquote></details> <details> <summary>.agents/skills/expo-deployment/references/ios-app-store.md-355-355 (1)</summary><blockquote> `355-355`: _⚠️ Potential issue_ | _🟡 Minor_ **Hyphenate “up-to-date” in the tip text.** Small docs wording fix for compound adjective usage. <details> <summary>📝 Suggested fix</summary> ```diff -- Keep demo account credentials up to date +- Keep demo account credentials up-to-date ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/ios-app-store.md at line 355, Change the tip text string "Keep demo account credentials up to date" to use a hyphenated compound adjective: replace it with "Keep demo account credentials up-to-date" wherever that exact phrase appears (e.g., the tip line containing Keep demo account credentials up to date in ios-app-store.md). ``` </details> </blockquote></details> <details> <summary>.agents/skills/expo-deployment/references/ios-app-store.md-227-227 (1)</summary><blockquote> `227-227`: _⚠️ Potential issue_ | _🟡 Minor_ **Use a non-stale scheduled-release timestamp example.** Line 227 currently shows **March 1, 2025**, which is already in the past as of **March 2, 2026**. Prefer a placeholder to avoid date drift. <details> <summary>📝 Suggested fix</summary> ```diff - "automaticRelease": "2025-03-01T10:00:00Z" + "automaticRelease": "<YYYY-MM-DDTHH:mm:ssZ>" ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/ios-app-store.md at line 227, Replace the stale scheduled-release timestamp value for the "automaticRelease" field (currently "2025-03-01T10:00:00Z") with a non-stale example or a placeholder to avoid date drift—for example use an ISO timestamp in the future or a placeholder like "YYYY-MM-DDTHH:MM:SSZ" so the example remains valid; update the string value for "automaticRelease" accordingly. ``` </details> </blockquote></details> <details> <summary>frontend/app/listings/[id].tsx-95-100 (1)</summary><blockquote> `95-100`: _⚠️ Potential issue_ | _🟡 Minor_ **Hide the Share action when the listing is hidden.** Line 95 renders `Share` even for hidden-owner view. This allows sharing links that resolve to unavailable pages for other users. Gate the button with `!isHidden`. <details> <summary>Suggested fix</summary> ```diff - <Pressable - style={({ pressed }) => [styles.shareButton, pressed && styles.buttonPressed]} - onPress={shareListing} - > - <Text style={styles.shareButtonText}>Share</Text> - </Pressable> + {!isHidden && ( + <Pressable + style={({ pressed }) => [styles.shareButton, pressed && styles.buttonPressed]} + onPress={shareListing} + > + <Text style={styles.shareButtonText}>Share</Text> + </Pressable> + )} ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/app/listings/`[id].tsx around lines 95 - 100, The Share button is rendered for hidden listings; wrap the Pressable that calls shareListing (the element using styles.shareButton and styles.shareButtonText) in a guard so it only renders when the listing is not hidden (use the isHidden boolean: render the Pressable when !isHidden), ensuring the shareListing action and its UI are completely omitted when isHidden is true. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (8)</summary><blockquote> <details> <summary>backend/convex/ResendOTP.ts (1)</summary><blockquote> `12-12`: **Consider trimming sender env value before validation/use.** Whitespace-only or padded values can bypass the current truthy check and fail later at send time. <details> <summary>♻️ Optional hardening</summary> ```diff -const resendFromAddress = process.env.AUTH_RESEND_FROM ?? process.env.RESEND_FROM; +const resendFromAddress = + (process.env.AUTH_RESEND_FROM ?? process.env.RESEND_FROM)?.trim(); ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@backend/convex/ResendOTP.ts` at line 12, Trim whitespace from the environment sender value before using or validating it: in the logic that determines resendFromAddress (the constant resendFromAddress), call .trim() on process.env.AUTH_RESEND_FROM and process.env.RESEND_FROM (guarding for undefined) so that values that are whitespace-only become empty strings and the truthy check fails early; then use the trimmed value for subsequent validation/send operations to avoid passing padded or whitespace-only senders to the mailer. ``` </details> </blockquote></details> <details> <summary>.agents/skills/expo-tailwind-setup/SKILL.md (2)</summary><blockquote> `214-217`: **Clarify the dual contentClassName mapping.** Both `contentClassName` and `contentContainerClassName` are mapped to `contentContainerStyle`. This might be intentional to accept either prop name, but it could confuse users about which to use. Consider adding a comment explaining this design choice or standardizing on one prop name. <details> <summary>📝 Suggested clarification</summary> ```diff export const AnimatedScrollView = ( props: React.ComponentProps<typeof Animated.ScrollView> & { className?: string; - contentClassName?: string; + contentClassName?: string; // Alias for contentContainerClassName contentContainerClassName?: string; } ) => { ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-tailwind-setup/SKILL.md around lines 214 - 217, The mapping in useCssElement for Animated.ScrollView sets both contentClassName and contentContainerClassName to 'contentContainerStyle', which is ambiguous; update the code in useCssElement (the Animated.ScrollView return) to either standardize on a single prop name (prefer contentContainerClassName) and map the legacy alias (contentClassName) to that canonical name, or add a clear inline comment explaining that both are intentionally accepted as aliases; ensure props and returned mapping use the chosen canonical symbol consistently (e.g., contentContainerClassName -> 'contentContainerStyle') and document the alias handling so users aren’t confused. ``` </details> --- `281-301`: **Consider adding an example of importing global.css.** The usage section shows component usage but doesn't demonstrate how to import the `global.css` file in the app entry point. This is mentioned in troubleshooting (line 441) but would be helpful to show upfront. <details> <summary>📚 Suggested addition before the Usage section</summary> ```markdown ## Import Global Styles Import the global CSS file in your app entry point (e.g., `app/_layout.tsx`): ```tsx import '../global.css'; export default function RootLayout() { // ... your layout code } ``` ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-tailwind-setup/SKILL.md around lines 281 - 301, Add a short "Import Global Styles" snippet before the Usage section showing how to import the global.css in the app entry point: instruct the reader to add an import of global.css at the top of their RootLayout (or app entry component) so styles are loaded globally, and mention placing the import before the export/default component definition; reference the global.css filename and the RootLayout component to locate where to add this example. ``` </details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/animations.md (1)</summary><blockquote> `3-3`: **Soften the "Avoid" guidance to better reflect official React Native recommendations and current codebase patterns.** Line 3 presents an absolute prohibition, but React Native's `Animated` API remains officially supported and is used in `frontend/hooks/useEntranceAnimation.ts` for simple entrance transitions. The React Native documentation lists it as one of two complementary animation systems. Reframe this as a preference for complex/performance-critical cases rather than a blanket restriction. <details> <summary>Suggested wording</summary> ```diff -Use Reanimated v4. Avoid React Native's built-in Animated API. +Prefer Reanimated v4 for complex and performance-critical animations. React Native's built-in Animated API is acceptable for simple transitions. ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/animations.md at line 3, Line 3's guidance is too absolute; update the wording to recommend Reanimated v4 for complex or performance-critical animations while acknowledging React Native's built-in Animated API remains supported and is appropriate for simple transitions (as used in frontend/hooks/useEntranceAnimation.ts). Replace "Avoid React Native's built-in Animated API" with a softer preference statement that explains when to choose Reanimated v4 versus Animated and references performance/complexity trade-offs. ``` </details> </blockquote></details> <details> <summary>frontend/components/CategoryPicker.tsx (1)</summary><blockquote> `20-20`: **Re-trigger entrance animation on modal reopen.** At Line 20, `useEntranceAnimation` is initialized once; if this component stays mounted and only `visible` toggles, the entrance effect may not replay on subsequent opens. Consider keying/restarting the animation from `visible`. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/components/CategoryPicker.tsx` at line 20, The entrance animation is only initialized once via useEntranceAnimation(40, 8) so reopening the modal (CategoryPicker) while it remains mounted doesn't replay the effect; update the component to restart or re-create the animation when the modal's visible prop changes — e.g., pass visible into useEntranceAnimation or call its restart method inside a useEffect that watches visible (referencing useEntranceAnimation, entranceStyle, and the CategoryPicker visible prop) so the entranceStyle is recomputed/restarted whenever visible becomes true. ``` </details> </blockquote></details> <details> <summary>frontend/app/(tabs)/index.tsx (1)</summary><blockquote> `249-249`: **Simplify unreachable null-check in empty-state condition.** `listings` is always an array (`allListings.filter(...)`), so `!listings` is unnecessary noise. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/app/`(tabs)/index.tsx at line 249, The ternary conditional includes an unnecessary null-check for listings which is always an array from allListings.filter(...); update the render condition that currently reads ") : !listings || listings.length === 0 ? (" by removing the "!listings ||" part so the branch only checks listings.length === 0, ensuring the empty-state is determined solely by the array length; locate the conditional surrounding the variable listings in the component render (where allListings.filter(...) sets listings) and simplify it accordingly. ``` </details> </blockquote></details> <details> <summary>frontend/components/ListingCard.tsx (1)</summary><blockquote> `24-51`: **Optional: consolidate entrance animation with the shared hook.** This block reimplements the same fade/translate pattern already centralized in `frontend/hooks/useEntranceAnimation.ts` (Lines 3-36). Consider extending that hook (e.g., optional duration) and reusing it here to keep animation tuning centralized. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/components/ListingCard.tsx` around lines 24 - 51, The ListingCard component duplicates the fade/translate entrance animation implemented in useEntranceAnimation; extend useEntranceAnimation to accept optional parameters (e.g., duration and/or delay multiplier) and return the animated values and style, then remove the local useEffect and local opacity/translateY setup in ListingCard and call useEntranceAnimation(index, { duration, delayMultiplier }) (or similar) to obtain opacity, translateY, and animatedStyle; update ListingCard to use the hook's returned animatedStyle instead of its own animatedStyle so animation tuning is centralized. ``` </details> </blockquote></details> <details> <summary>frontend/app/listings/new.tsx (1)</summary><blockquote> `139-270`: **Extract a shared listing form component to avoid create/edit drift.** This form is now near line-for-line duplicated with `frontend/app/listings/[id]/edit.tsx` (fields, image controls, category/condition chips, tags, and button block). Pulling shared UI/validation wiring into one reusable form component will reduce future divergence. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In `@frontend/app/listings/new.tsx` around lines 139 - 270, The Listing create form is duplicated in listings/[id]/edit.tsx; extract a reusable ListingForm component that encapsulates the UI and validation wiring (fields: title, description, price, category, condition, images with handleImageChange/handleRemoveImage/handleAddImage, TagInput, submit/cancel buttons and isSubmitting state) and replace the duplicated JSX in new.tsx and edit.tsx with <ListingForm initialValues={...} onSubmit={handleSubmit} onCancel={() => router.back()} /> (or similar); ensure the new component exports props for initialValues, onChange callbacks, validation, and styles so existing handlers (handleSubmit, TagInput, images array logic) can be moved into the component or passed in as props to avoid create/edit drift. ``` </details> </blockquote></details> </blockquote></details> --- <details> <summary>ℹ️ Review info</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between a3a5ecca4a925f793e82351ae4b6f78dbf5f67bb and 98ebfde073a956e2e13850b188e0d4e6f14c9b77. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `package-lock.json` is excluded by `!**/package-lock.json` </details> <details> <summary>📒 Files selected for processing (69)</summary> * `.agents/skills/building-native-ui/SKILL.md` * `.agents/skills/building-native-ui/references/animations.md` * `.agents/skills/building-native-ui/references/controls.md` * `.agents/skills/building-native-ui/references/form-sheet.md` * `.agents/skills/building-native-ui/references/gradients.md` * `.agents/skills/building-native-ui/references/icons.md` * `.agents/skills/building-native-ui/references/media.md` * `.agents/skills/building-native-ui/references/route-structure.md` * `.agents/skills/building-native-ui/references/search.md` * `.agents/skills/building-native-ui/references/storage.md` * `.agents/skills/building-native-ui/references/tabs.md` * `.agents/skills/building-native-ui/references/toolbar-and-headers.md` * `.agents/skills/building-native-ui/references/visual-effects.md` * `.agents/skills/building-native-ui/references/webgpu-three.md` * `.agents/skills/building-native-ui/references/zoom-transitions.md` * `.agents/skills/expo-api-routes/SKILL.md` * `.agents/skills/expo-cicd-workflows/SKILL.md` * `.agents/skills/expo-cicd-workflows/scripts/fetch.js` * `.agents/skills/expo-cicd-workflows/scripts/package.json` * `.agents/skills/expo-cicd-workflows/scripts/validate.js` * `.agents/skills/expo-deployment/SKILL.md` * `.agents/skills/expo-deployment/references/app-store-metadata.md` * `.agents/skills/expo-deployment/references/ios-app-store.md` * `.agents/skills/expo-deployment/references/play-store.md` * `.agents/skills/expo-deployment/references/testflight.md` * `.agents/skills/expo-deployment/references/workflows.md` * `.agents/skills/expo-dev-client/SKILL.md` * `.agents/skills/expo-tailwind-setup/SKILL.md` * `.agents/skills/native-data-fetching/SKILL.md` * `.agents/skills/native-data-fetching/references/expo-router-loaders.md` * `.agents/skills/upgrading-expo/SKILL.md` * `.agents/skills/upgrading-expo/references/expo-av-to-audio.md` * `.agents/skills/upgrading-expo/references/expo-av-to-video.md` * `.agents/skills/upgrading-expo/references/native-tabs.md` * `.agents/skills/upgrading-expo/references/new-architecture.md` * `.agents/skills/upgrading-expo/references/react-19.md` * `.agents/skills/upgrading-expo/references/react-compiler.md` * `.agents/skills/use-dom/SKILL.md` * `.cursor/settings.json` * `.eslintrc.js` * `babel.jest.config.js` * `backend/.env.example` * `backend/convex/ResendOTP.ts` * `backend/convex/auth.config.ts` * `docs/contributing.md` * `frontend/app.json` * `frontend/app/(tabs)/_layout.tsx` * `frontend/app/(tabs)/index.tsx` * `frontend/app/(tabs)/search.tsx` * `frontend/app/(tabs)/settings.tsx` * `frontend/app/_layout.tsx` * `frontend/app/auth/login.tsx` * `frontend/app/listings/[id].tsx` * `frontend/app/listings/[id]/edit.tsx` * `frontend/app/listings/new.tsx` * `frontend/babel.config.js` * `frontend/components/CategoryPicker.tsx` * `frontend/components/FilterBar.tsx` * `frontend/components/HiddenBanner.tsx` * `frontend/components/ListingCard.tsx` * `frontend/components/ListingUnavailable.tsx` * `frontend/components/PriceRangePicker.tsx` * `frontend/components/TagInput.tsx` * `frontend/components/TagPicker.tsx` * `frontend/hooks/useEntranceAnimation.ts` * `frontend/package.json` * `frontend/tsconfig.json` * `jest.config.js` * `skills-lock.json` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
Actionable comments posted: 12
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/app/auth/login.tsx (1)
55-59:⚠️ Potential issue | 🟡 MinorConsider validating that the code contains only digits.
keyboardType="number-pad"suggests numeric input but doesn't prevent non-numeric characters on all platforms (especially web). The validation at line 56 checks length but not content.🔧 Suggested fix
const handleVerifyCode = async () => { - if (!code.trim() || code.trim().length !== 8) { - setError('Please enter the 8-digit code'); + const trimmedCode = code.trim(); + if (!trimmedCode || trimmedCode.length !== 8 || !/^\d{8}$/.test(trimmedCode)) { + setError('Please enter the 8-digit code (numbers only)'); return; }Also applies to: 159-165
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 55 - 59, The code-length check in handleVerifyCode only enforces an 8-character length but not that the code is numeric; update handleVerifyCode to validate that the trimmed code is exactly 8 digits (e.g., match against a digits-only pattern) and set a clear error when it contains non-digit characters, and apply the same digits-only validation to the other code-validation handler in this module so both enforce an 8-digit numeric code consistently.frontend/app/listings/new.tsx (1)
1-393:⚠️ Potential issue | 🟡 MinorCI formatting warning still applies here.
GitHub Actions reports Prettier issues; please run formatting on this file to clear the pipeline warning.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/listings/new.tsx` around lines 1 - 393, This file failed CI formatting (Prettier) — run the project's formatter on this file (e.g., npm run format or prettier --write) and save the changes so the Prettier rules are applied; ensure NewListingScreen and its surrounding imports/JSX/StyleSheet are properly formatted and that there are no trailing commas/spacing issues left by the linter before committing.
♻️ Duplicate comments (5)
.agents/skills/expo-dev-client/SKILL.md (1)
170-173:⚠️ Potential issue | 🔴 Critical
eas updateis the wrong command for CLI upgrades (previously flagged).This issue was raised in a previous review but remains unfixed. The
eas updatecommand publishes over-the-air updates to your app, not upgrades the CLI itself. Running this command could inadvertently publish an OTA update to users. The correct way to upgrade the EAS CLI is via the package manager.📝 Proposed documentation fix
**Check EAS CLI version:** ```bash eas --version -eas update + +# Upgrade EAS CLI to latest +npm install --global eas-cli@latest</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/expo-dev-client/SKILL.md around lines 170 - 173, The doc
currently shows the wrong command ("eas update") for upgrading the EAS CLI;
replace the second line in the code block that currently reads "eas update" with
an explicit package-manager install to upgrade the CLI (for example "npm install
--global eas-cli@latest") and keep "eas --version" for verifying the CLI version
so the code block demonstrates checking the version and the correct upgrade
command instead of publishing an OTA update.</details> </blockquote></details> <details> <summary>.agents/skills/expo-tailwind-setup/SKILL.md (1)</summary><blockquote> `25-25`: _⚠️ Potential issue_ | _🟠 Major_ **Replace nightly `react-native-css` with a stable release.** Line 25 still pins a nightly build (`react-native-css@0.0.0-nightly.5ce6396`), which makes this setup less stable for adopters. This was already flagged in an earlier review and appears unresolved. <details> <summary>Suggested doc fix</summary> ```diff -npx expo install tailwindcss@^4 nativewind@5.0.0-preview.2 react-native-css@0.0.0-nightly.5ce6396 `@tailwindcss/postcss` tailwind-merge clsx +npx expo install tailwindcss@^4 nativewind@5.0.0-preview.2 react-native-css@^3.0.3 `@tailwindcss/postcss` tailwind-merge clsxAs of March 2026, what are the current stable and preview dist-tags/versions for npm packages `react-native-css` and `nativewind`?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-tailwind-setup/SKILL.md at line 25, The install command pins a nightly build for react-native-css; update the npx install line (the shown "npx expo install tailwindcss@^4 nativewind@5.0.0-preview.2 react-native-css@0.0.0-nightly.5ce6396 ...") to use a stable react-native-css release (either remove the explicit nightly version or pin to the official stable semver) and likewise avoid preview tags for nativewind unless intentionally desired (replace nativewind@5.0.0-preview.2 with the stable/nativewind@latest or a documented stable version); make the change in the npx command and any accompanying text in SKILL.md so the example shows stable packages instead of the nightly preview build..agents/skills/upgrading-expo/references/react-19.md (1)
9-10:⚠️ Potential issue | 🟠 Major
useshould be documented as a flexible alternative, not a replacement foruseContext.This wording is still incorrect for React 19 and can mislead migrations. Both are supported;
useis more flexible in specific cases.Proposed doc fix
-The `use` hook replaces `useContext`: +The `use` hook is a more flexible alternative to `useContext` in some cases: - [ ] Replace `useContext` with `use` + [ ] Consider `use` where conditional context reads or Promise-based resources are neededAccording to the official React 19 docs, does `use(resource)` replace `useContext`, or are both APIs supported with different constraints?Also applies to: 77-77
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/references/react-19.md around lines 9 - 10, The sentence claiming "`use` replaces `useContext`" is misleading; update the text to clarify that React 19 supports both APIs and that `use(resource)` is a more flexible alternative for some patterns but does not remove or replace `useContext`; specifically edit the statement mentioning `use` and `useContext` so it reads that both are supported, outline when to prefer `use` (e.g., async resources, Suspense-driven data) versus `useContext` (context propagation), and adjust any examples or guidance that assert replacement to instead compare trade-offs between `use` and `useContext`..agents/skills/building-native-ui/references/tabs.md (1)
397-399:⚠️ Potential issue | 🟠 MajorFix
ThemeProviderprop name (value, nottheme).Lines 397 and 412 use
theme={...};ThemeProviderexpectsvalue={...}. This example will mislead consumers and fail in typed usage.In `@react-navigation/native`, what prop does ThemeProvider accept for the theme object: `value` or `theme`?🛠 Suggested docs patch
- <ThemeProvider theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> + <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> <Stack /> </ThemeProvider>- <ThemeProvider theme={DarkTheme}> + <ThemeProvider value={DarkTheme}> <Stack /> </ThemeProvider>Also applies to: 412-414
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/tabs.md around lines 397 - 399, The ThemeProvider usage is passing the theme object via the wrong prop name (`theme`); update both ThemeProvider instances (wrapping <Stack /> and the other occurrence around the other component) to use value={colorScheme === 'dark' ? DarkTheme : DefaultTheme} instead of theme={...}; ensure you only rename the prop on the ThemeProvider components (symbol: ThemeProvider) so typed consumers of `@react-navigation/native` receive the theme via the expected value prop..agents/skills/building-native-ui/references/webgpu-three.md (1)
164-206:⚠️ Potential issue | 🟠 MajorPrevent re-initializing the WebGPU canvas on every render.
This
useEffecthas no dependency array, so the setup/cleanup cycle runs each render. In docs code, that’s a costly and misleading pattern.🔧 Suggested docs patch
- useEffect(() => { + useEffect(() => { const context = canvasRef.current!.getContext('webgpu')!; const renderer = makeWebGPURenderer(context); @@ root.current.render(children); return () => { if (canvas != null) { unmountComponentAtNode(canvas!); } }; - }); + }, [camera, scene]); + + useEffect(() => { + if (root.current) { + root.current.render(children); + } + }, [children]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/webgpu-three.md around lines 164 - 206, The effect is missing a dependency array so the WebGPU canvas and react-three root are recreated on every render; change the useEffect to run only once by adding an empty dependency array (useEffect(..., [])) and move dynamic updates (like re-rendering children) into a separate effect that watches children (e.g. useEffect(() => root.current?.render(children), [children])); keep the existing cleanup that calls unmountComponentAtNode(canvas) and ensure you still reference canvasRef, createRoot, root.current.configure, and root.current.render in their current places.
🟡 Minor comments (13)
.agents/skills/expo-deployment/references/app-store-metadata.md-128-133 (1)
128-133:⚠️ Potential issue | 🟡 MinorMake
keywordsexample format consistent across the doc.Line 131 uses a CSV string inside an array, while other sections show an array of keyword values. Pick one canonical format to avoid copy/paste misconfiguration.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/app-store-metadata.md around lines 128 - 133, The example for the JSON "keywords" field is inconsistent: it currently shows a single CSV string inside the array; update it to the canonical format used elsewhere by making "keywords" an array of individual keyword strings (e.g., "keywords": ["finance","budget","expense",...]) so copy/paste users get the correct type; locate the JSON example that contains the "keywords" key and replace the CSV-in-array value with an array of separate string entries..agents/skills/expo-tailwind-setup/SKILL.md-39-40 (1)
39-40:⚠️ Potential issue | 🟡 MinorMinor wording/capitalization cleanup for readability.
Line 39 and Line 40 use lowercase product names (
lightningcss,expo). In user-facing docs, use canonical names (Lightning CSS,Expo).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-tailwind-setup/SKILL.md around lines 39 - 40, Update the user-facing text to use canonical product names: replace occurrences of "lightningcss" with "Lightning CSS" and "expo" with "Expo" in the SKILL.md content lines that read "autoprefixer is not needed in Expo because of lightningcss" and "postcss is included in expo by default" so both references use proper capitalization and naming. Ensure only the product names are changed and surrounding wording remains unchanged..agents/skills/expo-cicd-workflows/scripts/validate.js-59-63 (1)
59-63:⚠️ Potential issue | 🟡 MinorHelp flow returns the wrong exit code for
--help.Line 63 exits with code
1when--helpis used without file args, which should be success (0).Proposed fix
- if (files.length === 0 || args.includes('--help') || args.includes('-h')) { + const showHelp = args.includes('--help') || args.includes('-h'); + if (files.length === 0 || showHelp) { @@ - process.exit(files.length === 0 ? 1 : 0); + process.exit(showHelp ? 0 : 1); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 59 - 63, The help path incorrectly returns exit code 1 when no files are passed but help flags are present; update the exit logic around the conditional that checks files/args (using the variables files, args and calling process.exit) so that if args.includes('--help') || args.includes('-h') the script always exits with 0, otherwise keep the current behavior of exiting 1 when files.length === 0 and 0 when files exist..agents/skills/building-native-ui/references/zoom-transitions.md-155-155 (1)
155-155:⚠️ Potential issue | 🟡 MinorUse hyphenated form “off-screen” at Line 155.
Minor wording fix for consistency and readability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/zoom-transitions.md at line 155, Update the sentence "When source is unavailable (e.g., scrolled off screen), the transition zooms from the center of the screen" to use the hyphenated form "off-screen" so it reads "When source is unavailable (e.g., scrolled off-screen), the transition zooms from the center of the screen"; locate this exact line in zoom-transitions.md and make the single-word hyphenation change..agents/skills/upgrading-expo/references/react-19.md-22-22 (1)
22-22:⚠️ Potential issue | 🟡 MinorFix the sentence at Line 22 for readability.
The clause uses a comma splice; split into two sentences.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/references/react-19.md at line 22, The sentence "`use` can be called conditionally, this simplifies components that consume multiple contexts." contains a comma splice; split it into two sentences by changing it to "`use` can be called conditionally. This simplifies components that consume multiple contexts." to improve readability..agents/skills/upgrading-expo/references/native-tabs.md-29-29 (1)
29-29:⚠️ Potential issue | 🟡 MinorFix or clarify the iOS version notation in BottomAccessory description.
iOS +26is both ambiguous in notation and appears inconsistent with documented requirements. The Expo SDK 55 minimum supported iOS version is iOS 15.1+. Clarify whatiOS +26refers to—whether it's a typo (e.g.,iOS 16+,iOS 17+), a specific BottomAccessory requirement above the SDK baseline, or something else. Use standard notation likeiOS 16+if specifying a version.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/references/native-tabs.md at line 29, The BottomAccessory description uses the ambiguous string "iOS +26"; update this to a standard, unambiguous iOS version notation (e.g., "iOS 16+" or the correct target such as "iOS 17+") or add a short clarifying parenthetical explaining what "+26" means, and ensure the text references the Expo SDK 55 baseline (iOS 15.1+) if this requirement is above that baseline; modify the BottomAccessory line in native-tabs.md to replace "iOS +26" with the chosen standard notation and a one-line note if needed to avoid confusion..agents/skills/building-native-ui/references/tabs.md-305-309 (1)
305-309:⚠️ Potential issue | 🟡 MinorAdd language to the fenced route-structure block.
Line 305 starts an unlabeled fence; add
textto resolve markdownlint MD040.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/tabs.md around lines 305 - 309, The fenced route-structure block containing the lines with "_layout.tsx # NativeTabs for iOS/Android" and "_layout.web.tsx # Headless tabs for web (expo-router/ui)" is missing a language label; update the opening code fence (the triple backticks that begin that block) to include the label text (i.e., change ``` to ```text) to satisfy markdownlint MD040..agents/skills/building-native-ui/SKILL.md-14-30 (1)
14-30:⚠️ Potential issue | 🟡 MinorAdd language identifiers to unlabeled fenced blocks.
Lines 14 and 249 start fences without language tags. Use
textfor directory-tree snippets to satisfy markdownlint MD040.Also applies to: 249-256
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/SKILL.md around lines 14 - 30, The unlabeled fenced code blocks in SKILL.md (the directory-tree snippets shown in the references/ block and the other block around lines 249-256) need explicit language tags to satisfy markdownlint MD040; add the language identifier `text` to the opening fences for those snippets (i.e., change ``` to ```text for the directory-tree blocks) so the fenced blocks in the references section and the block at lines ~249-256 are labeled..agents/skills/building-native-ui/references/webgpu-three.md-492-503 (1)
492-503:⚠️ Potential issue | 🟡 MinorAdd language tags to the last two fenced blocks.
Lines 492 and 507 open unlabeled fences; use
textfor these tree/decision blocks to resolve markdownlint MD040.Also applies to: 507-523
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/webgpu-three.md around lines 492 - 503, The final two fenced code blocks that show the project tree (containing entries like "src/", "components/", "lib/", and filenames such as "fiber-canvas.tsx", "make-webgpu-renderer.ts", "orbit-controls.tsx") are missing language labels; update those two fences to use the "text" language tag (i.e., change ``` to ```text) so the tree/decision blocks are labeled and satisfy markdownlint MD040..agents/skills/expo-api-routes/SKILL.md-35-43 (1)
35-43:⚠️ Potential issue | 🟡 MinorAdd a language tag to the fenced block.
Line 35 starts an unlabeled code fence, which triggers markdownlint MD040. Use
textfor the directory tree block.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-api-routes/SKILL.md around lines 35 - 43, The fenced code block that shows the directory tree (the block starting with the lines showing "app/", "api/", "hello+api.ts", etc.) is unlabeled and triggers markdownlint MD040; add a language tag "text" to the opening triple backticks so the block reads as a text code fence (```text) to silence the lint error and keep the directory tree formatting intact in SKILL.md..agents/skills/building-native-ui/references/route-structure.md-18-24 (1)
18-24:⚠️ Potential issue | 🟡 MinorLabel all directory-tree code fences with a language.
Lines 18, 30, 69, 95, 112, and 155 start unlabeled fences. Add
textto satisfy markdownlint MD040.Also applies to: 30-34, 69-77, 95-106, 112-119, 155-169
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/route-structure.md around lines 18 - 24, The markdown contains unlabeled fenced code blocks showing directory trees (e.g., the block starting with "app/", "users/", "[id].tsx", and similar directory-tree blocks elsewhere) which trigger markdownlint MD040; update each of those code fences to include the language label "text" (so the opening fence becomes ```text) for all directory-tree examples (including the blocks that correspond to the examples shown and the other unlabeled blocks referenced) to satisfy the linter.frontend/app/(tabs)/_layout.tsx-68-71 (1)
68-71:⚠️ Potential issue | 🟡 MinoriOS tab label color may not work correctly in dark mode.
tabTintcorrectly adapts to dark mode (line 69), butnativeTabLabelStyle(line 70) always appliesstyles.iosTabLabelwhich hardcodescolor: '#111111'. In dark mode, this results in dark text on a dark background.🔧 Suggested fix
- const nativeTabLabelStyle = Platform.OS === 'ios' ? styles.iosTabLabel : undefined; + const nativeTabLabelStyle = + Platform.OS === 'ios' ? { color: isDarkMode ? '#ffffff' : '#111111' } : undefined;And remove the unused
iosTabLabelstyle:- iosTabLabel: { - color: '#111111', - },Also applies to: 161-163
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/`(tabs)/_layout.tsx around lines 68 - 71, The iOS tab label color is fixed to styles.iosTabLabel (which hardcodes color '#111111') causing unreadable text in dark mode; update nativeTabLabelStyle assignment to choose styles.iosTabLabelDark when isDarkMode is true (or compute a dynamic style using isDarkMode) so the label color matches tabTint, and remove the now-unused iosTabLabel style definition; change references around nativeTabLabelStyle, isDarkMode, tabTint, and styles.iosTabLabel so both label color and tint adapt to dark mode (also apply the same fix to the other occurrence at the later block referenced)..agents/skills/building-native-ui/references/media.md-5-5 (1)
5-5:⚠️ Potential issue | 🟡 MinorUse “full-screen” in docs text.
Please hyphenate “full-screen” for clarity and consistency in the guidance line.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/media.md at line 5, The documentation line "Hide navigation headers when there's a full screen camera" should be updated to hyphenate "full-screen" for consistency; edit the sentence in media.md (the line containing "Hide navigation headers when there's a full screen camera") to read "Hide navigation headers when there's a full-screen camera".
🧹 Nitpick comments (8)
backend/convex/ResendOTP.ts (1)
43-47: Consider a more precise check for the test sender address.Using
.includes('onboarding@resend.dev')could theoretically match unintended strings (e.g., a custom domain containing that substring). While the practical risk is low since this is a developer-controlled setting, an exact match or a regex anchored to the email portion would be more precise.♻️ Suggested refinement
- if (resendFromAddress.toLowerCase().includes('onboarding@resend.dev')) { + // Extract email from "Name <email>" format or use as-is + const emailMatch = resendFromAddress.match(/<([^>]+)>/) ?? [null, resendFromAddress]; + const senderEmail = (emailMatch[1] ?? resendFromAddress).toLowerCase().trim(); + if (senderEmail === 'onboarding@resend.dev') {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/convex/ResendOTP.ts` around lines 43 - 47, The check in ResendOTP.ts uses resendFromAddress.toLowerCase().includes('onboarding@resend.dev') which can match unintended strings; change it to a precise comparison (e.g., compare the lowercased whole address for equality) or use an anchored regex that validates the email portion equals onboarding@resend.dev before throwing the ConvexError, updating the conditional that references resendFromAddress and the ConvexError message accordingly..agents/skills/upgrading-expo/SKILL.md (1)
40-44: Add a cross-platform fallback for cache-clearing commands.
watchman watch-del-allis not available in many environments (especially Windows/CI without Watchman). Add a short fallback note so this step doesn’t block upgrades.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/SKILL.md around lines 40 - 44, The step currently tells users to run "watchman watch-del-all", which isn't available on many platforms; update SKILL.md to add a cross-platform fallback note: if watchman isn't installed, instruct users to either run a platform-safe cache/cleanup command (examples: "expo start -c", "git clean -fdx" for CI, or use a Node tool like "npx rimraf .expo" / platform-specific removal on Windows) or skip with a clear message, and show a brief conditional suggestion like "if watchman exists run it otherwise run fallback" so the upgrade step doesn't block on Windows/CI..agents/skills/building-native-ui/references/icons.md (1)
16-19: Add language specifier to fenced code block.The references directory listing should have a language specifier for consistency and to satisfy linting rules.
📝 Suggested fix
-``` +```text references/ expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/icons.md around lines 16 - 19, The fenced code block in .agents/skills/building-native-ui/references/icons.md is missing a language specifier (closing/backtick block around the references/ listing); update the opening fence to include a language (e.g., ```text) so the snippet becomes ```text ... ``` to satisfy linting and maintain consistency with other docs..agents/skills/native-data-fetching/SKILL.md (2)
16-19: Add language specifier to fenced code block.The references directory listing should have a language specifier.
📝 Suggested fix
-``` +```text references/ expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/native-data-fetching/SKILL.md around lines 16 - 19, The fenced code block showing the references directory listing in SKILL.md is missing a language specifier; update the opening triple-backtick for the block that contains "references/" and "expo-router-loaders.md" to include a language tag (e.g., use ```text) so the block is properly rendered and highlighted in markdown.
415-449: Add language specifier to decision tree code block.The decision tree should have a language specifier (e.g.,
textorplaintext) for consistency.📝 Suggested fix
-``` +```text User asks about networking |-- Route-level data loading (web, SDK 55+)?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/native-data-fetching/SKILL.md around lines 415 - 449, The fenced decision-tree code block starting with "User asks about networking" lacks a language specifier; update that code fence to include a plain-text language tag (e.g., ```text or ```plaintext) so the block is consistently highlighted and formatted—locate the triple-backtick fence before the "User asks about networking" block in SKILL.md and add the language token immediately after the opening backticks.frontend/app/(tabs)/search.tsx (1)
35-36: Consider simplifying the filter version tracking.Using two separate refs (
filterVersionRefandcurrentFilterVersionRef) that are always incremented and assigned together adds complexity. A single ref would suffice sincequeryFilterVersion(line 57) captures the current value at render time, which is then compared inside the effect.♻️ Suggested simplification
- const filterVersionRef = useRef(0); - const currentFilterVersionRef = useRef(0); + const filterVersionRef = useRef(0); const processedCursorsRef = useRef(new Set<string>()); // ... useEffect(() => { filterVersionRef.current += 1; - currentFilterVersionRef.current = filterVersionRef.current; setCursor(null); // ... }, [searchTerm]); - const queryFilterVersion = currentFilterVersionRef.current; + const queryFilterVersion = filterVersionRef.current; // ... useEffect(() => { if (listingsResult && queryFilterVersion === filterVersionRef.current) {Also applies to: 57-57
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/`(tabs)/search.tsx around lines 35 - 36, The two refs filterVersionRef and currentFilterVersionRef are redundant—keep a single ref (e.g., filterVersionRef) and use it both to read the render-time version (queryFilterVersion) and to mark the effect-consumed version; update places that increment or assign currentFilterVersionRef to instead increment filterVersionRef and compare queryFilterVersion against filterVersionRef inside the useEffect that processes filter changes (the effect that currently checks those two refs), and remove all references to currentFilterVersionRef to simplify tracking.frontend/components/TagInput.tsx (1)
63-97: Comma-based tag addition logic is functional but verbose.The
handleInputChangefunction handles multiple edge cases (empty tags, duplicates, length limits, max tags). While the logic works correctly, consider extracting the validation into a helper function to reduce nesting depth.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/TagInput.tsx` around lines 63 - 97, Refactor the comma-add logic in handleInputChange by extracting the per-tag validation into a helper (e.g., validateAndProcessTag or isValidTag) so the main function stops nesting; move checks that use tagToAdd, tags, maxLength, and maxTags into that helper which should return a result object (status: 'add'|'error'|'ignore', errorMessage?, remainingText?) so handleInputChange can call the helper, apply onChange([...tags, tagToAdd]) when status==='add', or setError(errorMessage) and always setInputText(remainingText) otherwise; keep references to onChange, setError, setInputText, tags, maxLength, and maxTags intact.frontend/components/ListingCard.tsx (1)
21-51: Prefer the shared entrance-animation hook here.This local animation setup duplicates logic now provided by
frontend/hooks/useEntranceAnimation.ts; reusing the hook would reduce maintenance drift across cards/screens.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/ListingCard.tsx` around lines 21 - 51, This component duplicates entrance animation logic; replace the local refs/effect/memo with the shared hook by importing useEntranceAnimation and calling it inside ListingCard to obtain the animated values/style instead of manually creating opacity, translateY, useEffect, and animatedStyle; remove the local constants (opacity, translateY, animation useEffect, and animatedStyle) and use the hook's returned animatedStyle (or values) where the component currently consumes animatedStyle so ListingCard uses the centralized useEntranceAnimation implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.agents/skills/building-native-ui/references/form-sheet.md:
- Around line 42-43: The layout file is incorrectly rendering <Stack.Header> as
a child of <Stack.Screen> (e.g., the <Stack.Header> inside the <Stack.Screen> in
_layout.tsx); remove these nested <Stack.Header> blocks entirely and rely on the
existing options prop (e.g., headerTransparent: true) on <Stack.Screen>, and if
you need to use the composition API (<Stack.Header>, <Stack.Header.Right>, etc.)
move those into the individual route component files (e.g., app/yourRoute.tsx)
rather than keeping them inside the layout.
In @.agents/skills/expo-api-routes/SKILL.md:
- Around line 166-178: The corsHeaders example is too permissive: update the
cors logic used by corsHeaders and the OPTIONS/GET handlers to enforce an
explicit origin allowlist instead of Access-Control-Allow-Origin: '*', add a
"Vary: Origin" header, and only include "Authorization" in
Access-Control-Allow-Headers (and set Access-Control-Allow-Credentials if you
intend to support credentials) when the incoming Origin matches the allowlist;
locate and modify the corsHeaders constant and the OPTIONS and GET functions to
compute headers per-request (using the request Origin) rather than returning a
static permissive object.
In @.agents/skills/expo-cicd-workflows/scripts/validate.js:
- Around line 15-19: The fetchSchema function lacks defensive error handling
around the network/parse/compile path; wrap the fetchCached call and JSON.parse
inside a try/catch in fetchSchema, validate that parsed body and body.data exist
(throw a clear error or return a safe default), and on failure log a descriptive
error and exit with a non-zero code (or rethrow a wrapped error) so the CLI
doesn't crash unpredictably; apply the same pattern to the other parse/compile
step referenced in the diff (the compile/parse call around lines 66-67—e.g.,
compileSchema or wherever JSON.parse/compile is used) to ensure all external
calls and parsing have guarded error handling and clear logs.
- Around line 27-35: The validateFile function currently calls
readFile(filePath, 'utf-8') without handling IO errors, so file read failures
(ENOENT, EACCES, etc.) can crash the process; wrap the readFile call in a
try/catch (or add a separate try around it) and on failure return a per-file
result like { valid: false, error: `File read error: ${err.message}` } (include
err.code or err.message for diagnostics), ensuring the rest of validateFile
(yaml.load and its existing catch) only runs when the file was read
successfully.
- Line 55: The check using import.meta.main is unsupported on Node <22.18.0;
replace it with a Node-compatible entrypoint detection by computing the module
file path via fileURLToPath(import.meta.url) and comparing it to process.argv[1]
(i.e., treat the module as main when fileURLToPath(import.meta.url) ===
process.argv[1]). Update the conditional that currently uses import.meta.main in
validate.js to use this fileURLToPath(import.meta.url) vs process.argv[1]
comparison so it works on Node.js >=18 as declared.
In @.agents/skills/expo-deployment/references/app-store-metadata.md:
- Line 143: Remove the bullet that reads "Include competitor brand names
(carefully)" from app-store-metadata.md and replace it with safer guidance:
advise using descriptive, non-infringing, brand-safe keywords (e.g., feature-
and category-focused terms) and explicitly warn against using competitor
trademarks to avoid App Store policy/trademark issues; update any surrounding
list items or examples to reflect this change.
- Around line 77-83: Replace the plaintext demo credential in the example
object's review.notes with a non-sensitive placeholder and add a brief note to
inject real secrets from secure storage; specifically update the "review"
example (keys: firstName, lastName, email, phone, notes) so notes uses a
placeholder like "Demo account: <USERNAME> / <PASSWORD>" or "DO NOT COMMIT: set
via env/CI", and mention in the surrounding documentation that actual
credentials must be provided from secure environment variables or a secrets
manager during deployment.
In @.agents/skills/expo-deployment/references/ios-app-store.md:
- Around line 39-54: Add an explicit security note warning contributors to never
commit .p8 private keys and recommend using a secret manager or CI-injected
environment variables (the same mechanism shown by EXPO_ASC_API_KEY_PATH /
EXPO_ASC_API_KEY_ISSUER_ID / EXPO_ASC_API_KEY_ID). Insert a short paragraph or
blockquote near the existing examples that states: "Security: Never commit `.p8`
private keys to the repository. Store them in a secure secret manager and inject
paths/contents via CI environment variables." and place it directly above or
below the env var example so readers see the precaution when configuring ASC
keys.
In @.agents/skills/native-data-fetching/references/expo-router-loaders.md:
- Around line 205-215: The current snippet fetches Stripe balance before
validating the request and returns raw balance data; change flow to first
validate the session token (extracting sessionToken from request.headers as
currently done) and refuse/throw or return an unauthenticated response unless
the session is valid, then call the privileged Stripe API only when
authenticated; after fetching, map the Stripe response to a minimal safe shape
(e.g., available_balance and currency) instead of returning the full JSON, and
ensure the fetch uses server-only secret access (Authorization: Bearer from
process.env) without echoing secrets or raw error objects in responses—apply
these changes around the existing sessionToken extraction and the balance
fetch/return logic.
In `@frontend/app/listings/`[id].tsx:
- Around line 47-52: Replace the hardcoded origin when building the share URL so
it uses the environment variable; update the construction of shareUrl (used
before calling Share.share) to read process.env.EXPO_PUBLIC_APP_ORIGIN and
concatenate `/l/${listing._id}` instead of `"https://polybuys.com"`, and ensure
Share.share still receives the same message, url, and title values (refer to
shareUrl, Share.share, and listing._id in the change).
In `@frontend/app/listings/`[id]/edit.tsx:
- Around line 236-240: Update the cancel button logic so it is disabled while
there are pending uploads: in the Pressable that currently uses
disabled={isSubmitting}, include hasPendingUploads in the condition (e.g.,
disabled={isSubmitting || hasPendingUploads}) or alternatively guard router.back
with a confirmation when hasPendingUploads is true; modify the Pressable's
onPress handler (referencing Pressable, onPress, router.back, and the
isSubmitting/hasPendingUploads flags) to prevent navigation during active
uploads or prompt confirmation.
In `@frontend/app/listings/new.tsx`:
- Around line 241-245: The Cancel Pressable currently only uses isSubmitting to
disable navigation and should also block leaving when uploads are in progress;
update the Pressable disabled condition (and any onPress logic that calls
router.back()) to include hasPendingUploads (e.g., disabled={isSubmitting ||
hasPendingUploads}) or show a confirmation prompt before calling router.back();
adjust any related UX (styles.cancelButton/pressed behavior) so the button is
inert while hasPendingUploads is true.
---
Outside diff comments:
In `@frontend/app/auth/login.tsx`:
- Around line 55-59: The code-length check in handleVerifyCode only enforces an
8-character length but not that the code is numeric; update handleVerifyCode to
validate that the trimmed code is exactly 8 digits (e.g., match against a
digits-only pattern) and set a clear error when it contains non-digit
characters, and apply the same digits-only validation to the other
code-validation handler in this module so both enforce an 8-digit numeric code
consistently.
In `@frontend/app/listings/new.tsx`:
- Around line 1-393: This file failed CI formatting (Prettier) — run the
project's formatter on this file (e.g., npm run format or prettier --write) and
save the changes so the Prettier rules are applied; ensure NewListingScreen and
its surrounding imports/JSX/StyleSheet are properly formatted and that there are
no trailing commas/spacing issues left by the linter before committing.
---
Minor comments:
In @.agents/skills/building-native-ui/references/media.md:
- Line 5: The documentation line "Hide navigation headers when there's a full
screen camera" should be updated to hyphenate "full-screen" for consistency;
edit the sentence in media.md (the line containing "Hide navigation headers when
there's a full screen camera") to read "Hide navigation headers when there's a
full-screen camera".
In @.agents/skills/building-native-ui/references/route-structure.md:
- Around line 18-24: The markdown contains unlabeled fenced code blocks showing
directory trees (e.g., the block starting with "app/", "users/", "[id].tsx", and
similar directory-tree blocks elsewhere) which trigger markdownlint MD040;
update each of those code fences to include the language label "text" (so the
opening fence becomes ```text) for all directory-tree examples (including the
blocks that correspond to the examples shown and the other unlabeled blocks
referenced) to satisfy the linter.
In @.agents/skills/building-native-ui/references/tabs.md:
- Around line 305-309: The fenced route-structure block containing the lines
with "_layout.tsx # NativeTabs for iOS/Android" and "_layout.web.tsx
# Headless tabs for web (expo-router/ui)" is missing a language label; update
the opening code fence (the triple backticks that begin that block) to include
the label text (i.e., change ``` to ```text) to satisfy markdownlint MD040.
In @.agents/skills/building-native-ui/references/webgpu-three.md:
- Around line 492-503: The final two fenced code blocks that show the project
tree (containing entries like "src/", "components/", "lib/", and filenames such
as "fiber-canvas.tsx", "make-webgpu-renderer.ts", "orbit-controls.tsx") are
missing language labels; update those two fences to use the "text" language tag
(i.e., change ``` to ```text) so the tree/decision blocks are labeled and
satisfy markdownlint MD040.
In @.agents/skills/building-native-ui/references/zoom-transitions.md:
- Line 155: Update the sentence "When source is unavailable (e.g., scrolled off
screen), the transition zooms from the center of the screen" to use the
hyphenated form "off-screen" so it reads "When source is unavailable (e.g.,
scrolled off-screen), the transition zooms from the center of the screen";
locate this exact line in zoom-transitions.md and make the single-word
hyphenation change.
In @.agents/skills/building-native-ui/SKILL.md:
- Around line 14-30: The unlabeled fenced code blocks in SKILL.md (the
directory-tree snippets shown in the references/ block and the other block
around lines 249-256) need explicit language tags to satisfy markdownlint MD040;
add the language identifier `text` to the opening fences for those snippets
(i.e., change ``` to ```text for the directory-tree blocks) so the fenced blocks
in the references section and the block at lines ~249-256 are labeled.
In @.agents/skills/expo-api-routes/SKILL.md:
- Around line 35-43: The fenced code block that shows the directory tree (the
block starting with the lines showing "app/", "api/", "hello+api.ts", etc.) is
unlabeled and triggers markdownlint MD040; add a language tag "text" to the
opening triple backticks so the block reads as a text code fence (```text) to
silence the lint error and keep the directory tree formatting intact in
SKILL.md.
In @.agents/skills/expo-cicd-workflows/scripts/validate.js:
- Around line 59-63: The help path incorrectly returns exit code 1 when no files
are passed but help flags are present; update the exit logic around the
conditional that checks files/args (using the variables files, args and calling
process.exit) so that if args.includes('--help') || args.includes('-h') the
script always exits with 0, otherwise keep the current behavior of exiting 1
when files.length === 0 and 0 when files exist.
In @.agents/skills/expo-deployment/references/app-store-metadata.md:
- Around line 128-133: The example for the JSON "keywords" field is
inconsistent: it currently shows a single CSV string inside the array; update it
to the canonical format used elsewhere by making "keywords" an array of
individual keyword strings (e.g., "keywords":
["finance","budget","expense",...]) so copy/paste users get the correct type;
locate the JSON example that contains the "keywords" key and replace the
CSV-in-array value with an array of separate string entries.
In @.agents/skills/expo-tailwind-setup/SKILL.md:
- Around line 39-40: Update the user-facing text to use canonical product names:
replace occurrences of "lightningcss" with "Lightning CSS" and "expo" with
"Expo" in the SKILL.md content lines that read "autoprefixer is not needed in
Expo because of lightningcss" and "postcss is included in expo by default" so
both references use proper capitalization and naming. Ensure only the product
names are changed and surrounding wording remains unchanged.
In @.agents/skills/upgrading-expo/references/native-tabs.md:
- Line 29: The BottomAccessory description uses the ambiguous string "iOS +26";
update this to a standard, unambiguous iOS version notation (e.g., "iOS 16+" or
the correct target such as "iOS 17+") or add a short clarifying parenthetical
explaining what "+26" means, and ensure the text references the Expo SDK 55
baseline (iOS 15.1+) if this requirement is above that baseline; modify the
BottomAccessory line in native-tabs.md to replace "iOS +26" with the chosen
standard notation and a one-line note if needed to avoid confusion.
In @.agents/skills/upgrading-expo/references/react-19.md:
- Line 22: The sentence "`use` can be called conditionally, this simplifies
components that consume multiple contexts." contains a comma splice; split it
into two sentences by changing it to "`use` can be called conditionally. This
simplifies components that consume multiple contexts." to improve readability.
In `@frontend/app/`(tabs)/_layout.tsx:
- Around line 68-71: The iOS tab label color is fixed to styles.iosTabLabel
(which hardcodes color '#111111') causing unreadable text in dark mode; update
nativeTabLabelStyle assignment to choose styles.iosTabLabelDark when isDarkMode
is true (or compute a dynamic style using isDarkMode) so the label color matches
tabTint, and remove the now-unused iosTabLabel style definition; change
references around nativeTabLabelStyle, isDarkMode, tabTint, and
styles.iosTabLabel so both label color and tint adapt to dark mode (also apply
the same fix to the other occurrence at the later block referenced).
---
Duplicate comments:
In @.agents/skills/building-native-ui/references/tabs.md:
- Around line 397-399: The ThemeProvider usage is passing the theme object via
the wrong prop name (`theme`); update both ThemeProvider instances (wrapping
<Stack /> and the other occurrence around the other component) to use
value={colorScheme === 'dark' ? DarkTheme : DefaultTheme} instead of
theme={...}; ensure you only rename the prop on the ThemeProvider components
(symbol: ThemeProvider) so typed consumers of `@react-navigation/native` receive
the theme via the expected value prop.
In @.agents/skills/building-native-ui/references/webgpu-three.md:
- Around line 164-206: The effect is missing a dependency array so the WebGPU
canvas and react-three root are recreated on every render; change the useEffect
to run only once by adding an empty dependency array (useEffect(..., [])) and
move dynamic updates (like re-rendering children) into a separate effect that
watches children (e.g. useEffect(() => root.current?.render(children),
[children])); keep the existing cleanup that calls
unmountComponentAtNode(canvas) and ensure you still reference canvasRef,
createRoot, root.current.configure, and root.current.render in their current
places.
In @.agents/skills/expo-dev-client/SKILL.md:
- Around line 170-173: The doc currently shows the wrong command ("eas update")
for upgrading the EAS CLI; replace the second line in the code block that
currently reads "eas update" with an explicit package-manager install to upgrade
the CLI (for example "npm install --global eas-cli@latest") and keep "eas
--version" for verifying the CLI version so the code block demonstrates checking
the version and the correct upgrade command instead of publishing an OTA update.
In @.agents/skills/expo-tailwind-setup/SKILL.md:
- Line 25: The install command pins a nightly build for react-native-css; update
the npx install line (the shown "npx expo install tailwindcss@^4
nativewind@5.0.0-preview.2 react-native-css@0.0.0-nightly.5ce6396 ...") to use a
stable react-native-css release (either remove the explicit nightly version or
pin to the official stable semver) and likewise avoid preview tags for
nativewind unless intentionally desired (replace nativewind@5.0.0-preview.2 with
the stable/nativewind@latest or a documented stable version); make the change in
the npx command and any accompanying text in SKILL.md so the example shows
stable packages instead of the nightly preview build.
In @.agents/skills/upgrading-expo/references/react-19.md:
- Around line 9-10: The sentence claiming "`use` replaces `useContext`" is
misleading; update the text to clarify that React 19 supports both APIs and that
`use(resource)` is a more flexible alternative for some patterns but does not
remove or replace `useContext`; specifically edit the statement mentioning `use`
and `useContext` so it reads that both are supported, outline when to prefer
`use` (e.g., async resources, Suspense-driven data) versus `useContext` (context
propagation), and adjust any examples or guidance that assert replacement to
instead compare trade-offs between `use` and `useContext`.
---
Nitpick comments:
In @.agents/skills/building-native-ui/references/icons.md:
- Around line 16-19: The fenced code block in
.agents/skills/building-native-ui/references/icons.md is missing a language
specifier (closing/backtick block around the references/ listing); update the
opening fence to include a language (e.g., ```text) so the snippet becomes
```text ... ``` to satisfy linting and maintain consistency with other docs.
In @.agents/skills/native-data-fetching/SKILL.md:
- Around line 16-19: The fenced code block showing the references directory
listing in SKILL.md is missing a language specifier; update the opening
triple-backtick for the block that contains "references/" and
"expo-router-loaders.md" to include a language tag (e.g., use ```text) so the
block is properly rendered and highlighted in markdown.
- Around line 415-449: The fenced decision-tree code block starting with "User
asks about networking" lacks a language specifier; update that code fence to
include a plain-text language tag (e.g., ```text or ```plaintext) so the block
is consistently highlighted and formatted—locate the triple-backtick fence
before the "User asks about networking" block in SKILL.md and add the language
token immediately after the opening backticks.
In @.agents/skills/upgrading-expo/SKILL.md:
- Around line 40-44: The step currently tells users to run "watchman
watch-del-all", which isn't available on many platforms; update SKILL.md to add
a cross-platform fallback note: if watchman isn't installed, instruct users to
either run a platform-safe cache/cleanup command (examples: "expo start -c",
"git clean -fdx" for CI, or use a Node tool like "npx rimraf .expo" /
platform-specific removal on Windows) or skip with a clear message, and show a
brief conditional suggestion like "if watchman exists run it otherwise run
fallback" so the upgrade step doesn't block on Windows/CI.
In `@backend/convex/ResendOTP.ts`:
- Around line 43-47: The check in ResendOTP.ts uses
resendFromAddress.toLowerCase().includes('onboarding@resend.dev') which can
match unintended strings; change it to a precise comparison (e.g., compare the
lowercased whole address for equality) or use an anchored regex that validates
the email portion equals onboarding@resend.dev before throwing the ConvexError,
updating the conditional that references resendFromAddress and the ConvexError
message accordingly.
In `@frontend/app/`(tabs)/search.tsx:
- Around line 35-36: The two refs filterVersionRef and currentFilterVersionRef
are redundant—keep a single ref (e.g., filterVersionRef) and use it both to read
the render-time version (queryFilterVersion) and to mark the effect-consumed
version; update places that increment or assign currentFilterVersionRef to
instead increment filterVersionRef and compare queryFilterVersion against
filterVersionRef inside the useEffect that processes filter changes (the effect
that currently checks those two refs), and remove all references to
currentFilterVersionRef to simplify tracking.
In `@frontend/components/ListingCard.tsx`:
- Around line 21-51: This component duplicates entrance animation logic; replace
the local refs/effect/memo with the shared hook by importing
useEntranceAnimation and calling it inside ListingCard to obtain the animated
values/style instead of manually creating opacity, translateY, useEffect, and
animatedStyle; remove the local constants (opacity, translateY, animation
useEffect, and animatedStyle) and use the hook's returned animatedStyle (or
values) where the component currently consumes animatedStyle so ListingCard uses
the centralized useEntranceAnimation implementation.
In `@frontend/components/TagInput.tsx`:
- Around line 63-97: Refactor the comma-add logic in handleInputChange by
extracting the per-tag validation into a helper (e.g., validateAndProcessTag or
isValidTag) so the main function stops nesting; move checks that use tagToAdd,
tags, maxLength, and maxTags into that helper which should return a result
object (status: 'add'|'error'|'ignore', errorMessage?, remainingText?) so
handleInputChange can call the helper, apply onChange([...tags, tagToAdd]) when
status==='add', or setError(errorMessage) and always setInputText(remainingText)
otherwise; keep references to onChange, setError, setInputText, tags, maxLength,
and maxTags intact.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (69)
.agents/skills/building-native-ui/SKILL.md.agents/skills/building-native-ui/references/animations.md.agents/skills/building-native-ui/references/controls.md.agents/skills/building-native-ui/references/form-sheet.md.agents/skills/building-native-ui/references/gradients.md.agents/skills/building-native-ui/references/icons.md.agents/skills/building-native-ui/references/media.md.agents/skills/building-native-ui/references/route-structure.md.agents/skills/building-native-ui/references/search.md.agents/skills/building-native-ui/references/storage.md.agents/skills/building-native-ui/references/tabs.md.agents/skills/building-native-ui/references/toolbar-and-headers.md.agents/skills/building-native-ui/references/visual-effects.md.agents/skills/building-native-ui/references/webgpu-three.md.agents/skills/building-native-ui/references/zoom-transitions.md.agents/skills/expo-api-routes/SKILL.md.agents/skills/expo-cicd-workflows/SKILL.md.agents/skills/expo-cicd-workflows/scripts/fetch.js.agents/skills/expo-cicd-workflows/scripts/package.json.agents/skills/expo-cicd-workflows/scripts/validate.js.agents/skills/expo-deployment/SKILL.md.agents/skills/expo-deployment/references/app-store-metadata.md.agents/skills/expo-deployment/references/ios-app-store.md.agents/skills/expo-deployment/references/play-store.md.agents/skills/expo-deployment/references/testflight.md.agents/skills/expo-deployment/references/workflows.md.agents/skills/expo-dev-client/SKILL.md.agents/skills/expo-tailwind-setup/SKILL.md.agents/skills/native-data-fetching/SKILL.md.agents/skills/native-data-fetching/references/expo-router-loaders.md.agents/skills/upgrading-expo/SKILL.md.agents/skills/upgrading-expo/references/expo-av-to-audio.md.agents/skills/upgrading-expo/references/expo-av-to-video.md.agents/skills/upgrading-expo/references/native-tabs.md.agents/skills/upgrading-expo/references/new-architecture.md.agents/skills/upgrading-expo/references/react-19.md.agents/skills/upgrading-expo/references/react-compiler.md.agents/skills/use-dom/SKILL.md.cursor/settings.json.eslintrc.jsbabel.jest.config.jsbackend/.env.examplebackend/convex/ResendOTP.tsbackend/convex/auth.config.tsdocs/contributing.mdfrontend/app.jsonfrontend/app/(tabs)/_layout.tsxfrontend/app/(tabs)/index.tsxfrontend/app/(tabs)/search.tsxfrontend/app/(tabs)/settings.tsxfrontend/app/_layout.tsxfrontend/app/auth/login.tsxfrontend/app/listings/[id].tsxfrontend/app/listings/[id]/edit.tsxfrontend/app/listings/new.tsxfrontend/babel.config.jsfrontend/components/CategoryPicker.tsxfrontend/components/FilterBar.tsxfrontend/components/HiddenBanner.tsxfrontend/components/ListingCard.tsxfrontend/components/ListingUnavailable.tsxfrontend/components/PriceRangePicker.tsxfrontend/components/TagInput.tsxfrontend/components/TagPicker.tsxfrontend/hooks/useEntranceAnimation.tsfrontend/package.jsonfrontend/tsconfig.jsonjest.config.jsskills-lock.json
✅ Files skipped from review due to trivial changes (1)
- .agents/skills/upgrading-expo/references/expo-av-to-video.md
🚧 Files skipped from review as they are similar to previous changes (29)
- .agents/skills/building-native-ui/references/gradients.md
- frontend/components/HiddenBanner.tsx
- .cursor/settings.json
- .agents/skills/building-native-ui/references/animations.md
- backend/.env.example
- .agents/skills/expo-deployment/references/workflows.md
- .agents/skills/upgrading-expo/references/react-compiler.md
- .eslintrc.js
- docs/contributing.md
- .agents/skills/expo-deployment/SKILL.md
- .agents/skills/building-native-ui/references/search.md
- skills-lock.json
- .agents/skills/upgrading-expo/references/expo-av-to-audio.md
- .agents/skills/expo-cicd-workflows/SKILL.md
- .agents/skills/expo-cicd-workflows/scripts/fetch.js
- .agents/skills/use-dom/SKILL.md
- frontend/hooks/useEntranceAnimation.ts
- backend/convex/auth.config.ts
- frontend/components/CategoryPicker.tsx
- .agents/skills/upgrading-expo/references/new-architecture.md
- frontend/app/_layout.tsx
- frontend/app/(tabs)/index.tsx
- .agents/skills/expo-deployment/references/play-store.md
- frontend/components/PriceRangePicker.tsx
- .agents/skills/building-native-ui/references/storage.md
- frontend/babel.config.js
- frontend/tsconfig.json
- .agents/skills/expo-deployment/references/testflight.md
- .agents/skills/building-native-ui/references/controls.md
- Deleted Babel configuration file as it is no longer needed. - Updated Jest configuration to specify Babel config file path. - Added environment variables for email handling in backend. - Enhanced email validation and error handling in ResendOTP function. - Improved frontend components with better loading states and animations. - Updated dependencies in package-lock.json for compatibility with new Expo version.
- Updated auth configuration to use a unified provider domain from environment variables. - Simplified search component logic to enhance performance and maintain reactivity for first-page results. - Removed unnecessary cursor handling for improved clarity in state management.
…n package files - Upgraded expo-image-manipulator to version 55.0.9 and expo-image-picker to version 55.0.10 in both package-lock.json and package.json for improved functionality and compatibility.
- Added a function to dynamically determine the app origin for shareable links in the ListingDetailScreen. - Updated the cancel button in both NewListingScreen and EditListingScreen to be disabled during submissions or pending uploads, with visual feedback for disabled state.
fe176f6 to
b11d43c
Compare
There was a problem hiding this comment.
Actionable comments posted: 8
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/app/listings/new.tsx (1)
66-69:⚠️ Potential issue | 🟠 MajorTreat empty price as missing before numeric parsing.
Line 66 currently allows an empty input (
'') to pass as0. Add an explicit non-empty check beforeNumber(...).🛠️ Proposed fix
- const parsedPrice = Number(price); + const normalizedPrice = price.trim(); + if (!normalizedPrice) { + Alert.alert('Missing fields', 'Price is required.'); + return; + } + + const parsedPrice = Number(normalizedPrice); if (!Number.isFinite(parsedPrice) || parsedPrice < 0) { Alert.alert('Invalid price', 'Please enter a valid non-negative price.'); return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/listings/new.tsx` around lines 66 - 69, The current logic converts price to a Number which treats an empty string as 0; before calling Number(price) and checking Number.isFinite(parsedPrice) in the form submission (the code that defines parsedPrice and uses Alert.alert), add an explicit check that price is non-empty (e.g., price !== '' or price.trim() !== '') and treat an empty value as missing (show the same "Invalid price" Alert.alert or a specific "Price required" message) and return early; keep the subsequent Number(...) and Number.isFinite(parsedPrice) / parsedPrice < 0 checks unchanged.frontend/app/auth/login.tsx (1)
100-104:⚠️ Potential issue | 🟡 MinorClear success state when returning to the email step
handleBackleavessuccessMessageintact, so the resend-success banner can appear on the email step with stale context.🔧 Suggested fix
const handleBack = () => { setStep('email'); setCode(''); setError(null); + setSuccessMessage(null); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 100 - 104, handleBack currently resets step, code, and error but leaves successMessage set, causing a stale resend-success banner on the email step; update the handler (handleBack) to also clear the success state by invoking the state setter for successMessage (e.g., setSuccessMessage(null) or an empty string) when navigating back so the banner is removed alongside setStep('email'), setCode(''), and setError(null).
♻️ Duplicate comments (17)
.agents/skills/expo-dev-client/SKILL.md (1)
168-173:⚠️ Potential issue | 🟠 MajorReplace incorrect CLI upgrade command in Line 172.
eas updatepublishes app OTA updates; it does not upgrade EAS CLI. In this section, keepeas --versionand replace Line 172 with an actual CLI upgrade command.Proposed doc fix
**Check EAS CLI version:** ```bash eas --version -eas update +# Upgrade EAS CLI +npm install --global eas-cli@latest</details> ```web Expo official docs: what does `eas update` do, and what is the recommended way to upgrade/install the latest `eas-cli`?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-dev-client/SKILL.md around lines 168 - 173, In the "Check EAS CLI version" doc block replace the incorrect `eas update` command (which publishes OTA updates) with the actual CLI upgrade instruction; keep the existing `eas --version` check and change the second command to the recommended installer command (for example, use npm install --global eas-cli@latest) so the section correctly verifies version and shows how to upgrade the EAS CLI..agents/skills/use-dom/SKILL.md (2)
261-271:⚠️ Potential issue | 🟠 MajorDocument missing router caveats (
canGoBack/canDismiss).The unsupported-routing section should also call out
router.canGoBack()androuter.canDismiss()as values to marshal from native, alongside the listed synchronous hooks.Proposed doc patch
These hooks don't work directly in DOM components because they need synchronous access to native routing state: @@ - `useRootNavigation()` - `useRootNavigationState()` +- `router.canGoBack()` +- `router.canDismiss()`Expo DOM components + expo-router: are `router.canGoBack()` and `router.canDismiss()` unsupported directly inside DOM components and expected to be marshalled from native?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/use-dom/SKILL.md around lines 261 - 271, The docs list router hooks that require synchronous native routing state but omitted router.canGoBack() and router.canDismiss(); update the "Router APIs That Require Props" section to explicitly mention that router.canGoBack() and router.canDismiss() are unsupported directly in DOM components and must be marshalled from native (alongside useLocalSearchParams(), usePathname(), useSegments(), useRootNavigation(), useRootNavigationState(), etc.), and add a short note or example clarifying that these boolean methods should be derived on the native side and passed into the DOM component as props.
63-71:⚠️ Potential issue | 🟠 MajorNormalize
domprop guidance (currently contradictory).Line 63 says “Every DOM component receives
dom…”, but examples alternate between required and optional typing. Make the docs consistent by typingdom?: import('expo/dom').DOMPropsunless an example specifically requires explicit webview options.Proposed doc patch
-Every DOM component receives a special `dom` prop for webview configuration. Always type it in your props: +DOM components can receive a special `dom` prop for webview configuration. Type it as optional unless your component requires specific webview options:-export default function WebChart({ data }: { data: number[]; dom: import('expo/dom').DOMProps }) { +export default function WebChart({ data }: { data: number[]; dom?: import('expo/dom').DOMProps }) {Expo DOM components docs: is the `dom` prop optional at runtime and should TypeScript props usually declare `dom?: DOMProps`?Also applies to: 39-40, 180-181, 206-207, 231-232, 249-250, 331-332
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/use-dom/SKILL.md around lines 63 - 71, The docs are inconsistent about whether the special dom prop is required; update the examples to make dom optional by changing prop typings like the interface named Props (the example block starting with 'interface Props { content: string; dom: import('expo/dom').DOMProps; }') to use dom?: import('expo/dom').DOMProps so examples consistently show dom as optional unless a specific example needs explicit webview options; apply the same normalization to all other example occurrences referenced (lines around 39-40, 180-181, 206-207, 231-232, 249-250, 331-332) so every example uses dom? unless the example explicitly documents required webview options..agents/skills/expo-cicd-workflows/scripts/validate.js (3)
55-55:⚠️ Potential issue | 🟠 MajorReplace
import.meta.mainwith a Node-compatible main-module check.Line 55 depends on
import.meta.main, which is not consistently available across older Node runtimes. UsefileURLToPath(import.meta.url) === process.argv[1]for broader compatibility.Proposed fix
import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import process from 'node:process'; @@ -if (import.meta.main) { +const isMain = process.argv[1] === fileURLToPath(import.meta.url); +if (isMain) {#!/bin/bash set -euo pipefail # Verify declared Node engine range(s) rg -n -A3 -B2 '"engines"\s*:\s*\{' package.json .agents/skills/expo-cicd-workflows/scripts/package.json # Verify use of import.meta.main in this script rg -nP '\bimport\.meta\.main\b' .agents/skills/expo-cicd-workflows/scripts/validate.js🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js at line 55, The script uses import.meta.main which is not available on older Node runtimes; replace the main-module check by converting import.meta.url to a file path and comparing it to process.argv[1] (use fileURLToPath(import.meta.url) === process.argv[1]) so the top-level invocation detection is Node-compatible; add the import/require for fileURLToPath if needed and update the conditional that currently references import.meta.main to use this new comparison (look for the occurrence of import.meta.main and import.meta.url in validate.js).
27-35:⚠️ Potential issue | 🟠 MajorHandle file read errors per file instead of crashing the whole run.
Line 28 can throw and currently bypasses your YAML error path. Return a per-file validation error when read fails.
Proposed fix
async function validateFile(validator, filePath) { - const content = await readFile(filePath, 'utf-8'); + let content; + try { + content = await readFile(filePath, 'utf-8'); + } catch (e) { + return { valid: false, error: `File read error: ${e.message}` }; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 27 - 35, The validateFile function currently calls readFile(filePath, 'utf-8') which can throw and bypass the existing YAML parse error handling; wrap the readFile call in its own try/catch inside validateFile (before calling yaml.load) and on error return a per-file validation object like { valid: false, error: `File read error: ${err.message}` } (include filePath/context if useful) so failures to read one file don't crash the whole run; keep the existing yaml.load try/catch for parse errors.
15-19:⚠️ Potential issue | 🟠 MajorGuard schema fetch/parse/compile failures and return a deterministic CLI error.
Line 15 and Line 66 currently allow uncaught failures in fetch/JSON parse/schema compile. This can abort the validator without a clear CI-facing error report.
Proposed fix
async function fetchSchema() { - const data = await fetchCached(SCHEMA_URL); - const body = JSON.parse(data); - return body.data; + let body; + try { + const data = await fetchCached(SCHEMA_URL); + body = JSON.parse(data); + } catch (e) { + throw new Error(`Failed to fetch/parse workflow schema: ${e.message}`); + } + if (!body?.data || typeof body.data !== 'object') { + throw new Error('Invalid schema response: missing `data` object'); + } + return body.data; } @@ - const schema = await fetchSchema(); - const validator = createValidator(schema); + let validator; + try { + const schema = await fetchSchema(); + validator = createValidator(schema); + } catch (e) { + console.error(`Failed to initialize schema validator: ${e.message}`); + process.exit(1); + }Also applies to: 66-67
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 15 - 19, The fetchSchema flow (async function fetchSchema) currently permits uncaught failures from fetchCached and JSON.parse (and similarly the schema compile step referenced around lines 66-67); wrap the fetchCached call, JSON.parse, and the schema compilation in a single try/catch, validate that the parsed object has the expected data property before returning, and on any error log a deterministic, CI-friendly error message and exit with a non-zero status (or throw a well-formed Error) so the validator fails predictably instead of aborting with an uncaught exception..agents/skills/expo-deployment/references/app-store-metadata.md (2)
143-143:⚠️ Potential issue | 🟠 MajorRemove recommendation to use competitor brand names in keywords.
Line 143 can lead to trademark/policy risk in App Store submissions. Prefer descriptive, non-infringing, brand-safe terms instead.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/app-store-metadata.md at line 143, Remove the recommendation "Include competitor brand names (carefully)" and replace it with guidance to avoid competitor/trademarked brand names in App Store keywords and metadata; update the text surrounding the phrase so it advises using descriptive, non-infringing, brand-safe keywords and terms instead (search for the exact phrase "Include competitor brand names (carefully)" to locate the line).
77-83:⚠️ Potential issue | 🟠 MajorRemove plaintext credential patterns from review examples.
Lines 77-83 and 377-387 normalize storing demo usernames/passwords directly in config examples. Use placeholders and explicitly direct readers to secure secret injection.
Suggested patch
- "notes": "Demo account: test@example.com / password123" + "notes": "Demo account credentials are injected via secure CI secrets. Do not commit real credentials." @@ - "demoUsername": "demo@example.com", - "demoPassword": "ReviewDemo2025!", - "notes": "To test premium features:\n1. Log in with demo credentials\n2. Navigate to Settings > Subscription\n3. Tap 'Restore Purchase' - sandbox purchase will be restored\n\nFor location features, allow location access when prompted." + "demoUsername": "<DEMO_USERNAME_FROM_SECRET>", + "demoPassword": "<DEMO_PASSWORD_FROM_SECRET>", + "notes": "Demo credentials are provided securely via CI/secret manager. Do not commit real credentials."Also applies to: 377-387
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/app-store-metadata.md around lines 77 - 83, Replace plaintext demo credentials in the "review" example objects (the review JSON with keys firstName, lastName, email, phone, notes) with non-sensitive placeholders (e.g., "<REVIEWER_EMAIL>", "<DEMO_USERNAME>", "<DEMO_PASSWORD>") and add a brief note directing readers to inject real secrets via secure secret management or environment/CI secret injection rather than hardcoding; update both occurrences of the "review" example to use placeholders and the explanatory sentence about secure secret injection..agents/skills/expo-deployment/references/ios-app-store.md (1)
39-54:⚠️ Potential issue | 🟠 MajorAdd an explicit “never commit
.p8keys” warning near the API key examples.This security warning is still missing around Lines 39-54 where key paths/env vars are shown.
Suggested patch
Or use environment variables: @@ EXPO_ASC_API_KEY_ID=XXXXXXXXXX
+> Security: Never commit
.p8private keys to the repository. Store them in a secure secret manager and inject paths/contents via CI environment variables.</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/expo-deployment/references/ios-app-store.md around lines 39 -
54, Add an explicit security warning immediately above or below the API key
examples that show "ascApiKeyPath" and the corresponding EXPO_ASC_* environment
variables: state clearly "Security: Never commit.p8private keys to the
repository. Store them in a secure secret manager and inject paths/contents via
CI environment variables." Ensure this notice is prominent and adjacent to the
code block that lists ascApiKeyPath/ascApiKeyIssuerId/ascApiKeyId and the
EXPO_ASC_API_KEY_* env var examples so readers cannot miss it.</details> </blockquote></details> <details> <summary>.agents/skills/expo-api-routes/SKILL.md (1)</summary><blockquote> `166-178`: _⚠️ Potential issue_ | _🟠 Major_ **Harden the default CORS template; current example is overly permissive.** Line 167 uses wildcard origin while Line 169 allows `Authorization`. For auth-capable APIs, this should be origin-scoped and include `Vary: Origin`. <details> <summary>🔐 Suggested docs patch</summary> ```diff -const corsHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization', -}; +const ALLOWED_ORIGINS = ['https://app.example.com']; + +function corsHeaders(origin: string | null) { + const allowOrigin = origin && ALLOWED_ORIGINS.includes(origin) ? origin : ALLOWED_ORIGINS[0]; + return { + 'Access-Control-Allow-Origin': allowOrigin, + Vary: 'Origin', + 'Access-Control-Allow-Credentials': 'true', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }; +} -export function OPTIONS() { - return new Response(null, { headers: corsHeaders }); +export function OPTIONS(request: Request) { + return new Response(null, { headers: corsHeaders(request.headers.get('Origin')) }); } -export function GET() { - return Response.json({ data: 'value' }, { headers: corsHeaders }); +export function GET(request: Request) { + return Response.json({ data: 'value' }, { headers: corsHeaders(request.headers.get('Origin')) }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-api-routes/SKILL.md around lines 166 - 178, The CORS template is too permissive: update the cors handling in the OPTIONS and GET handlers to echo the incoming Origin header (instead of '*') and add a Vary: Origin header so caches handle per-origin responses; preserve allowed methods and headers (including Authorization) but ensure you read request.headers.get('Origin') and set 'Access-Control-Allow-Origin' to that value (or omit if absent), and include 'Vary': 'Origin' in the response headers; adjust corsHeaders usage or build headers per-request inside the OPTIONS and GET functions so the origin is scoped securely..agents/skills/native-data-fetching/references/expo-router-loaders.md (1)
201-215:⚠️ Potential issue | 🟠 MajorGate authentication before privileged fetch and avoid returning raw Stripe payload.
At Line 205, the Stripe balance call happens before auth is validated (Line 211), and Line 214 returns the full upstream object. This example should gate first and return a minimal safe shape.
🔐 Suggested docs patch
-import { type LoaderFunction } from 'expo-server'; +import { StatusError, type LoaderFunction } from 'expo-server'; export const loader: LoaderFunction<{ balance: any; isAuthenticated: boolean }> = async ( request, params ) => { + const sessionToken = request?.headers.get('cookie')?.match(/session=([^;]+)/)?.[1]; + if (!sessionToken) { + throw new StatusError(401, 'Unauthorized'); + } + const data = await fetch('https://api.stripe.com/v1/balance', { headers: { Authorization: `Bearer ${process.env.STRIPE_SECRET_KEY}`, }, }); - const sessionToken = request?.headers.get('cookie')?.match(/session=([^;]+)/)?.[1]; - const balance = await data.json(); - return { balance, isAuthenticated: !!sessionToken }; + return { + balance: { available: balance.available }, + isAuthenticated: true, + }; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/native-data-fetching/references/expo-router-loaders.md around lines 201 - 215, The loader currently calls fetch('https://api.stripe.com/v1/balance') before checking authentication and returns the raw Stripe payload in balance; change loader to first extract and validate sessionToken (request.headers.get + match) and immediately deny/short-circuit (isAuthenticated: false) if missing/invalid, only then perform the Stripe fetch when authenticated, and when building the return value map the Stripe response into a minimal safe shape (e.g., only numeric balances like available and pending or other specific fields needed) instead of returning the full balance object to avoid exposing upstream metadata/secrets..agents/skills/building-native-ui/references/controls.md (2)
165-170:⚠️ Potential issue | 🟠 Major
Stepperis not exported by React Native core.
import { Stepper } from 'react-native'will not compile. React Native does not provide a Stepper component. Use a third-party package such asreact-native-ios-kit,react-native-ui-stepper, orreact-native-simple-stepper.Suggested fix
-import { Stepper } from 'react-native'; +// React Native core does not provide Stepper. +// Use a third-party package. Example using react-native-ios-kit: +// npm install react-native-ios-kit +import { Stepper } from 'react-native-ios-kit'; import { useState } from 'react'; const [count, setCount] = useState(0); <Stepper value={count} onValueChange={setCount} minimumValue={0} maximumValue={10} />;,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/controls.md around lines 165 - 170, The file incorrectly imports Stepper from React Native core; replace the import of Stepper with a supported third‑party package (e.g., react-native-ios-kit, react-native-ui-stepper, or react-native-simple-stepper) and update the import statement to the chosen package, keeping the component usage (Stepper, value, onValueChange, minimumValue, maximumValue) and state hooks (useState, setCount) intact; ensure you install the package, import the correct exported component name from that package, and adjust any prop names if the chosen library uses different prop names than minimumValue/maximumValue.
56-63:⚠️ Potential issue | 🟠 Major
SegmentedControl.valuesuses unsupported object shape — must be string array.The
valuesprop for@react-native-segmented-control/segmented-controlaccepts onlystring[], not objects withlabelandiconproperties. This example will fail type-checking and at runtime.Suggested fix
<SegmentedControl - values={[ - { label: 'List', icon: 'list.bullet' }, - { label: 'Grid', icon: 'square.grid.2x2' }, - ]} + values={['List', 'Grid']} selectedIndex={index} onChange={({ nativeEvent }) => setIndex(nativeEvent.selectedSegmentIndex)} />,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/controls.md around lines 56 - 63, The example passes an array of objects to SegmentedControl.values which only accepts string[]; update the SegmentedControl usage (the values prop on the SegmentedControl component) to supply an array of strings (e.g., ['List','Grid']) instead of objects with label/icon, keep selectedIndex and onChange/setIndex as-is, and if icons are required move icon rendering to a custom component or use a different control that supports icons..agents/skills/building-native-ui/references/webgpu-three.md (1)
164-206:⚠️ Potential issue | 🟠 MajorAdd dependency array to
useEffectto prevent re-initialization on every render.The
useEffectinFiberCanvashas no dependency array, causing the WebGPU renderer to be repeatedly initialized on each render. This is incorrect and misleading for developers copying this sample code.Suggested fix
useEffect(() => { // ...existing initialization code... return () => { if (canvas != null) { unmountComponentAtNode(canvas!); } }; - }); + }, [children, scene, camera]);Note: If
children,scene, orcamerashouldn't trigger re-initialization, use[]for mount-only behavior and handle updates differently.,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/webgpu-three.md around lines 164 - 206, The useEffect in FiberCanvas is missing a dependency array, causing createRoot, makeWebGPURenderer and related initialization (canvasRef, root.current, renderer, and the onCreated hook) to run on every render; add an appropriate dependency array to the useEffect (e.g. [] for mount-only or [children, scene, camera] if those should trigger re-init) so the WebGPU renderer and root are only initialized when intended and avoid repeated re-initialization..agents/skills/building-native-ui/references/tabs.md (1)
397-397:⚠️ Potential issue | 🟠 MajorFix
ThemeProviderprop name: usevalue, nottheme.The
ThemeProvidercomponent from@react-navigation/nativeexpects thevalueprop, nottheme. The current examples will fail type-checking and at runtime.Suggested fix
// Line 397 - <ThemeProvider theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> + <ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> <Stack /> </ThemeProvider> // Line 412 - <ThemeProvider theme={DarkTheme}> + <ThemeProvider value={DarkTheme}> <Stack /> </ThemeProvider>,
Also applies to: 412-412
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/tabs.md at line 397, The ThemeProvider from `@react-navigation/native` is using the wrong prop name; replace the `theme` prop with `value` on the ThemeProvider instance so it receives the theme object (e.g., change ThemeProvider theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme} to use the `value` prop). Update both occurrences (the one referencing `colorScheme`, `DarkTheme`, and `DefaultTheme`) so type-checking and runtime behavior work with ThemeProvider..agents/skills/building-native-ui/references/form-sheet.md (1)
42-43:⚠️ Potential issue | 🟠 MajorRemove nested
<Stack.Header>from<Stack.Screen>layout examples.These snippets show an invalid Expo Router pattern in
_layout.tsx. Keep header config inoptionsfor layout-level screens, and use composition API in route component files instead.In Expo Router (SDK 55), can <Stack.Screen> in app/_layout.tsx render children like <Stack.Header>, or should it only be configured via name/options?🛠️ Proposed doc correction
<Stack.Screen name="about" options={{ presentation: 'formSheet', sheetAllowedDetents: [0.25], headerTransparent: true, contentStyle: { backgroundColor: 'transparent' }, sheetGrabberVisible: true, }} - > - <Stack.Header style={{ backgroundColor: 'transparent' }}></Stack.Header> - </Stack.Screen> + /><Stack.Screen name="confirm" options={{ contentStyle: { backgroundColor: 'transparent' }, presentation: 'formSheet', title: '', sheetGrabberVisible: true, sheetAllowedDetents: [0.25], headerTransparent: true, }} - > - <Stack.Header style={{ backgroundColor: 'transparent' }}> - <Stack.Header.Right /> - </Stack.Header> - </Stack.Screen> + />Also applies to: 154-156
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/form-sheet.md around lines 42 - 43, The example incorrectly nests <Stack.Header> inside <Stack.Screen> in _layout.tsx; remove any nested <Stack.Header> from the <Stack.Screen> examples and instead configure headers via the <Stack.Screen options={...}> prop for layout-level screens, and demonstrate using the composition API (i.e., placing <Stack.Header /> inside individual route component files) to customize per-route headers; update snippets referencing Stack.Screen and Stack.Header accordingly.frontend/app/(tabs)/index.tsx (1)
82-94:⚠️ Potential issue | 🟠 MajorKeep the initial page reactive instead of deduping it
Using
'initial'inprocessedCursorsRefblocks latercursor === nullupdates, which can freeze first-page results after the first fetch.🔧 Suggested fix
useEffect(() => { if (listingsResult && queryFilterVersion === filterVersionRef.current) { - const cursorId = cursor || 'initial'; - if (!processedCursorsRef.current.has(cursorId)) { - if (cursor === null) { - setAllListings(listingsResult.page); - } else { - setAllListings((prev) => [...prev, ...listingsResult.page]); - } - setIsDone(listingsResult.isDone); - setIsLoadingMore(false); - processedCursorsRef.current.add(cursorId); - } + if (cursor === null) { + setAllListings(listingsResult.page); + setIsDone(listingsResult.isDone); + setIsLoadingMore(false); + return; + } + + if (!processedCursorsRef.current.has(cursor)) { + setAllListings((prev) => [...prev, ...listingsResult.page]); + setIsDone(listingsResult.isDone); + setIsLoadingMore(false); + processedCursorsRef.current.add(cursor); + } } }, [listingsResult, cursor, queryFilterVersion]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/`(tabs)/index.tsx around lines 82 - 94, The code currently maps cursor === null to the string 'initial' and stores it in processedCursorsRef, which prevents subsequent first-page updates; change the logic so that null (the initial page) is never deduped: when cursor === null always treat it as a fresh load (call setAllListings to replace, update setIsDone/setIsLoadingMore) and do not add any 'initial' key to processedCursorsRef; only add actual non-null cursor values to processedCursorsRef to dedupe subsequent pages. Update the useEffect containing listingsResult, queryFilterVersion, filterVersionRef, cursor, processedCursorsRef, and setAllListings to implement this behavior.
🟡 Minor comments (14)
.agents/skills/native-data-fetching/SKILL.md-16-19 (1)
16-19:⚠️ Potential issue | 🟡 MinorAdd a language to this fenced code block.
This block is missing a language identifier, which triggers markdownlint MD040 and reduces editor rendering quality.
Suggested fix
-``` +```text references/ expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+)</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/native-data-fetching/SKILL.md around lines 16 - 19, The
fenced code block that contains the directory listing starting with
"references/" is missing a language identifier; update the opening
triple-backtick fence to include a language (e.g., changetotext) so the
block becomes "```text" to satisfy markdownlint MD040 and improve editor
rendering in SKILL.md.</details> </blockquote></details> <details> <summary>.agents/skills/native-data-fetching/SKILL.md-415-449 (1)</summary><blockquote> `415-449`: _⚠️ Potential issue_ | _🟡 Minor_ **Add a language to the decision-tree fenced block.** This code fence also lacks a language tag (MD040). Use `text` for plain decision-tree formatting. <details> <summary>Suggested fix</summary> ```diff -``` +```text User asks about networking |-- Route-level data loading (web, SDK 55+)? | \-- Expo Router loaders — see references/expo-router-loaders.md @@ |-- Deduplication -> React Query handles this \-- Cancellation -> AbortController or React Query ``` ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/native-data-fetching/SKILL.md around lines 415 - 449, The
fenced decision-tree block starting with "User asks about networking" is missing
a language tag; update the triple-backtick fence to include "text" (i.e.,.agents/skills/native-data-fetching/SKILL.md; ensure the opening fence is changed only to ```text and the closing fence remains ``` without altering the block content..agents/skills/native-data-fetching/SKILL.md-497-500 (1)
497-500:⚠️ Potential issue | 🟡 MinorFix env var prefix typo in examples.
EXPO*PUBLIC*is incorrect and can mislead readers; it should beEXPO_PUBLIC_.Suggested fix
-User: "How do I configure different API URLs for dev and prod?" --> Use EXPO*PUBLIC* env vars with .env.development and .env.production files +User: "How do I configure different API URLs for dev and prod?" +-> Use EXPO_PUBLIC_ env vars with .env.development and .env.production files User: "Where should I put my API key?" --> Client-safe keys: EXPO*PUBLIC* in .env. Secret keys: non-prefixed env vars in API routes only +-> Client-safe keys: EXPO_PUBLIC_ in .env. Secret keys: non-prefixed env vars in API routes only🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/native-data-fetching/SKILL.md around lines 497 - 500, Update the typoed env var prefix occurrences `EXPO*PUBLIC*` in the SKILL.md examples and explanatory text to the correct `EXPO_PUBLIC_` (e.g., in the "Use EXPO*PUBLIC* env vars with .env.development and .env.production files" line and the "Client-safe keys: EXPO*PUBLIC* in .env" sentence), ensuring all example env var names and guidance mention `EXPO_PUBLIC_` consistently..agents/skills/upgrading-expo/references/react-19.md-22-22 (1)
22-22:⚠️ Potential issue | 🟡 MinorFix comma splice.
The sentence contains a comma splice. Use a semicolon, conjunction, or split into two sentences for proper grammar.
✍️ Suggested grammar fix
-- `use` can be called conditionally, this simplifies components that consume multiple contexts. +- `use` can be called conditionally, which simplifies components that consume multiple contexts.Or alternatively:
-- `use` can be called conditionally, this simplifies components that consume multiple contexts. +- `use` can be called conditionally; this simplifies components that consume multiple contexts.As per static analysis hint: "To form a complete sentence, be sure to include a subject."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/references/react-19.md at line 22, The sentence "`use` can be called conditionally, this simplifies components that consume multiple contexts." contains a comma splice; update it to form a complete sentence by replacing the comma with a semicolon or splitting into two sentences (e.g., "`use` can be called conditionally; this simplifies components that consume multiple contexts." or "`use` can be called conditionally. This simplifies components that consume multiple contexts.") so the clause after the comma has its own subject and reads grammatically correct in react-19.md..agents/skills/upgrading-expo/references/react-19.md-3-3 (1)
3-3:⚠️ Potential issue | 🟡 MinorAlign SDK version with the actual upgrade target.
The documentation references "Expo SDK 54," but this PR upgrades to SDK 55. Consider updating to "Expo SDK 55" or using "Expo SDK 54+" to accurately reflect the version context.
📝 Suggested documentation fix
-React 19 is included in Expo SDK 54. This release simplifies several common patterns. +React 19 is included in Expo SDK 55. This release simplifies several common patterns.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/references/react-19.md at line 3, Update the documentation line that currently reads "React 19 is included in Expo SDK 54."—replace the "Expo SDK 54" reference with the correct upgrade target (e.g., "Expo SDK 55" or a range like "Expo SDK 54+") so the sentence ("React 19 is included in Expo SDK 54.") accurately reflects the PR's SDK upgrade..agents/skills/expo-cicd-workflows/scripts/validate.js-59-64 (1)
59-64:⚠️ Potential issue | 🟡 MinorReturn exit code 0 for explicit help requests.
At Line 63,
validate --helpexits with code 1 when no files are passed. Help should be a successful exit path.Proposed fix
- if (files.length === 0 || args.includes('--help') || args.includes('-h')) { + const wantsHelp = args.includes('--help') || args.includes('-h'); + if (files.length === 0 || wantsHelp) { console.log(`Usage: validate <workflow.yml> [workflow2.yml ...] @@ - process.exit(files.length === 0 ? 1 : 0); + process.exit(wantsHelp ? 0 : 1); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 59 - 64, The script currently treats a help request as an error when no files are passed; change the exit logic so explicit help requests return 0. In .agents/skills/expo-cicd-workflows/scripts/validate.js update the conditional around files/args (variables files and args in the shown block) so that if args.includes('--help') || args.includes('-h') the process.exit call uses 0 even when files.length === 0 (e.g., compute an exitCode = argsIncludesHelp ? 0 : (files.length === 0 ? 1 : 0) and call process.exit(exitCode) or split the branches so help always exits 0)..agents/skills/expo-tailwind-setup/SKILL.md-39-39 (1)
39-39:⚠️ Potential issue | 🟡 MinorMinor docs wording/casing cleanup.
Use
Lightning CSS(proper name/casing) for clarity in setup docs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-tailwind-setup/SKILL.md at line 39, The docs line currently says "lightningcss" in lowercase; update the wording in SKILL.md (the line that reads "autoprefixer is not needed in Expo because of lightningcss") to use the proper product casing "Lightning CSS" so it reads e.g. "autoprefixer is not needed in Expo because of Lightning CSS". Ensure only the casing/wording is changed and preserve the rest of the sentence..agents/skills/upgrading-expo/SKILL.md-111-113 (1)
111-113:⚠️ Potential issue | 🟡 MinorThe postcss.config.mjs requirement should be softened—it's recommended, not mandatory.
While
autoprefixerremoval in SDK 53+ is accurate (Expo's Metro handles vendor prefixing natively), the statement "Usepostcss.config.mjsin SDK +53" overstates the requirement. Bothpostcss.config.jsandpostcss.config.mjsare supported;.mjsis recommended primarily when using ESM syntax (export default), but.jswith CommonJS syntax is equally valid. Align guidance with your project's conventions rather than prescribing one format.Suggested doc fix
- `autoprefixer` isn't needed in SDK +53. Remove it from dependencies and check `postcss.config.js` or `postcss.config.mjs` to remove it from the plugins list. - Use `postcss.config.mjs` in SDK +53. + Remove `autoprefixer` from dependencies and plugins list in SDK +53 (Expo's Metro handles vendor prefixing natively). + Use `postcss.config.mjs` (ESM) or `postcss.config.js` (CommonJS) per your project conventions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/upgrading-expo/SKILL.md around lines 111 - 113, Update the guidance to soften the mandate about postcss config and clarify autoprefixer removal: state that removing `autoprefixer` is recommended for Expo SDK 53+ (since Metro handles vendor prefixes) and instruct to remove it from dependencies and from any `postcss.config.js` or `postcss.config.mjs` plugins list; change the sentence "Use `postcss.config.mjs` in SDK +53" to recommend `postcss.config.mjs` only when using ESM (`export default`) and otherwise allow `postcss.config.js` with CommonJS, advising to follow the project's existing convention rather than forcing one format..agents/skills/expo-deployment/SKILL.md-123-137 (1)
123-137:⚠️ Potential issue | 🟡 MinorFix broken reference paths (
reference→references).Lines 123-137 and Line 165 use
./reference/..., but the directory is./references/.... These links will break for readers.Suggested patch
-- See ./reference/testflight.md for credential setup -- See ./reference/ios-app-store.md for App Store submission +- See ./references/testflight.md for credential setup +- See ./references/ios-app-store.md for App Store submission @@ -- See ./reference/play-store.md for detailed setup +- See ./references/play-store.md for detailed setup @@ -- See ./reference/workflows.md for CI/CD automation +- See ./references/workflows.md for CI/CD automation @@ -See ./reference/workflows.md for more workflow examples. +See ./references/workflows.md for more workflow examples.Also applies to: 165-165
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/SKILL.md around lines 123 - 137, Update all broken link paths that use "./reference/..." to the correct "./references/..." in SKILL.md: search for occurrences of the string "./reference/" (notably the links under the iOS, Android, and Web sections and the occurrence at line 165) and replace them with "./references/"; ensure each referenced file name (e.g., testflight.md, ios-app-store.md, play-store.md, workflows.md) remains unchanged and links still resolve after the path fix..agents/skills/expo-deployment/references/play-store.md-77-82 (1)
77-82:⚠️ Potential issue | 🟡 MinorAlign track naming with Google Play Developer API terminology.
The table uses
internalas the track identifier for internal testing, but the official Google Play Developer API usesqafor this purpose. The Play Console UI labels this as "Internal testing", while the API track ID isqa. Update the table to useqainstead ofinternalfor clarity and accuracy, or add a note explaining that Expo's EAS abstracts this mapping. Additionally, clarify whetheralpharefers to a custom closed testing track or the predefinedalphaAPI track, as closed testing tracks can be custom-named in Play Console.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-deployment/references/play-store.md around lines 77 - 82, Update the Play Store track table to use the Google Play Developer API track ID `qa` instead of `internal` (or explicitly note that Expo/EAS maps Play Console "Internal testing" to API `qa`), and clarify the `alpha` row to state whether it refers to the predefined API `alpha` track or to custom-named closed testing tracks in Play Console; update the table entries and add a short parenthetical note after `qa` and `alpha` to make the mapping explicit (refer to the table rows for `internal`/`qa` and `alpha` in the README fragment)..agents/skills/expo-api-routes/SKILL.md-35-43 (1)
35-43:⚠️ Potential issue | 🟡 MinorAdd a language to the fenced code block to satisfy markdown linting.
At Line 35, specify the fence language (for example,
text) to avoid MD040 warnings.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/expo-api-routes/SKILL.md around lines 35 - 43, The fenced code block in SKILL.md is missing a language tag which triggers MD040; update the block fence that shows the app/api tree (the triple-backtick block around the listing) to include a language identifier such as text (e.g., ```text) so the markdown linter recognizes the block language and the warning is resolved..agents/skills/building-native-ui/references/zoom-transitions.md-155-155 (1)
155-155:⚠️ Potential issue | 🟡 MinorMinor wording fix: hyphenate “off-screen.”
At Line 155, use “off-screen” for the compound modifier.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/zoom-transitions.md at line 155, Update the sentence that currently reads "When source is unavailable (e.g., scrolled off screen), the transition zooms from the center of the screen" by hyphenating the compound modifier: change "scrolled off screen" to "scrolled off-screen" so it reads "When source is unavailable (e.g., scrolled off-screen), the transition zooms from the center of the screen.".agents/skills/building-native-ui/references/media.md-97-101 (1)
97-101:⚠️ Potential issue | 🟡 Minor
GlassButtoncomponent is used but not defined.The
GlassButtoncomponent is referenced here but not shown in this file. This will confuse readers trying to implement this camera UI. Either defineGlassButtonin this document or reference where it's defined (e.g., invisual-effects.md).Suggested addition before usage
// Define GlassButton helper function GlassButton({ onPress, icon }: { onPress: () => void; icon: string }) { return ( <GlassView isInteractive style={{ borderRadius: 50, padding: 12 }}> <TouchableOpacity onPress={onPress}> <SymbolView name={icon} tintColor="white" size={24} /> </TouchableOpacity> </GlassView> ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/media.md around lines 97 - 101, The document references the GlassButton component (used in the snippet with onPress={selectPhoto} and onPress={() => setType(...)} and icons "photo"/"arrow.triangle.2.circlepath") but never defines or links to it; either add a short local definition for GlassButton (e.g., a wrapper using GlassView and SymbolView with TouchableOpacity) above its usage or add a clear reference/link to the file where it’s implemented (for example visual-effects.md), so readers can find the GlassButton implementation and its props.frontend/components/PriceRangePicker.tsx-36-36 (1)
36-36:⚠️ Potential issue | 🟡 MinorEntrance animation doesn't replay when modal reopens.
The
useEntranceAnimationhook's effect only runs once (its dependencies[delay, opacity, translateY]are stable Ref objects). Since the Modal keeps children mounted while togglingvisible, the Animated.View retains its final animation state (opacity: 1, translateY: 0). When the modal reopens, the custom entrance animation won't replay.Add
visibleas a trigger dependency to reset animation values on reopen:Fix: Add visible as dependency
// In useEntranceAnimation export function useEntranceAnimation(delay = 0, distance = 16, visible?: boolean) { const opacity = useRef(new Animated.Value(0)).current; const translateY = useRef(new Animated.Value(distance)).current; useEffect(() => { opacity.setValue(0); translateY.setValue(distance); const animation = Animated.parallel([ Animated.timing(opacity, { toValue: 1, duration: 320, delay, easing: Easing.out(Easing.cubic), useNativeDriver: true, }), Animated.timing(translateY, { toValue: 0, duration: 320, delay, easing: Easing.out(Easing.cubic), useNativeDriver: true, }), ]); animation.start(); return () => animation.stop(); }, [delay, opacity, translateY, visible]); return useMemo(() => ({ opacity, transform: [{ translateY }] }), [opacity, translateY]); } // In PriceRangePicker const entranceStyle = useEntranceAnimation(40, 8, visible);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/PriceRangePicker.tsx` at line 36, The entrance animation never replaying is caused by useEntranceAnimation only depending on stable refs; modify useEntranceAnimation to accept a visible boolean (e.g., add parameter visible) and include that visible in the effect dependency array so the effect resets opacity and translateY (call .setValue(0) and .setValue(distance) or equivalent) and restarts the Animated.parallel when visible changes; then update the PriceRangePicker call to pass its visible prop into useEntranceAnimation (e.g., useEntranceAnimation(40, 8, visible)).
🧹 Nitpick comments (7)
skills-lock.json (1)
4-48: Consider automating hash integrity checks for this lock manifest.To prevent silent drift, add/keep a CI check that recomputes each skill hash from its source doc and fails on mismatch.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills-lock.json` around lines 4 - 48, The lockfile contains computedHash entries for skills (e.g., keys like "building-native-ui", "expo-api-routes", "expo-dev-client") but there is no automated check to detect drift; add a validation step by creating a script (e.g., validateSkillHashes or computeSkillHash) that fetches/parses each skill source doc, recomputes its hash and compares against the value in skills-lock.json, exiting non‑zero on any mismatch, and wire that script into CI as a job (e.g., .github/workflows/validate-skills.yml) so the pipeline fails when any skill hash differs..agents/skills/building-native-ui/references/route-structure.md (1)
18-24: Add language specifiers to directory structure code blocks.Multiple code blocks showing directory structures lack language specifiers. Use
textorplaintextfor consistency and to satisfy linting.Suggested fix for all occurrences
## Dynamic Routes Use square brackets for dynamic segments: -``` +```text app/ users/ [id].tsx # Matches /users/123, /users/abcApply similar changes to code blocks at lines 30, 69, 95, 112, and 155.
Also applies to: 30-34, 69-77, 95-106, 112-119, 155-169
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/route-structure.md around lines 18 - 24, Update the fenced code blocks that show directory structures (for example the block containing "app/ users/ [id].tsx # Matches /users/123, /users/abc" and the similar blocks later) to include a language specifier such as ```text or ```plaintext instead of bare ``` so linting passes; locate the directory-structure blocks in route-structure.md (the ones indicated in the review) and change their opening fences to ```text (apply the same change to the other occurrences noted in the comment)..agents/skills/building-native-ui/references/tabs.md (1)
305-309: Add language specifier to fenced code block.The code block at line 305 showing the file structure lacks a language specifier, which affects syntax highlighting and linting.
Suggested fix
-``` +```text app/ _layout.tsx # NativeTabs for iOS/Android _layout.web.tsx # Headless tabs for web (expo-router/ui)</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.agents/skills/building-native-ui/references/tabs.md around lines 305 - 309,
The fenced code block showing the app file structure is missing a language
specifier; update the block in tabs.md that contains the lines referencing
_layout.tsx and _layout.web.tsx to use a language tag (e.g., "text") for the
fenced code block so syntax highlighting and linters recognize it properly.</details> </blockquote></details> <details> <summary>.agents/skills/building-native-ui/references/webgpu-three.md (1)</summary><blockquote> `492-503`: **Add language specifiers to directory structure and decision tree code blocks.** Code blocks at lines 492 and 507 lack language specifiers. <details> <summary>Suggested fix</summary> ```diff ## File Structure -``` +```text src/ ├── app/ │ └── index.tsx # Entry point with lazy loading## Decision Tree -``` +```text Need 3D graphics? ├── Simple shapes → mesh + geometry + materialAlso applies to: 507-523
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/webgpu-three.md around lines 492 - 503, The two fenced code blocks (the directory tree beginning with "src/" and the decision tree beginning with "Need 3D graphics?") are missing language specifiers; update both fenced blocks to include an appropriate specifier (e.g., ```text or ```bash) so syntax highlighting and rendering are correct for the directory structure and decision-tree snippets in webgpu-three.md..agents/skills/building-native-ui/references/media.md (1)
1-11: Minor: Use hyphenated "full-screen" as a compound adjective.Line 5 uses "full screen camera" which should be "full-screen camera" when used as a compound adjective.
Suggested fix
-- Hide navigation headers when there's a full screen camera +- Hide navigation headers when there's a full-screen camera🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/references/media.md around lines 1 - 11, Update the compound adjective in the "## Camera" section by replacing "full screen camera" with the hyphenated form "full-screen camera" (i.e., edit the line that currently reads "Hide navigation headers when there's a full screen camera" to use "full-screen camera") so the phrase is grammatically correct as a modifier..agents/skills/building-native-ui/SKILL.md (1)
14-30: Add language specifiers to directory structure code blocks.Code blocks at lines 14 and 249 showing directory structures lack language specifiers.
Suggested fix
## References Consult these resources as needed: -``` +```text references/ animations.md Reanimated: entering, exiting, layout, scroll-driven, gesturesApply similarly to line 249.
Also applies to: 249-256
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/skills/building-native-ui/SKILL.md around lines 14 - 30, Update the two directory-structure fenced code blocks in SKILL.md (the block that begins with "references/" near the top and the similar block later in the file) to include a language specifier; change the opening triple backticks from ``` to ```text so the listings render as plain text (apply the same fix to both directory blocks, e.g., replace ``` with ```text for the block that starts with "references/" and the matching later block).frontend/components/FilterBar.tsx (1)
128-133: MountTagPickeronly when visible so entrance animation runs on open.Line 128 keeps
TagPickermounted continuously; with hook-driven entrance animation, the animation can complete before the modal is first shown.💡 Proposed fix
- <TagPicker - visible={tagPickerVisible} - selectedTags={selectedTags} - onSelectTags={onTagsChange} - onClose={() => setTagPickerVisible(false)} - /> + {tagPickerVisible && ( + <TagPicker + visible={tagPickerVisible} + selectedTags={selectedTags} + onSelectTags={onTagsChange} + onClose={() => setTagPickerVisible(false)} + /> + )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/components/FilterBar.tsx` around lines 128 - 133, TagPicker is always mounted which prevents its entrance animation from running on first open; change the render in FilterBar to conditionally mount TagPicker only when tagPickerVisible is true (e.g., render TagPicker when tagPickerVisible && ...) and keep the same props (selectedTags, onSelectTags={onTagsChange}, onClose={() => setTagPickerVisible(false)}) so it unmounts on close and its entrance animation will play when opened.
|
|
||
| const AnimatedExpoImage = Animated.createAnimatedComponent(RNImage); | ||
|
|
||
| export type ImageProps = React.ComponentProps<typeof Image>; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "SKILL.md" | head -20Repository: codebox-calpoly/PolyBuys
Length of output: 50
🏁 Script executed:
# First, let's find and read the SKILL.md file
find . -name "SKILL.md" -type fRepository: codebox-calpoly/PolyBuys
Length of output: 452
🏁 Script executed:
cat -n ".agents/skills/expo-tailwind-setup/SKILL.md" | sed -n '230,260p'Repository: codebox-calpoly/PolyBuys
Length of output: 1272
🌐 Web query:
TypeScript circular type reference self-referential type alias React.ComponentProps
💡 Result:
A “circular type reference” usually happens when you try to define a component’s props type in terms of the component itself, e.g.:
const Button = (props: ButtonProps) => {/*...*/}
type ButtonProps = React.ComponentProps<typeof Button>; // ❌ circularHere, typeof Button depends on ButtonProps (because it’s used in the function signature), and ButtonProps depends on typeof Button, so TypeScript reports a circular/self-referential type alias (TS2456). TypeScript only allows certain kinds of recursive aliases, and “alias through another alias” patterns are a common way to hit TS2456. [2][3][7]
Fixes
1) Define props first (recommended)
type ButtonProps = {
variant?: "primary" | "secondary";
};
const Button = (props: ButtonProps) => {/*...*/};2) If you’re trying to extend another component / intrinsic element, point ComponentProps at that, not at yourself
React.ComponentProps<T> is meant for extracting props from some other component or tag. [1]
type ButtonProps = { variant?: "primary" | "secondary" }
& React.ComponentPropsWithoutRef<"button">;
function Button(props: ButtonProps) {
return <button {...props} />;
}3) If you need “props of this component” elsewhere, export them directly
export type ButtonProps = { /*...*/ };
export function Button(props: ButtonProps) { /*...*/ }Rule of thumb: React.ComponentProps<typeof X> is great for reusing/extracting props from an existing X, but it can’t be used to “discover” a component’s own props from itself without creating a cycle. [1][7]
🏁 Script executed:
# Check if the file exists and get its location
find . -path "*expo-tailwind-setup/SKILL.md" -type fRepository: codebox-calpoly/PolyBuys
Length of output: 113
🏁 Script executed:
# Read the relevant section around line 244
sed -n '220,280p' ".agents/skills/expo-tailwind-setup/SKILL.md" | cat -nRepository: codebox-calpoly/PolyBuys
Length of output: 2422
Remove self-referential ImageProps type alias and extract props from the base component.
Line 244 references Image before it is declared, creating a forward reference issue. Since Image is defined later (line 43) with props based on CSSImage, the type alias creates an indirect circular dependency.
Fix
-export type ImageProps = React.ComponentProps<typeof Image>;
+export type ImageProps = React.ComponentProps<typeof AnimatedExpoImage> & { className?: string };
@@
-export const Image = (props: React.ComponentProps<typeof CSSImage> & { className?: string }) => {
+export const Image = (props: ImageProps) => {
return useCssElement(CSSImage, props, { className: 'style' });
};Define the type based on AnimatedExpoImage (which is already declared) instead of referencing the wrapper component itself.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/expo-tailwind-setup/SKILL.md at line 244, The ImageProps
alias currently references Image before it's declared causing a
forward-reference/circular type; replace its definition to extract props from
the already-declared AnimatedExpoImage instead of Image (i.e., make ImageProps =
React.ComponentProps<typeof AnimatedExpoImage>), ensuring compatibility with
CSSImage-based props and removing the self-referential dependency.
| await setAudioModeAsync({ | ||
| playsInSilentMode: true, | ||
| shouldPlayInBackground: true, | ||
| interruptionMode: 'doNotMix', | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n ".agents/skills/upgrading-expo/references/expo-av-to-audio.md"Repository: codebox-calpoly/PolyBuys
Length of output: 5421
🌐 Web query:
Expo SDK 55 expo-audio setAudioModeAsync recording iOS option documentation
💡 Result:
In Expo SDK 55 using expo-audio, the iOS “enable recording” flag for setAudioModeAsync is:
allowsRecording: boolean(iOS only) — “Whether the audio session allows recording” (defaultfalse). [1]
Example (from Expo docs):
import { setAudioModeAsync } from 'expo-audio';
await setAudioModeAsync({
allowsRecording: true,
playsInSilentMode: false,
});This differs from the older expo-av API/docs, which used:
allowsRecordingIOS: boolean[2]
Sources: Expo Audio (expo-audio) docs (v54 / latest) [1], older Expo AV Audio docs (v51) showing allowsRecordingIOS [2].
Add missing allowsRecording option to the "After" example for iOS recording support.
The "After" example at lines 105–109 is incomplete. The "Before" example includes allowsRecordingIOS: true, which maps to allowsRecording: true in Expo SDK 55's expo-audio. Without this option in the "After" example, iOS recording functionality will fail for developers following this migration guide.
Update the "After" example to include:
await setAudioModeAsync({
allowsRecording: true,
playsInSilentMode: true,
shouldPlayInBackground: true,
interruptionMode: 'doNotMix',
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/upgrading-expo/references/expo-av-to-audio.md around lines
105 - 109, The "After" example using setAudioModeAsync is missing the
allowsRecording option needed for iOS recording support; update the call to
setAudioModeAsync in the example to include allowsRecording: true alongside
playsInSilentMode, shouldPlayInBackground, and interruptionMode so it matches
the original Before behavior and enables iOS recording.
| - ./references/react-19.md -- SDK +54: React 19 changes (useContext → use, Context.Provider → Context, forwardRef removal) | ||
| - ./references/react-compiler.md -- SDK +54: React Compiler setup and migration guide |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
React 19 useContext removed replaced "use" hook official documentation
💡 Result:
useContext was not removed in React 19. It’s still part of the React API reference and works as before. [1]
React 19 introduced/expanded the use API so you can read context via use(ThemeContext). The official docs state that when a context is passed to use, it works similarly to useContext, but useContext must be called at the top level while use can be called inside conditionals/loops—and “use is preferred over useContext because it is more flexible.” [2]
Official docs:
useContext(SomeContext)reference: [1]use(resource)reference + “Reading context withuse”: [2]
Example (docs-equivalent):
import { use } from "react";
const theme = use(ThemeContext);🌐 Web query:
React 19 forwardRef removal deprecated official changelog
💡 Result:
React 19 did not remove forwardRef, but it made it unnecessary for function components by introducing “ref as a prop”.
- Official React 19 changelog / release post (Dec 5, 2024): “New function components will no longer need
forwardRef… In future versions we will deprecate and removeforwardRef.” (in the “refas a prop” section) [1] - Official
forwardRefreference page: MarksforwardRefas Deprecated, stating: “In React 19,forwardRefis no longer necessary. Passrefas a prop instead.forwardRefwill be deprecated in a future release.” [2]
Bottom line: in React 19, forwardRef is effectively obsolete for new function components, and React’s official docs say it’s slated for deprecation/removal in a future release—not removed in 19 itself. [1][2]
Sources: [1] [2]
Fix inaccurate React 19 API claims.
Lines 11–12 claim useContext → use and forwardRef removal, but both are incorrect. useContext remains valid in React 19; use() is a more flexible alternative for context consumption but does not replace it. forwardRef is deprecated but not removed—React 19 introduces ref as a prop as the preferred approach for new code.
Update the reference summary to reflect accurate guidance:
Suggested fix
- ./references/react-19.md -- SDK +54: React 19 changes (useContext → use, Context.Provider → Context, forwardRef removal)
+ ./references/react-19.md -- SDK +54: React 19 changes (use() for flexible context reading, ref as a prop for function components, Context.Provider changes)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/upgrading-expo/SKILL.md around lines 11 - 12, Update the
React 19 reference summary to correct the API claims: state that useContext
remains valid (do not replace it with use), describe use() as a more flexible
alternative for context consumption (optional for new patterns), clarify that
forwardRef is deprecated but not removed and that the new preferred pattern is
passing ref as a prop for new code, and adjust the Context.Provider → Context
phrasing to indicate the provider API still exists while Context usage patterns
are evolving; edit the summary lines referencing useContext, use, forwardRef,
and Context.Provider to reflect these accurate statements.
|
|
||
| - Review release notes for the target SDK version at https://expo.dev/changelog | ||
| - If using Expo SDK 54 or later, ensure react-native-worklets is installed — this is required for react-native-reanimated to work. | ||
| - Enable React Compiler in SDK 54+ by adding `"experiments": { "reactCompiler": true }` to app.json — it's stable and recommended |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .agents/skills/upgrading-expo/SKILL.md | sed -n '70,80p'Repository: codebox-calpoly/PolyBuys
Length of output: 846
🌐 Web query:
React Compiler Expo SDK 54 55 stability production recommended
💡 Result:
React Compiler is stable and production-ready as of React Compiler v1.0 (Oct 7, 2025)—the React team says it’s “fully production-ready” and has been battle-tested at Meta, and they explicitly partnered with Expo so new apps can start with it enabled. [1]
For Expo SDK 54:
- Expo’s SDK 54 changelog (Sep 10, 2025) says React Compiler is enabled in the default template and they recommend using it (logs may still say “Experimental … enabled” because it was RC at the time). [2]
- Expo’s React Compiler guide still documents enabling it via the
experiments.reactCompiler: trueflag and installingbabel-plugin-react-compiler@beta(last updated Nov 3, 2025), which is why it can feel “experimental” in Expo even though the compiler itself is now stable. [3]
For Expo SDK 55:
- SDK 55 ships React 19.2 and React Native 0.83, so it’s on the modern baseline where React Compiler is intended to work well. [4]
Production recommendation (SDK 54 / 55): Yes—generally recommended for production, but treat Expo’s integration as “opt-in / verify in your app” (since Expo still exposes it behind an experiments flag and uses @beta package tags in docs). Use the healthcheck and be ready to opt out specific files/components if you hit edge cases. [1][3]
Sources:
[1] React: React Compiler v1.0 (Oct 7, 2025)
[2] Expo: SDK 54 changelog (Sep 10, 2025)
[3] Expo Docs: React Compiler guide (updated Nov 3, 2025)
[4] Expo: SDK 55 changelog (Feb 2026)
🌐 Web query:
React Compiler compatibility caveats Expo known issues
💡 Result:
Expo + React Compiler: compatibility caveats / known issues
- SDK requirement & setup differences: Expo SDK 54+ has the React Compiler Babel integration wired into
babel-preset-expo; older SDKs require manual setup and (for some versions) addingreact-compiler-runtime. [1] - Expo’s compiler scope is limited by design: In Expo, the compiler only runs on your application code (not
node_modules) and only for client bundles (it’s disabled for server rendering). [1] - Class components aren’t optimized: React Compiler optimizes function components/hooks; Expo docs explicitly note class components won’t be optimized (migrate to function components for benefit). [1]
- Incompatible libraries/patterns can “freeze” UI with memoization: React’s linter flags certain libraries/APIs as incompatible with memoization, and React Compiler may need to skip affected components to avoid breaking behavior (or you may need to opt out with
"use no memo"). [2] - Babel plugin interactions can break builds: React warns that some Babel plugins can conflict with React Compiler; mitigation includes placing
babel-plugin-react-compilerearly in the plugin list and disabling conflicting optimizations. [3] - Expo SDK 54 known issue (strict mode crash): In Expo SDK 54, setting
compilationMode: "strict"has been reported to crash withUnexpected compilationMode "strict"(i.e., that option isn’t accepted in that setup). [4] - “Experimental/RC” status: Expo has described React Compiler support as experimental / release-candidate and notes the defaults may change depending on stability feedback. [5]
Sources: Expo React Compiler guide [1], React linter rule incompatible-library [2], React “Compiling Libraries” troubleshooting notes [3], Expo GitHub issue #39579 [4], Expo SDK 54 beta changelog [5].
Frame React Compiler enablement as conditional on app validation, not universal best practice.
React Compiler is production-ready (v1.0, Oct 2025) and Expo recommends it, but Expo's integration has documented compatibility requirements: certain libraries are incompatible with memoization, Babel plugin conflicts can break builds, class components aren't optimized, and SDK 54 has a known strict mode issue. Unconditionally recommending it without qualification could lead users to enable it in incompatible environments. The guidance should ask users to validate their toolchain and libraries first.
Suggested fix
-- Enable React Compiler in SDK 54+ by adding `"experiments": { "reactCompiler": true }` to app.json — it's stable and recommended
+- Consider enabling React Compiler in SDK 54+ via `"experiments": { "reactCompiler": true }` after validating library and tooling compatibility in your app.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Enable React Compiler in SDK 54+ by adding `"experiments": { "reactCompiler": true }` to app.json — it's stable and recommended | |
| - Consider enabling React Compiler in SDK 54+ via `"experiments": { "reactCompiler": true }` after validating library and tooling compatibility in your app. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/upgrading-expo/SKILL.md at line 74, Update the sentence that
unconditionally recommends enabling the React Compiler (the line that currently
instructs: add "experiments": { "reactCompiler": true } to app.json) to instead
advise conditional enablement: instruct users to validate their app/toolchain
and libraries first (checking for memoization-incompatible libs, Babel plugin
conflicts, class component behavior, and known SDK 54 strict-mode issues) and
only enable the React Compiler in app.json once compatibility is confirmed or
after testing in a staging build; reference the exact config key
"experiments.reactCompiler" and mention testing/rollback guidance so users know
how to safely try it.
| | Old Package | Replacement | | ||
| | -------------------- | ---------------------------------------------------- | | ||
| | `expo-av` | `expo-audio` and `expo-video` | | ||
| | `expo-permissions` | Individual package permission APIs | | ||
| | `@expo/vector-icons` | `expo-symbols` (for SF Symbols) | | ||
| | `AsyncStorage` | `expo-sqlite/localStorage/install` | | ||
| | `expo-app-loading` | `expo-splash-screen` | | ||
| | expo-linear-gradient | experimental_backgroundImage + CSS gradients in View | | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, confirm the file content at the specified lines
if [ -f ".agents/skills/upgrading-expo/SKILL.md" ]; then
sed -n '82,90p' ".agents/skills/upgrading-expo/SKILL.md"
else
find . -name "SKILL.md" -path "*upgrading-expo*" -type f
fiRepository: codebox-calpoly/PolyBuys
Length of output: 708
🌐 Web query:
Expo vector-icons @expo/vector-icons current status 2025 deprecation
💡 Result:
@expo/vector-icons was not deprecated in 2025 and is still a supported, documented Expo library as of March 2, 2026—it’s installed by default in create-expo-app templates and described as part of the Expo ecosystem. [1]
What did happen around the 2024–2025 timeframe is maintenance/behavior changes, not deprecation:
- In Expo SDK 50 (Jan 18, 2024),
@expo/vector-iconswas updated to usereact-native-vector-icons@10.0.0, which introduced some icon-name changes (notably Ionicons droppingios-/md-prefixes). [2] - Also in SDK 50, Expo changed how
react-native-vector-iconsis aliased to@expo/vector-icons(moving it from the Babel preset to the Metro resolver), which affected some setups—especially web/storybook configurations. [2]
Current version signals:
- Expo’s Icon Explorer currently references
@expo/vector-icons@14.0.4. [3] - Package deprecation trackers report no deprecated versions of
@expo/vector-icons(and show recent published versions in 2024). [4]
Sources:
[1] Expo docs: “Expo Vector Icons” guide (last updated Feb 17, 2026) (docs.expo.dev)
[2] Expo SDK 50 changelog (vector-icons + resolver/aliasing notes) (expo.dev)
[3] Expo Icon Explorer showing @expo/vector-icons@14.0.4 (icons.expo.app)
[4] Deprecation/version tracker showing “No deprecated versions” (xeol.io)
Citations:
- 1: https://docs.expo.dev/guides/icons
- 2: https://expo.dev/changelog/2024-01-18-sdk-50?utm_source=openai
- 3: https://icons.expo.app/
- 4: https://www.xeol.io/explorer/package/npm/%40expo%2Fvector-icons
🌐 Web query:
expo-linear-gradient deprecation status 2025 Expo SDK
💡 Result:
expo-linear-gradient is not deprecated in Expo SDK “latest” docs (as of the current Expo documentation), and Expo still documents installing and using it as the supported LinearGradient component (bundled version shown in docs: ~15.0.8). [1]
What was deprecated/removed (years earlier) was the old global access pattern (for example global.expo.LinearGradient) that used to come from the main expo package; since SDK 41 you’re expected to install/import the package directly: import { LinearGradient } from 'expo-linear-gradient';. [2]
There is a July 13, 2025 open docs issue suggesting the docs could also mention newer React Native alternatives (like experimental_backgroundImage)—but that issue is not a deprecation notice for expo-linear-gradient. [3]
Sources: [1] [2] [3]
🌐 Web query:
AsyncStorage recommended package Expo SDK 2025 @react-native-async-storage``
💡 Result:
For Expo SDK (including 2025-era SDKs), the recommended AsyncStorage library is:
- Package:
@react-native-async-storage/async-storage(docs.expo.dev) - Install (recommended in Expo):
npx expo install@react-native-async-storage/async-storage`` (this pins a version compatible with your Expo SDK) (docs.expo.dev)
Expo’s SDK docs list it as the supported AsyncStorage solution (with a “bundled version” shown on the page; e.g., it listed 2.1.2 and was last updated April 16, 2025). (docs.expo.dev)
Citations:
- 1: https://docs.expo.dev/versions/latest/sdk/async-storage?utm_source=openai
- 2: https://docs.expo.dev/versions/latest/sdk/async-storage?utm_source=openai
- 3: https://docs.expo.dev/versions/latest/sdk/async-storage?utm_source=openai
Three deprecated package mappings (lines 86–90) are incorrect and could mislead migrations.
@expo/vector-iconsis not deprecated; it's still actively maintained and bundled increate-expo-app.expo-symbolsis an iOS-specific SF Symbols option, not a general replacement.expo-linear-gradientis not deprecated; it remains the documented package for gradients in Expo.AsyncStoragemapping is wrong; the correct package is@react-native-async-storage/async-storage, notexpo-sqlite/localStorage/install.
Update these three rows to reflect current Expo SDK guidance:
Suggested fix
-| `@expo/vector-icons` | `expo-symbols` (for SF Symbols) |
-| `AsyncStorage` | `expo-sqlite/localStorage/install` |
-| expo-linear-gradient | experimental_backgroundImage + CSS gradients in View |
+| `@expo/vector-icons` | Keep; use `expo-symbols` only for iOS SF Symbols |
+| `AsyncStorage` | `@react-native-async-storage/async-storage` |
+| `expo-linear-gradient` | Keep; still the official Expo gradient package |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.agents/skills/upgrading-expo/SKILL.md around lines 82 - 90, Update the
three incorrect mappings in the table: replace the `@expo/vector-icons` ->
`expo-symbols` row to indicate `@expo/vector-icons` is still maintained and
bundled (remove `expo-symbols` as a general replacement; note `expo-symbols` is
iOS-only), change the `expo-linear-gradient` row to keep `expo-linear-gradient`
as the recommended package instead of marking it deprecated, and correct the
`AsyncStorage` mapping to point to `@react-native-async-storage/async-storage`
(remove `expo-sqlite/localStorage/install`). Locate and edit the table entries
referencing `@expo/vector-icons`, `expo-symbols`, `expo-linear-gradient`,
`AsyncStorage`, and `@react-native-async-storage/async-storage`.
- Integrated useLocalSearchParams to retrieve returnTo parameter for post-auth redirection. - Updated router.replace to redirect users to the specified return path after successful login, improving user experience.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/app/auth/login.tsx`:
- Around line 183-187: The success banner currently shows whenever
successMessage is set, causing stale "code sent" text after navigating back to
the email-entry UI; update the conditional render around successMessage so it
also checks the current flow step and only displays when the component is in the
verification step (e.g., only render when step/currentStep/authStep === 'verify'
or similar), and apply the same conditional to the other successMessage render
block at lines ~205-217; locate the successMessage render blocks to add the step
check (referencing successMessage and your step state variable) so the banner is
restricted to the verification step.
- Introduced a new state variable to manage the verification step in the login process. - Updated the rendering logic to display success messages conditionally based on the verification step, improving user feedback during authentication.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/app/auth/login.tsx (2)
65-67:⚠️ Potential issue | 🟡 MinorEnforce numeric OTP input in client validation.
Current check validates only length, so non-digit 8-char values pass client-side despite the “8-digit code” requirement.
💡 Suggested fix
- if (!code.trim() || code.trim().length !== 8) { + if (!/^\d{8}$/.test(code.trim())) { setError('Please enter the 8-digit code'); return; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 65 - 67, The client-side validation currently only checks length, allowing non-numeric 8-char values; update the validation around the "code" variable (the same block that calls setError('Please enter the 8-digit code')) to require exactly eight digits (e.g. test with a regex like /^\d{8}$/) and call setError if the test fails so only numeric 8-digit OTPs pass; keep the existing error message and return early as before.
108-112:⚠️ Potential issue | 🟡 MinorClear
successMessagewhen leaving verification step.
handleBackdoes not resetsuccessMessage, so a previous “code resent” banner can reappear when the user re-enters verification with a different email.💡 Suggested fix
const handleBack = () => { setStep('email'); setCode(''); setError(null); + setSuccessMessage(null); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/app/auth/login.tsx` around lines 108 - 112, The handleBack function currently resets step, code, and error but leaves successMessage intact, causing prior "code resent" banners to reappear; update handleBack (in frontend/app/auth/login.tsx) to also clear the successMessage state by calling the success message setter (e.g., setSuccessMessage('') or setSuccessMessage(null) consistent with its type) alongside setStep('email'), setCode(''), and setError(null).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@frontend/app/auth/login.tsx`:
- Around line 65-67: The client-side validation currently only checks length,
allowing non-numeric 8-char values; update the validation around the "code"
variable (the same block that calls setError('Please enter the 8-digit code'))
to require exactly eight digits (e.g. test with a regex like /^\d{8}$/) and call
setError if the test fails so only numeric 8-digit OTPs pass; keep the existing
error message and return early as before.
- Around line 108-112: The handleBack function currently resets step, code, and
error but leaves successMessage intact, causing prior "code resent" banners to
reappear; update handleBack (in frontend/app/auth/login.tsx) to also clear the
successMessage state by calling the success message setter (e.g.,
setSuccessMessage('') or setSuccessMessage(null) consistent with its type)
alongside setStep('email'), setCode(''), and setError(null).
- Added expo-router version 55.0.3 to package.json and package-lock.json for improved routing capabilities. - Updated TypeScript configuration in tsconfig.json to include additional file types and improve module resolution.
- Updated the updateListing action to return specific moderation error responses instead of throwing exceptions. - Added a new query to retrieve the current user's listings, including hidden and inactive items. - Introduced a new query to fetch the current authenticated user's full profile, including non-public fields. - Enhanced profile creation and update mutations to include additional fields and validation for email, year, and other profile attributes. - Improved error handling in listing creation and editing to provide user-friendly feedback for moderation issues. - Updated frontend components to reflect new profile and listing functionalities, including loading states and input validations.
- Updated the test case for createProfile to clarify rejection conditions when no email is provided or available on identity. - Enhanced error message to be more user-friendly, specifying that an email is required to create a profile.
Summary
I upgraded Expo to SDK 55, added tabs at the bottom of the app using the Expo native tabs layout, which includes rendering liquid glass on iOS. Adopted the tabs to be in the header of the web app and did an overall UI/animation polish. We can definitely change the UI however we want in the future. I just cleaned some things up that weren't working and added some animations for fun.
How to Test
Steps to verify locally:
npm run lintnpm run typechecknpm testnpm run dev:backend(in terminal A)npm run dev(in terminal B)Checklist
npm run lint)devScreenshots / Demos
Summary by CodeRabbit
New Features
UI/UX Updates
Platform & Build
Documentation