Skip to content

feat: search location ui flow#244

Merged
anish-sahoo merged 8 commits intomainfrom
feat/search-location-flow
Apr 4, 2026
Merged

feat: search location ui flow#244
anish-sahoo merged 8 commits intomainfrom
feat/search-location-flow

Conversation

@anish-sahoo
Copy link
Copy Markdown
Member

@anish-sahoo anish-sahoo commented Apr 1, 2026

Description

  • Add page/components/etc. for searching and selecting locations. this includes map view and typeahead view
  • MIGRATE FROM EXPO GO TO EXPO. This will require all devs to setup the new image (install cocoapods on macos)

How has this been tested?

Checklist

  • I have self-reviewed my code for readability, maintainability, performance, and added comments/documentation where necessary.
  • New and existing tests pass locally with my changes.
  • I have followed the project's coding standards and best practices.

User-visible changes

  • New location search modal with debounced typeahead autocomplete and selectable place predictions
  • Interactive MapLibre map preview showing selected location with pin and fly-to animation
  • "Search Location" action added to trip details that opens the search flow as a modal with swipe/back gestures
  • Expo migration notes: MapLibre plugin added and iOS run instruction updated (requires CocoaPods and new image setup)

Changes by category

Features

  • Search-location screen: debounced typeahead, predictions list, place-details fetching, and map preview (new UI flow)
  • Map view integration using MapLibre with pinned marker and camera animation
  • "Search Location" button in trip view that navigates to the search-location modal
  • New route registration for search-location in trips layout (modal presentation with gestures)

Infra

  • Added @maplibre/maplibre-react-native dependency (v^10.4.2)
  • Added MapLibre plugin to frontend/app.json
  • Updated recommended iOS command from expo start --ios to expo run:ios (requires CocoaPods and new Expo image)

Improvements

  • Activity detail: added dummy activity support and conditional query gating to avoid unnecessary fetches

Author contribution

File Added Removed
frontend/app/(app)/trips/[id]/search-location.tsx 357 0
frontend/app/(app)/trips/[id]/activities/[id]/index.tsx 23 2
frontend/app/(app)/trips/[id]/_layout.tsx 8 0
frontend/app/(app)/trips/[id]/index.tsx 6 0
frontend/package.json 1 0
frontend/app.json 2 1
Total 397 3

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f778fc1b-0fbe-4e30-b878-842c8f254ab5

📥 Commits

Reviewing files that changed from the base of the PR and between 9208b4f and 0e23aab.

📒 Files selected for processing (2)
  • frontend/app.json
  • frontend/package.json

📝 Walkthrough

Walkthrough

Adds MapLibre dependency and Expo plugin, a modal "search-location" route and button, a new SearchLocationScreen with debounced typeahead and MapLibre preview, and a dummy-activity fallback for activity detail loading.

Changes

Cohort / File(s) Summary
MapLibre & Expo config
frontend/app.json, frontend/package.json
Registered @maplibre/maplibre-react-native in expo.plugins and added it to dependencies (^10.4.2). Minor formatting adjustment in app.json plugins array.
Route layout
frontend/app/(app)/trips/[id]/_layout.tsx
Added Stack.Screen route name="search-location" with options { headerShown: false, presentation: "modal", gestureEnabled: true }.
Search location feature
frontend/app/(app)/trips/[id]/search-location.tsx
Added new default-export screen implementing debounced typeahead, predictions list, place-details fetch, selected-location state, and MapLibre map preview with marker and camera fly-to.
Trip view UI
frontend/app/(app)/trips/[id]/index.tsx
Added a "Search Location" text-primary Button that navigates to /trips/${tripID}/search-location.
Activity detail handling
frontend/app/(app)/trips/[id]/activities/[id]/index.tsx
Introduced DUMMY_ACTIVITY and DUMMY_ID; disabled useGetActivity query when dummy ID is used and select dummy data as fallback.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Router
    participant SearchLocationScreen
    participant SearchPlacesAPI
    participant PlaceDetailsAPI
    participant MapLibre as MapLibre(Map)

    User->>Router: Open /trips/:id/search-location (modal)
    Router->>SearchLocationScreen: Render screen
    User->>SearchLocationScreen: Type query
    SearchLocationScreen->>SearchLocationScreen: Debounce (300ms)
    SearchLocationScreen->>SearchPlacesAPI: searchPlacesTypeahead(query)
    SearchPlacesAPI-->>SearchLocationScreen: predictions[]
    SearchLocationScreen->>User: Show predictions list

    User->>SearchLocationScreen: Select prediction
    SearchLocationScreen->>SearchLocationScreen: set isSelecting, clear predictions
    SearchLocationScreen->>PlaceDetailsAPI: getPlaceDetailsCustom(place_id)
    PlaceDetailsAPI-->>SearchLocationScreen: place geometry & details
    SearchLocationScreen->>MapLibre: Render map, flyTo(location), add marker
    MapLibre-->>User: Display map preview with marker
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A query typed, the list appears,
A tap selects, the details near.
The map will fly, the marker stay,
A place is picked, then saved away.
New routes and maps join the way.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changeset: a new UI flow for searching and selecting locations with typeahead and map preview.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/search-location-flow

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@anish-sahoo anish-sahoo changed the title feat: Search Location UI Flow feat: search location ui flow Apr 1, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/app/(app)/trips/[id]/activities/[id]/index.tsx (2)

59-73: ⚠️ Potential issue | 🟡 Minor

Use dedicated LoadingState and ErrorState components.

The inline loading and error handling with plain Text components does not follow the guideline requiring LoadingState, ErrorState, or EmptyState UI components. Replacing these with proper state components ensures consistent UX across the app and centralizes styling.

Suggested approach
-        {isLoading && (
-          <Box padding="lg">
-            <Text variant="bodyDefault" color="textSubtle">
-              Loading...
-            </Text>
-          </Box>
-        )}
-
-        {isError && (
-          <Box padding="lg">
-            <Text variant="bodyDefault" color="textSubtle">
-              Failed to load activity.
-            </Text>
-          </Box>
-        )}
+        {isLoading && <LoadingState />}
+        {isError && <ErrorState message="Failed to load activity." />}

Import LoadingState and ErrorState from the design system if available.

As per coding guidelines: "React/Expo UI error handling must not expose raw API errors; use UI states (LoadingState, ErrorState, EmptyState)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/`(app)/trips/[id]/activities/[id]/index.tsx around lines 59 -
73, Replace the inline loading/error JSX that uses Box and Text guarded by
isLoading/isError with the designated UI state components: return or render
<LoadingState /> when isLoading is true and <ErrorState /> when isError is true
(instead of the manual Text message). Add imports for LoadingState and
ErrorState at the top of the file, remove the inline messages inside the
isLoading/isError blocks, and ensure you do not surface raw API errors (keep
ErrorState generic). Update any surrounding markup so the new components match
existing layout where the previous Box wrapper was used.

110-114: 🧹 Nitpick | 🔵 Trivial

Avoid hardcoded pixel values for image dimensions.

The image style uses magic numbers (width: 120, height: 120). Extract these to the design system tokens or define named constants to maintain consistency and ease future adjustments.

As per coding guidelines: "avoid hard-coded color values, magic spacing numbers, and duplicated style definitions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/`(app)/trips/[id]/activities/[id]/index.tsx around lines 110 -
114, The inline style block uses hardcoded pixels (width: 120, height: 120);
replace these magic numbers with a named constant or design token (e.g., const
ACTIVITY_IMAGE_SIZE = 120 or import a token like tokens.size.activityImage) and
use that constant in the style object (alongside CornerRadius.sm) so dimensions
are centralized and reusable; update any other occurrences to use the same
constant and export it if needed from the design tokens or the component module.
🤖 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/`(app)/trips/[id]/search-location.tsx:
- Around line 71-79: The fetchPredictions function currently swallows errors
from searchPlacesTypeahead; update it to catch errors,
setIsLoadingPredictions(false) in finally (keep), and surface a user-friendly
error to the UI (e.g., call a toast/notification or set an error state) so users
know the search failed; specifically wrap the await searchPlacesTypeahead(q,
TYPEAHEAD_LIMIT) in try/catch inside fetchPredictions, call setPredictions([])
or leave previous predictions as appropriate on error, and invoke your app's
notification helper (or set a local error state used by the component) with a
clear message; keep the finally block that calls setIsLoadingPredictions(false)
unchanged.
- Around line 81-94: The handler handleSelectPrediction currently sets
isSelectingPlace true but never resets it if getPlaceDetailsCustom throws,
leaving the component stuck; modify handleSelectPrediction to ensure
setIsSelectingPlace(false) is called in the finally block alongside
setIsLoadingDetails(false) (or in both catch and finally) so isSelectingPlace is
always reset after the request completes or fails, and keep setting
setSelectedLocation(res.data) only on success; reference handleSelectPrediction,
getPlaceDetailsCustom, isSelectingPlace, setIsSelectingPlace,
setIsLoadingDetails, and setSelectedLocation when making this change.

---

Outside diff comments:
In `@frontend/app/`(app)/trips/[id]/activities/[id]/index.tsx:
- Around line 59-73: Replace the inline loading/error JSX that uses Box and Text
guarded by isLoading/isError with the designated UI state components: return or
render <LoadingState /> when isLoading is true and <ErrorState /> when isError
is true (instead of the manual Text message). Add imports for LoadingState and
ErrorState at the top of the file, remove the inline messages inside the
isLoading/isError blocks, and ensure you do not surface raw API errors (keep
ErrorState generic). Update any surrounding markup so the new components match
existing layout where the previous Box wrapper was used.
- Around line 110-114: The inline style block uses hardcoded pixels (width: 120,
height: 120); replace these magic numbers with a named constant or design token
(e.g., const ACTIVITY_IMAGE_SIZE = 120 or import a token like
tokens.size.activityImage) and use that constant in the style object (alongside
CornerRadius.sm) so dimensions are centralized and reusable; update any other
occurrences to use the same constant and export it if needed from the design
tokens or the component module.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b12aea7b-b1c9-4f08-851e-de2d67502559

📥 Commits

Reviewing files that changed from the base of the PR and between e0ed34a and 5c74554.

⛔ Files ignored due to path filters (1)
  • frontend/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • backend/internal/controllers/comment_reactions.go
  • backend/internal/models/comment_reactions.go
  • backend/internal/repository/comment_reactions.go
  • backend/internal/services/comment_reactions.go
  • backend/internal/tests/activity_test.go
  • backend/internal/tests/comment_reactions_test.go
  • backend/internal/validators/time_of_day.go
  • frontend/app.json
  • frontend/app/(app)/trips/[id]/_layout.tsx
  • frontend/app/(app)/trips/[id]/activities/[id]/index.tsx
  • frontend/app/(app)/trips/[id]/index.tsx
  • frontend/app/(app)/trips/[id]/search-location.tsx
  • frontend/package.json
💤 Files with no reviewable changes (5)
  • backend/internal/controllers/comment_reactions.go
  • backend/internal/services/comment_reactions.go
  • backend/internal/validators/time_of_day.go
  • backend/internal/repository/comment_reactions.go
  • backend/internal/tests/comment_reactions_test.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 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/`(app)/trips/[id]/search-location.tsx:
- Around line 320-340: The pin, pinDot and predictionItem styles currently use
hard-coded magic numbers (width: 24, height: 24, borderRadius: 12, pinDot
width/height 6 borderRadius 3, and predictionItem minHeight: 48); replace these
literals with design-system tokens (e.g., Spacing.SM/MD, Radius.SM/MD, Size.SM,
etc.) and/or centralized constants so sizes are consistent and not duplicated,
updating the style objects named pin, pinDot and predictionItem to reference
those tokens (keep ColorPalette usage as-is) and remove duplicated numeric
values across the file.
- Around line 91-94: The catch block in the getPlaceDetailsCustom call currently
only logs the error and resets setIsSelectingPlace, leaving the user without any
feedback; update the error handling in the catch to surface a user-friendly
message (e.g., call the app's toast helper or set a local error state like
setPlaceError) with a clear, non-technical message such as "Unable to load place
details. Please try again." and ensure the UI for this component (where place
results are rendered) reads that state or the toast so the user sees the error;
reference the getPlaceDetailsCustom call, the existing catch block, and
setIsSelectingPlace when making the change.
- Around line 51-98: SearchLocationScreen currently lets users pick a place
(handleSelectPrediction sets selectedLocation) but never returns it to the
parent; add a confirmation action (e.g., a Confirm/Done button shown when
selectedLocation is set and map view is active) that calls router.setParams({
selectedLocation: <serializedLocation> }) or navigates back with the location in
route params, then clears isSelectingPlace and selectedLocation as needed;
update the UI render to show the button when selectedLocation !== null and wire
its onPress to serialize the LocationDetails and pass it via router.setParams or
router.push to the trip details route so the parent receives the selection.
- Around line 87-90: The code assigns an untyped API response from
getPlaceDetailsCustom to selectedLocation (typed LocationDetails) via
setSelectedLocation, which risks runtime failures in LocationMapView when fields
change; update the API layer to return a typed response (e.g.,
request<LocationDetails>) or perform runtime validation before calling
setSelectedLocation—use a schema validator (zod/io-ts) or explicit checks for
geometry.location.lng/lat and required fields, then map/normalize the validated
payload to the LocationDetails shape before setting state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 840d68bc-3600-49c7-aa30-f8a46041cbea

📥 Commits

Reviewing files that changed from the base of the PR and between 5c74554 and 422dfef.

📒 Files selected for processing (1)
  • frontend/app/(app)/trips/[id]/search-location.tsx

@in-mai-space in-mai-space linked an issue Apr 2, 2026 that may be closed by this pull request
@anish-sahoo anish-sahoo merged commit c2cdc87 into main Apr 4, 2026
8 of 9 checks passed
@anish-sahoo anish-sahoo deleted the feat/search-location-flow branch April 4, 2026 15:35
This was referenced Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FE]: Search for Location

2 participants