Commit Graph
96 Commits
Author SHA1 Message Date
KrikoriosandClaude 899ca93cd5 Remove mock seed drivers and dead marker scatter
The drivers table was seeded with 4 fake fixtures (Karim/Rana/Omar/Layal)
using randomuser.me/unsplash placeholder images. They had no user_id, no
position, and were excluded from matching and the rider map by design, so
they only ever cluttered the dashboard. The table now starts empty — real
drivers are created in-app via onboarding (driver/profile POST), which
links a row to a real user account and gives it a live GPS position.

Dropped the dead random-offset scatter in generateMarkersFromData that
fabricated fake driver positions for drivers without GPS. It was already
unreachable (the null-position filter excluded those drivers), so this is
stub cleanup, not a behavior change — drivers without a real position
simply aren't rendered.

The 4 fixture rows were also removed from the live Neon DB (user_id IS
NULL); real onboarded drivers were untouched.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-24 14:23:42 +03:00
Krikorios 90cc487c32 Merge driver app, dispatch, POI suggestions, and map-tiles fix 2026-08-24 13:58:05 +03:00
KrikoriosandClaude f50ff27e11 Build driver app, Uber-style dispatch, POI suggestions; fix map tiles
Driver side (was a stub):
- In-app driver onboarding: a driver-role user creates their own linked
  drivers profile (driver/profile+api GET/POST/PATCH).
- Driver dashboard: online/offline toggle, today's earnings, incoming
  request cards (accept/decline), active ride panel (start/complete trip).
  Polls /driver/rides every 4s while online.
- Location heartbeat (use-driver-location): watchPositionAsync pings
  /driver/location every ~5s; restarts the watch on app foreground so a
  backgrounded driver doesn't go permanently stale and miss requests.

Dispatch (auto-match nearest, Uber-style):
- Ride state machine: requested -> accepted -> en_route -> completed/cancelled
  with a nullable driver_id until matched (lib/dispatch.matchNextDriver).
- matchNextDriver locks the ride (SELECT FOR UPDATE), expires 15s-stale
  offers, picks the nearest eligible driver of the matching service by
  haversine, offers one at a time. Called from ride/create, ride/[id] GET
  (lazy match on the rider's poll), and ride/[id]/respond (on decline).
- ride/create is now a request endpoint (driver_id NULL, status=requested,
  service); drops the pre-match driver_id payment reconciliation.
- ride/[id] GET returns status/service/nullable driver; PATCH handles rider
  cancel + driver en_route/completed. ride/list backs the history tabs.

Rider flow (best experience):
- confirm-ride is now a request screen: single trip fare + nearest-driver
  ETA + cash/card + Request Ride -> live status. Periodically polls online
  drivers of the selected service and disables Request when none are
  online (prevents the "stuck searching forever" state).
- book-ride is the live ride-status screen (searching -> accepted ->
  en_route -> completed/cancelled + Cancel), polling every 3s.
- lib/request-ride unifies the Areeba card flow + cash path.
- Map reads /driver/nearby (real positions, service-filtered); lib/map
  adds calculateTripFare + service-aware fares.

POI suggestions:
- lib/places (Google Nearby Search) + nearby-suggestions chips for
  mall/hospital/pharmacy/restaurant on the home screen.

Service categories now drive both matching and a per-service fare
multiplier (car 1.0 / moto 0.7 / courier 0.85 / chauffeur 1.5).

Map tiles: react-native-maps rendered blank on Android because no Google
Maps key was set. Switched app.json -> app.config.js so
android.config.googleMaps.apiKey is injected from
EXPO_PUBLIC_GOOGLE_API_KEY at build time (keeps the key out of git).
Requires a native rebuild (expo run:android) to take effect.

Also includes the prior payment/auth hardening (server-authoritative
payment_orders ledger with double-spend guards, peppered OTP, register
TOCTOU fix, stats cents fix) that was left uncommitted.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-24 13:57:21 +03:00
KrikoriosandClaude Opus 5 4e0a7cca51 Fix map failing to render, dedupe expo-crypto
The home screen passed its FlatList header as `ListHeaderComponent={() =>
(...)}`. VirtualizedList renders a function-valued header prop as
`<HeaderComponent />`, so a fresh arrow function on each render is a fresh
element type: React unmounted the entire header subtree — MapView included —
and mounted a new one. Home re-renders several times on mount (useFetch
loading->data, useUserLocation pending->granted, session resolve), and
recreating the Android GoogleMap surface each time left it grey with the
Google logo and tiles that never finished loading.

Pass the header as an element instead so the type stays stable and MapView
mounts once. The same `() => (...)` pattern in ListEmptyComponent here, and in
rides.tsx and confirm-ride.tsx, cost needless remounts of list chrome and
DriverCards; fixed alongside.

Also pin expo-crypto to ~13.0.2. It was ^57.0.1 — a wrong-major native module
for SDK 51 that nothing in the app imports. npm hoisted it to the top level
and gave expo-auth-session a nested 13.0.2 to satisfy its ~13.0.0 constraint,
leaving two copies of one native module in the tree for autolinking to choose
between.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 00:32:34 +03:00
KrikoriosandClaude Opus 5 59e336c23d Fix home map and location, add service selector
The Android map never drew because mapType was "mutedStandard", an Apple
Maps value. Android's MapManager looks the name up in a fixed table and
unboxes the result into an int, so an unrecognised value threw a
NullPointerException in the native view manager before any tile
rendered. Android now gets "standard" plus a customMapStyle that mutes
POI and transit labels, since showsPointsOfInterest is iOS-only too.

Location hung indefinitely: getCurrentPositionAsync was called with no
accuracy and no timeout, so it waited for a GPS fix that never arrives
indoors or on an emulator with no mock location. useUserLocation now
takes a cached fix first for an immediate render, caps the precise
reading at 15 seconds, and checks device location services separately
from app permission. Reverse geocoding moved off the critical path so a
failed lookup costs the address label rather than the coordinates. The
single boolean became five states, each with its own notice and either a
retry or a settings shortcut, since retrying a hard denial does nothing.

Map also no longer deletes itself when the driver fetch fails or the
location is still pending: drivers are an overlay, and calculateRegion
already falls back to Beirut.

Adds a four-tile service selector above Recent Rides - Car, Moto,
Courier, My Car - with the choice held in useServiceStore for the
booking flow to read. English only for now; the intended Arabic names
are recorded in constants/services.ts for the language pass. Selection
styling matches the role picker on sign-up so the two read as one
control.

app.config.js layers the Google Maps key and expo-location permission
strings onto app.json. No effect under Expo Go, which ignores native
config, but required for the first EAS build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 23:34:04 +03:00
KrikoriosandClaude Opus 5 bc23c94ea2 Add remember-me and OTP autofill, fix session persistence
Sign-in gains a "Keep me signed in" checkbox: checked issues a 30-day
token and prefills the address next launch, unchecked drops the session
to 12 hours and forgets the address. The TTL is chosen server-side in
the login route.

Emailed codes are now reachable without retyping. OtpField opts into the
iOS one-time-code keyboard suggestion and raises a paste chip when the
user returns from Gmail with a code on the clipboard. The mails put the
code first in the subject and body, which is what makes Gmail render its
"Copy code" notification action at all.

Fixes found along the way:

- Session was wiped on every launch. decodeJwtExp used atob, which
  neither RN 0.74 nor Expo SDK 51 defines, so it threw, returned null,
  and the caller read that as "expired" and deleted the token. Replaced
  with a dependency-free base64url decoder, and restore now only
  discards a session it can prove is expired.
- Verification and reset codes counted attempts but never enforced them,
  leaving a 6-digit code open to unlimited guessing. Both routes now
  charge the attempt before comparing so concurrent guesses can't race
  past the cap of five, and compare in constant time.
- A wrong verification code showed the "Verified" success screen:
  onModalHide fired unconditionally, so the failure state advanced the
  flow. Only an explicit "verified" state does that now.
- fetchAPI discarded the server's error body, so the UI substring-matched
  synthetic status strings and showed "Could not sign in" for everything.
  It now throws ApiError carrying status and the server's message.
- Login answered a missing account faster than a wrong password; it now
  runs the same scrypt work either way.
- Blank email or password is caught client-side instead of surfacing as
  an opaque 400, and a failed attempt only clears the password on a 401.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 23:33:51 +03:00
KrikoriosandClaude Fable 5 eceb6b45d5 Fix SMTP delivery, add password reset and user deletion
SMTP:
- Add connection/greeting/socket timeouts so a stalled Gmail
  connection no longer hangs sign-up
- Wrap sendMail in try/catch and fall back to logging the code
- Derive secure from port (465 implicit TLS vs 587 STARTTLS)
- Strip whitespace from the Gmail app password
- Document SMTP_HOST/SMTP_PORT in .env.example and environment.d.ts

Password reset (new):
- POST /(api)/auth/forgot-password emails a 6-digit code and does
  not reveal whether the address is registered
- POST /(api)/auth/reset-password validates the code, sets the new
  password, verifies the email, and signs the user in
- password_reset_codes table added to seed-db.mjs
- "Forgot password?" flow on the mobile sign-in screen

User deletion (new):
- DELETE /(api)/admin/users/[id], owner-only, blocks self-deletion
- Delete button with confirmation on the dashboard Users page

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 22:41:41 +03:00
Krikorios a0b297285a Add self-hosted auth, admin API, and owner web dashboard
- Replace Clerk with self-hosted JWT auth (register/login/verify, bcrypt
  passwords, Gmail OTP with console fallback)
- Add lib/db.ts pg pool + transaction helpers; seed script migrates legacy
  Clerk-era schema (drop clerk_id, enforce UUID ids and unique email)
- Add owner-gated admin API: stats, users, drivers CRUD, rides
- Add dashboard/ Vite React owner dashboard (login, overview, users,
  fleet, rides) with dev-server proxy to avoid Expo CORS middleware
- Add scripts/set-owner.mjs for role management
2026-08-23 16:38:41 +03:00
Krikorios fbe92c9d16 Add rider/driver role selection after sign-up
- users.role column (+ migration in seed script)
- /(api)/user: GET role by clerkId, PATCH to set role
- Role selection screen; drivers get placeholder driver-home
- Root index routes by role; hardened location handling on home
2026-08-22 16:13:59 +03:00
Krikorios fdc1664cce chore: drop upstream README-update workflow 2026-08-22 16:04:02 +03:00
Krikorios c16c335481 docs: replace Stripe setup with Areeba in README 2026-08-22 15:59:45 +03:00
Krikorios 62dc5e9d53 Rebrand to Waseel, swap Stripe for Areeba, add phone-ready auth and DB seed
- Rename app: Waseel (name, slug, scheme waseel://, com.waseel.app ids, splash)
- Payments: replace Stripe with Areeba hosted checkout (create/verify API routes,
  lib/areeba.ts, WebBrowser-based payment flow)
- Maps: migrate address autocomplete to Places API (New), drop legacy library
- Web support: map stub for web (native maps are iOS/Android only)
- Auth: keep email + Google OAuth; fix OAuth redirect for Expo Go
- Add scripts/seed-db.mjs (schema + Lebanese driver seed)
- Pin Expo SDK 51 compatible package versions
2026-08-22 15:53:41 +03:00
Sanidhya Kumar Verma a2f46e6c03 Merge pull request #5 from sanidhyy/docs/update-github-issue-templates
docs: update github issue templates
2026-08-22 14:04:35 +05:30
Sanidhya Kumar Verma 49f8f9b1db docs: update github issue templates 2026-08-22 13:41:31 +05:30
Sanidhya Kumar Verma 25677aea3c Merge pull request #3 from sanidhyy/chore/rename-domain-to-sanidhyy-name
chore: update author contact email
2026-08-21 20:43:56 +05:30
Sanidhya Kumar Verma b3f5860eb9 Merge pull request #4 from sanidhyy/docs/add-missing-contact-email
docs: add missing community contact email
2026-08-21 20:30:03 +05:30
Sanidhya Kumar Verma 310738ca2c docs: add missing community contact email 2026-08-21 20:17:15 +05:30
Sanidhya Kumar Verma a94bf7ba56 chore: update author contact email 2026-08-21 19:26:03 +05:30
github-actions[bot] 68272e41d6 docs: update dependencies and folder structure in README 2026-02-23 05:23:05 +00:00
Sanidhya Kumar Verma d28759b7a5 Merge branch 'main' of https://github.com/sanidhyy/uber-clone 2026-02-23 10:52:41 +05:30
Sanidhya Kumar Verma f102d01528 ci: configure eas workflow 2026-02-23 10:52:38 +05:30
github-actions[bot] 22727e3c9b docs: update dependencies and folder structure in README 2026-02-23 05:17:04 +00:00
Sanidhya Kumar Verma 8809c31068 ci: add workflow to auto-update dependencies and folder structure in README 2026-02-23 10:46:31 +05:30
Sanidhya Kumar Verma ba89fcf1ad Update README.md 2026-02-19 22:44:25 +05:30
Sanidhya Kumar Verma ed8aefaf1c Update Twitter link to new X.com format 2026-02-13 10:06:54 +05:30
Sanidhya Kumar Verma 730471b731 Update README.md 2026-01-10 16:37:25 +05:30
Sanidhya Kumar Verma bd48211703 updated package info 2024-09-06 06:07:14 +00:00
Sanidhya Kumar Verma 81481724ba fix eslint warnings 2024-09-06 06:03:01 +00:00
Sanidhya Kumar Verma e69adb70b1 README completed 2024-09-06 05:56:01 +00:00
Sanidhya Kumar Verma 4171199097 github readme images added 2024-09-06 05:55:50 +00:00
Sanidhya Kumar Verma caf67adc50 env example added 2024-09-06 05:30:47 +00:00
Sanidhya Kumar Verma 4d21e5590b Create CODE_OF_CONDUCT.md 2024-09-06 10:37:36 +05:30
Sanidhya Kumar Verma d6b69e7249 Create CONTRIBUTING.md 2024-09-06 10:37:10 +05:30
Sanidhya Kumar Verma 6511e8511b Create dependabot.yml 2024-09-06 10:34:10 +05:30
Sanidhya Kumar Verma e0db76d4ed Create SECURITY.md 2024-09-06 10:32:48 +05:30
Sanidhya Kumar Verma e2ca0c5d85 Create FUNDING.yml 2024-09-06 10:31:57 +05:30
Sanidhya Kumar Verma c3376a6a16 Update issue templates 2024-09-06 10:31:46 +05:30
Sanidhya Kumar Verma bb80621a8e updated project id 2024-09-06 04:41:03 +00:00
Sanidhya Kumar Verma 8b40f7a5e6 setup eas file for building app 2024-09-06 04:09:10 +00:00
Sanidhya Kumar Verma dfe455c9c0 updated app data 2024-09-04 13:05:14 +00:00
Sanidhya Kumar Verma 7894ff18aa source code link added 2024-09-04 12:58:27 +00:00
Sanidhya Kumar Verma 2a0e9a79dc completed final todo 2024-09-04 12:32:35 +00:00
Sanidhya Kumar Verma 96d14cecad typo fixes and code improvements 2024-09-04 12:01:27 +00:00
Sanidhya Kumar Verma ac4019e5d1 profile screen ui implemented 2024-09-04 11:57:15 +00:00
Sanidhya Kumar Verma d1a8106c81 chat screen ui completed 2024-09-04 11:56:20 +00:00
Sanidhya Kumar Verma 04694246c0 fix oauth flow 2024-09-04 11:53:27 +00:00
Sanidhya Kumar Verma 1f0ecd696d OAuth implemented 2024-09-04 11:38:47 +00:00
Sanidhya Kumar Verma 8cb07ae079 bun add expo-linking 2024-09-04 11:19:33 +00:00
Sanidhya Kumar Verma efe9b523a2 rides fixed 2024-09-04 11:14:56 +00:00
Sanidhya Kumar Verma 02dbd6c7af stripe payment integrated 2024-09-04 11:05:39 +00:00