Skip to content

feat(mobile): connect orders and reservations flow to backend#220

Merged
masch merged 7 commits into
mainfrom
issue-211/connect-mobile-orders-api
May 25, 2026
Merged

feat(mobile): connect orders and reservations flow to backend#220
masch merged 7 commits into
mainfrom
issue-211/connect-mobile-orders-api

Conversation

@masch

@masch masch commented May 24, 2026

Copy link
Copy Markdown
Owner

Pull Request Template

Linked Issue

Closes #211

Summary

  • Connects the mobile client to the new backend endpoints (/v1/orders and /v1/reservations) with type-safe operations.
  • Implements a 2-step booking flow with automated rollback (cancels reservation if order creation fails) in REST mode.
  • Refactors REST services (RestOrderService and RestProductService) to use the new apiClient helper injecting the auth token.
  • Cleans up and archives the SDD planning artifacts for both connect-mobile-orders-api and orders-endpoints-booking-flow sessions.

Changes

File Change
apps/mobile/src/services/api-client.ts Created API client with token injection & base URL prefix
apps/mobile/src/services/order.service.ts Refactored RestOrderService to use client & support Zod DTOs
apps/mobile/src/services/product.service.ts Refactored RestProductService & threw errors in REST placeOrder
apps/mobile/src/app/tourist/booking.tsx Implemented 2-step booking flow + reservation rollback
openspec/changes/archive/ Archived both SDD changes and added archive-report.md

Test Summary

✅ PASS: 532 total tests, make check successful

Contributor Checklist

  • Linked an approved issue
  • Added exactly one type:* label
  • Ran make check and tests pass
  • Conventional commit format
  • No Co-Authored-By trailers

@masch masch added the type:feature New feature label May 24, 2026
@masch
masch temporarily deployed to development May 24, 2026 18:54 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented May 24, 2026

Copy link
Copy Markdown

React Doctor

Score: 87 / 100

react-doctor v0.2.4

✔ Select projects to scan › impenetrable-mobile
Scanning changes: issue-211/connect-mobile-orders-api → main

Scanning /home/runner/work/impenetrable-connect/impenetrable-connect/apps/mobile...



  ⚠ react-doctor/no-giant-component                ×3
      Component "ProjectFormScreen" is 365 lines — consider breaking it into smaller focused components
      → Extract logical sections into focused components: `<UserHeader />`, `<UserActions />`, etc.
      src/app/admin/project/[id].tsx:55
      src/app/tourist/booking.tsx:41
      src/app/tourist/index.tsx:29

  ⚠ react-doctor/prefer-useReducer                 ×2
      Component "BookingScreen" has 7 useState calls — consider useReducer for related state
      → Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`
      src/app/tourist/booking.tsx:41
      src/app/tourist/index.tsx:29

  ⚠ react-doctor/jsx-no-jsx-as-prop
      JSX prop receives JSX created on every render — extract it or memoize to avoid re-renders.
      → Hoist the inner JSX outside the render or memoize via `useMemo`.
      src/app/tourist/booking.tsx:342

  ⚠ react-doctor/rn-no-scrollview-mapped-list
      <ScrollView> rendering items.map(...) — use FlashList, LegendList, or FlatList so only visible rows mount
      → Use FlashList, LegendList, or FlatList — `<ScrollView>{items.map(...)}</ScrollView>` mounts every row in memory
      src/app/tourist/booking.tsx:453

  ⚠ react-doctor/rendering-hydration-mismatch-time
      new Date() reachable from JSX renders differently on server vs client — wrap in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
      → Wrap dynamic time/random values in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
      src/app/tourist/index.tsx:422

  ⚠ react-doctor/no-generic-handler-names
      Non-descriptive handler name "handleChange" — name should describe what it does, not when it runs
      → Rename to describe the action: e.g. `handleSubmit` → `saveUserProfile`, `handleClick` → `toggleSidebar`
      src/components/DatePicker.tsx:283

  ┌─────┐  96 / 100 Great
  │ ◠ ◠ │  ████████████████████████████████████████████████░░
  │  ▽  │  React Doctor (www.react.doctor)
  └─────┘

  9 issues across 4/23 files  in 1.4s
  Full diagnostics written to /tmp/react-doctor-ba92251e-63e9-4330-a10c-655ff5cac3f6

@masch
masch temporarily deployed to development May 24, 2026 20:59 — with GitHub Actions Inactive

@masch masch left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🥦

- Create apps/mobile/src/utils/date.ts with getDatePartsInTimezone
  and HOURS_PER_DAY named constant
- Replace duplicated inline getParts in moments.ts and
  useTimeValidation.ts with shared utility
- Add i18n keys for cascade_timeout_helper, max_attempts_helper,
  project_timezone_helper
- Fix hardcoded English strings in admin project form
- Add 27 tests covering timezone edge cases: UTC±0, ±12, ±14,
  half-hour, quarter-hour offsets, DST spring/fall, leap year,
  year boundary, and local/UTC date crossing
@masch
masch temporarily deployed to development May 25, 2026 00:13 — with GitHub Actions Inactive

@masch masch left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🥦

Replace jest.spyOn(useCartStore.getState(), 'setContext') with
direct store state assertions. The spy pattern is unreliable in CI
due to Zustand v5 reference handling. Check store state directly
after submit instead.
@masch
masch temporarily deployed to development May 25, 2026 00:24 — with GitHub Actions Inactive
…iness

The test relied on jest.useFakeTimers + jest.setSystemTime to prevent
isTimeInPast from blocking the submit flow. Since selectedDate is
always 2024-01-15 (not today at runtime), isTimeInPast returns false
regardless of the real system clock - fake timers were unnecessary.

Also added an explicit expect(submitButton.props.accessibilityState?.disabled)
toBeFalsy check to verify the button is enabled before pressing.
@masch
masch temporarily deployed to development May 25, 2026 00:33 — with GitHub Actions Inactive
… GGA violations

- Add expired-moment guard in handleProceed before setContext call
- Add time_error_expired i18n key (en/es)
- Add testID to all interactive components in index.tsx + DatePicker.tsx
- Extract magic numbers: EPOCH_TIMESTAMP, MIN_GUEST_COUNT, TIME_PAD_WIDTH
- Extract magic numbers in DatePicker: DEFAULT_HOUR, CALENDAR_ICON_SIZE, PENCIL_ICON_SIZE
- Add test for expired moment blocking submit flow
- Add testID prop to DatePicker component interface
- Use named constants over inline literals for GGA compliance
@masch
masch temporarily deployed to development May 25, 2026 01:01 — with GitHub Actions Inactive
…re updater type

- Use functional form for setGuestCount to avoid stale closures (prev -> prev +/- 1)
- Add useMemo for getDefaultTimeForMoment to stabilize Date reference across renders
- Update cart.store setGuestCount to accept (prev: number) => number updater
- Pass functional updater through to Zustand set for consistency
@masch
masch temporarily deployed to development May 25, 2026 01:11 — with GitHub Actions Inactive

@masch masch left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

🥦

@masch
masch merged commit 207c3d3 into main May 25, 2026
3 checks passed
@masch
masch deleted the issue-211/connect-mobile-orders-api branch May 25, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(backend): orders endpoints (booking flow)

1 participant