vineroute// field manual
Rider
Driver
Dispatch
Systems
The Rider/Offers
07 / 08

Offers

Promotions, in the rider's hand

MarketingOffersCatalog

Overview

Six to ten offer cards rendered as a FlatList. Each card has a square hero image (Unsplash, cached), a route-color accent stripe down the left edge, the winery name and offer title in Instrument Serif, a single paragraph of body, a redemption code chip chip if the offer has one, and a small validity range ('VALID THROUGH MAY 20'). The list reorders by validFrom so newer offers float to the top.

How it works

1

`GET /api/passenger/offers` returns only active offers within their validity window — the API filters on isActive=true and validFrom <= now <= validTo server-side so the client doesn't render dead promotions.

2

Tap-to-copy is `expo-clipboard.setStringAsync(code)` plus a haptic via `expo-haptics` (ImpactFeedbackStyle.Light) and a toast that auto-dismisses in 2s.

3

Tap on the card body (anywhere except the code chip) opens an external browser via `Linking.openURL` to the winery's site, if one is on the offer record.

4

Images use the same disk-cached Unsplash flow as routes and stops — `/assets/<id>.regular.jpg`, resolved through `resolveImageUrl`.

5

The list refreshes via React Query on screen focus, so a freshly-published offer from the admin shows up the next time the rider opens the tab.

Key decisions

Codes are tap-to-copy, not auto-applied

We don't have a wallet or auto-applied promo system — partner wineries enter codes at their POS. Tap-to-copy on the rider's phone makes the redemption physical and trivially fast. The haptic and toast confirm the action without a modal.

Server-side filtering, not client-side

Showing an expired offer is worse than showing nothing. The API enforces the validity window before the row ever reaches the client, so a clock-skewed phone can't surface a stale promotion. The win is a guarantee; the cost is one extra WHERE clause.

Offers

Quick Reference

Routeapps/mobile/app/(passenger)/(tabs)/offers.tsx
StoreReact Query
APIsGET /api/passenger/offers
Components
OfferCardCodePillexpo-clipboardexpo-haptics
PreviousTripsNextYou