Skip to content

Release v0.1.0 - #64

Open
roncodes wants to merge 90 commits into
mainfrom
release/v0.1.0
Open

roncodes wants to merge 90 commits into
mainfrom
release/v0.1.0

Conversation

@roncodes

@roncodes roncodes commented Oct 6, 2026

Copy link
Copy Markdown
Member

Release v0.1.0

Release branch for the Network edition (marketplace) and the extensibility work. Cut from main; merging it tags v0.1.0 through the release workflow (#55).

Included via #54 (feature/marketplace-edition → release/v0.1.0)

On this branch

  • Version bumped to 0.1.0

Before merging

  • Merge feat: restore marketplace edition #54 into this branch
  • Device testing on iOS and Android: single-store and Network edition flows, cart and checkout, login, push notifications
  • Web build smoke test

roncodes and others added 30 commits August 11, 2026 23:33
- Read runtime app config for Tamagui custom colors via src/env.ts
- Web MMKV shim: stable defaults, cross-hook sync, raw string storage
- Web device id is generated once and reused
- Use browser confirm for cart replacement on web
- Guard StoreCategory deep links and boot splash on missing config
- Return to the calling screen after location permission is granted
- Replace undefined palette tokens with defined theme tokens
- Pass missing env keys to the web build and derive __DEV__ from mode
- Fix storage setters dropping values and CI .env overwrites
- Add TrueVegan themes to the web CSS theme-name fix
- Move Network edition screens to src/screens/network (NetworkHome, NetworkSearch,
  NetworkMap, NetworkCategory, NetworkStore, NetworkProduct) and rename routes/tabs
- Move marketplace-runtime to src/network/network-runtime; storefront mode is now 'network'
- Rename MarketplaceStoreCard to NetworkStoreCard and the i18n namespace to Network
- Declare Network deep-link paths once (stores/:storeId, stores/:storeId/products/:productId,
  stores/:storeId/categories/:categoryId, categories/:categoryId, search, map)
- Pin persisted storage scope values with a test so renames cannot orphan data
- Replace lint/typecheck:marketplace with lint/typecheck:strict and update CI and README
- Remove unused placeholder NetworkHomeScreen, ConfigContext, empty TabBar and
  ProductBookingPanel, and the stale canAddProductToCart helper
The device was only registered at login, and only if a push token had
already been received. Tokens that arrived later (e.g. after granting the
Android 13+ notification permission) or rotated were never registered, so
those customers got no push notifications. Register whenever the token or
the customer changes, and unregister the token on logout so the next
customer on the device does not receive the previous customer's pushes.
- Stable screen ids with typed params for overridable screens
- Lazy default screens, compiled-in overrides and declarative variants
- screenSlot(id) components used by navigators instead of screen imports
- Error boundaries fall back to the default screen, then a load-error view
- Preload initial screens during boot to avoid a loading frame
- storefront.extensions.ts as the brand override entry point
- Network store/product shells render the store.home/product.detail slots
- ESLint rule and test enforcing the navigator import boundary
- Registry, fallback and type tests; docs/extensibility.md
- Register i18n translations lazily instead of at LanguageContext import time;
  reading storefront config during module initialization crashed web boot through
  the utils -> use-storefront -> LanguageContext -> utils cycle
- Fix Platform import typo in AddNewLocationScreen that threw at module load
- Versioned, zod-validated branding schema (colors, appearance, components,
  assets, boot, navigation, screen variants) with per-value fallback
- Layered resolution: defaults < legacy env keys < storefront.brand.ts < dev preview
- Legacy APP_THEME, CUSTOM_COLORS*, STORE_HEADER_*, PRODUCT_CARD_STYLE and
  navigator env keys mapped into branding; existing profiles resolve unchanged
- Themes generated from presets with exact parity to the previous themes, plus
  Tamagui interaction keys (hover/press/focus, placeholder, color1-12)
- WCAG contrast checks; enforced for preview sources, reported for build sources
- BrandingProvider owns the color scheme (system/light/dark, migrated from the
  old key, follows device changes) and registers runtime themes via addTheme
  when resolved colors differ from the compiled theme
- useAppTheme/ThemeContext/getTheme become shims over one shared state
- config/default.js presentation keys and screen variant selection read branding
- Dev-only local branding preview; docs/branding.md
- QPayPaymentSheet: import Platform
- DriverMarker: import haversine from utils/math
- StoreRating: fix nRatingChange typo
- TabSwitch: import LayoutChangeEvent type
- use-customer: import isResource (utils) and storage get
- use-fleetbase-data: depend on fleetbase instead of undefined storefront
- use-oauth.web: Apple Sign-In is native-only, report unsupported
- use-stripe-checkout.web: stub native Stripe functions to return an error
- StoreNavigator/TestNavigator: fix focued typo in tabBarLabelStyle
- CircleExpandInterpolator: take width/height from layouts.screen
- CartItemScreen: drop unused getCartItem import (cart comes from useCart)
- App.tsx: import Platform
- ConfigContext: use imported storefrontConfig (useAuth doesn't provide it)
- AddNewLocationScreen: fix Platfrom import typo
- EditLocationCoordScreen, LocationPickerScreen: import toast
- SaveLocationScreen: define theme and loading state; gate button on save in progress
- StripeCustomerScreen.web: drop native-only CustomerSheet usage
- DriverMarker: declare event refs after useEventBuffer (TDZ fix)
fix: stabilize network edition runtime, web shims, and theming config
refactor: rename Marketplace application concepts to Network
feat: add typed screen registry with compiled-in overrides
feat: add typed branding system with generated themes
fix: keep the push device token registered for the signed-in customer
fix: resolve TS2304 missing-name runtime bugs
Fix undefined-name runtime bugs flagged by tsc (TS2304)
- Register uk.json in localize.js and the default AVAILABLE_LOCALES
- Add Ukrainian strings for the Network and ScreenSlot keys and common.goBack
- Add the two Mongolian keys missing from mn.json
- Test that every locale has the same keys as en.json and is registered
- Deliver to sheet: search for a new address, use the current location, or pick
  a saved place (current one first, marked Default, with edit) and confirm.
  Checkout notes that the delivery fee is re-quoted.
- Address search: current location and nearby addresses before typing, live
  results while typing, empty state, and "set it on the map". On the web it
  falls back to the Geocoding API, since the Places API has no CORS.
- Map pin: fixed pin, address looked up as the map settles, reset and locate
  me; also used to adjust the pin of an address being edited.
- Address details: pin preview, place type, label, street (required), unit,
  postal code, neighbourhood, city, phone, courier notes, default switch and
  delete with confirmation. Saving returns to whatever opened the flow.
- Saved places: cards with type icon, Default badge, Edit and Set as default.
- Location prompt: allow, enter an address, Not now when opened in the app,
  and a Settings path when permission is off.
- The address screens are registered at the root, so the network edition can
  search addresses instead of only using the map. Guest places (no id) are
  matched by street and pin.
"Free delivery over $40 · spend S$7.80 more to unlock" mixed the promotion's
free-text name with an amount the app formats. Free delivery, percentage and
fixed-amount hints now read "Spend S$7.80 more for free delivery", "... for 15%
off" and "... for S$5 off", all formatted in the cart's currency. Other
promotion types keep the name with the amount to spend.
A short, still map at the top of the delivery address card: each store in the
cart joined to the delivery pin by a dashed line, with the straight-line
distance ("About 2.4 km from Bloom & Co.", or "2 stores · about 3 km"). The
line turns red when delivery isn't available. Tapping it changes the address.
Straight lines need no directions lookup, so checkout makes no extra map API
call; until the stores' locations load, or if they can't be found, the card
looks as before. The web map shim now maps line colour, width and dashes.
After the payment went through, a failed capture showed an error and dropped
the checkout: the customer was charged with no order. Capture is safe to
repeat (the server returns the existing order), so it is now retried after 1,
2 and 4 seconds. If it still fails, the paid checkout is kept (also across app
restarts, for the same customer) and checkout shows "Your payment went
through" with a Finish placing order button that captures it without charging
again. The cart is only emptied once the order exists.
…iet socket drops

- Checkout route preview: each store joins the delivery pin with a dashed arc,
  as in the design, instead of a straight line; the map frames the arc.
- Order map (delivery and pickup): the store is a round initials tile and the
  delivery address a dark house pin (a person for the customer on pickup),
  replacing the large pins with address callouts.
- A dropped socket connection ("Socket hung up", e.g. a tunnel or proxy closing
  an idle socket) is logged quietly instead of as an error; the client
  reconnects and resubscribes by itself.
- Orders on a custom order config (e.g. Created > Dispatched > Started >
  Enroute > Completed) show that config's own steps, labels and details from
  GET orders/{id}/activity-flow, which resolves branches server-side. Orders on
  the default storefront config keep the app's wording. Refreshed when the
  status changes.
- The order QR code shows on every active order, delivery and pickup, so
  drivers and stores can scan it; it was only shown on ready pickups.
- The ready-for-pickup box only shows on pickup orders.
- Store: pickup location or food truck name, full address, and a call button.
- Order public id next to the tracking number; full delivery/pickup address;
  item variants, add-ons and photo; notes under a heading; cash due on
  delivery.
- Percentage tips ("10%") are shown as amounts here and on the receipt.
The screen registry loads screens with import(). Development bundles are
requested with lazy=true, so Metro split at every import() and each screen was
built and downloaded the first time it opened, which over the network took up
to a minute per screen. Requests now ask for lazy=false, so the first bundle
holds the whole app as it did before the registry. Release builds are
unaffected: they always contain every screen.
- Store info: opening hours are grouped by weekday in the app instead of the
  storefront SDK's schedule getter, which crashed ('pushObject' of undefined)
  unless days were written exactly "Monday"; days are matched in any case.
  A location without hours is no longer shown as open 24 hours, and today's
  column is highlighted correctly (it was one day off, and only in English).
- Scroll bars are hidden on every scrolling screen and list.
- The active order on the profile is a brand-tinted card with a thin brand
  border, a live dot, the store and order number, and a Track pill.
The page was a fixed column, so content below the fold (reviews) was cut off.
The header, contact pills, hours and reviews now scroll together, with room
for the home indicator.
…t 2.0.1

The storefront SDK now builds on the core SDK v2 instead of a bundled 1.2.13,
so the app and storefront share one copy of the core SDK (resources, adapters
and instanceof checks match) and requests use its Fetch transport. 2.1.1 sends
query lists in the bracket form the API reads.

- axios is now a direct dependency (Google geocoding); it used to arrive
  through the old SDK.
- Web: the core SDK alias points at its v2 entry (dist/index.js).
- Adapter headers are set through a typed withHeaders() helper; the
  Storefront <=1.1.14 store re-propagation is gone, as 2.x rebuilds its stores
  in setAdapter().
…it; close button works; sheet background continues past its end
… products shown coming with the earliest appointment
return value.replace(/\\/g, '\\\\').replace(/;/g, '\x5c;').replace(/,/g, '\\,').replace(/\r?\n/g, '\\n');
}

export function icsFor(event: CalendarEvent, uid: string): string {
…inimum order); pickup stays each store's own
…creen, and only retried when retrying can help
…ore page home, shared product screen, catalog, search, map, store info, edit profile and tab bar
… truck menus; trucks tab in Networks and a home screen setting

- The Trucks tab opens on a map of trucks and stores with the customer's zone, a category slider, the nearest truck and store, and the cart. A toggle switches to a list home (greeting, live trucks card, categories, current offer) and the choice is remembered.
- Search covers truck menus and store products. Each result names its truck or store, and items from trucks that are offline or outside the customer's zone can't be ordered.
- A truck's menu is laid out like a store page: category tabs and product rows that open the shared product screen with the truck as the fulfilling location.
- In a Network the map shows member stores and their trucks. A single store shows its own locations and trucks.
- HOME_SCREEN=foodTrucks (branding navigation.home) opens either edition on the trucks map. NETWORK_FOOD_TRUCKS_TAB adds the Trucks tab to a Network. STORE_NAVIGATOR_DEFAULT_TAB is now applied.
…ens and tabs, and bring their own fonts

Client builds in brand/
- A client build keeps everything it owns in brand/: storefront.brand.ts, storefront.extensions.ts, screens, translations/<locale>.json and fonts. A fork that only adds brand/ merges new releases without conflicts.
- scripts/link-brand.js writes git-ignored modules in src/generated that point at the brand files, or at the root templates when there is no brand/. It runs from babel.config.js, so Metro, webpack, Jest and the Tamagui compiler resolve the same files. It also runs on postinstall, before typecheck:strict, and from yarn brand:link.
- brand/translations are merged over the app's strings and can add keys or locales.
- Type checks include brand/, so a client's overrides are checked against screen params after an upgrade.

Custom routes and tabs
- New `routes` in the extensions add screens to every stack of their editions, reachable with navigation.navigate. Optional deep-link paths are declared once. Name clashes with core routes are skipped. Load and render failures show an error view.
- New `tabs` open a custom route, with an icon (FontAwesome or a render function) and a label (translation key, plain string or per locale). A tab goes where navigation.store.tabs lists it, at its `position`, or before Cart. `initial` opens the app on it. Both editions are supported.

Typography
- Branding `typography.body` and `typography.heading` name a family and, per weight, the PostScript name of a file in brand/fonts. `typography.scale` adjusts the shared text sizes.
- Tamagui's body and heading fonts use them. Native builds link brand/fonts (react-native.config.js). The web build registers the files with @font-face at startup.

Docs: docs/client-builds.md, plus updates to extensibility, branding and the README.
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.

2 participants