Skip to content

feat(PWA-S11): A2HS iOS bottom-sheet on tracking T+0 + standalone heuristique (#463)#480

Merged
alexpmichelet merged 3 commits into
mainfrom
agent/463
Jun 10, 2026
Merged

feat(PWA-S11): A2HS iOS bottom-sheet on tracking T+0 + standalone heuristique (#463)#480
alexpmichelet merged 3 commits into
mainfrom
agent/463

Conversation

@alexpmichelet

Copy link
Copy Markdown
Contributor

Closes #463

Summary

S11 (PWA Client) ships the iOS half of the A2HS moat — the platform that #462 (Android beforeinstallprompt) cannot reach, since Safari iOS never fires the install event. Two surfaces, both decision-driven (pure functions in apps/web/src/lib/a2hs-ios/, vitest-pinned in node env, mirror of the #462 / #460 sibling pattern):

  1. <IOSInstallBottomSheet> — Vaul Drawer rendered on app/c/[orderId]/page.tsx (state T+0 « Cmd reçue », post-paiement endorphin moment, decisions-log Q4 / US 58). 4-gate visibility via decideIosBottomSheetVisibility:
    • iOS Safari only (isIosSafari UA sniff — strict on device family AND on excluding in-app browsers / Chrome iOS / Firefox iOS / Edge iOS / Opera iOS / Instagram / Facebook / TikTok / Snapchat / Pinterest WebViews, since those have a different share menu).
    • NOT already standalone (matchMedia('(display-mode: standalone)') via useSyncExternalStore).
    • pushEnrollment.a2hsStatus !== "enrolled" (Convex sub on getCurrentCustomer).
    • NOT dismissed this session (sessionStorage kb_a2hs_ios_sheet_dismissed, same shape as <WalletPromptBanner> palier 2 S9a — Wallet install button + 3 paliers de prompt (sans bridge identité) #460).
    • Content : 3-step illustration (Safari → Share icon → « Sur l'écran d'accueil » → « Ajouter ») as inline SVG (placeholder mirror of S8 — Tracking page realtime + incidents (placeholders SVG en attendant Lottie) #459's Lottie placeholders — cosmetic GIF swap deferred to a follow-up PR when assets are livered).
  2. <IOSStandaloneHeuristicRunner> — root-layout-mounted, fires customer.pushEnrollment.recordA2hsAccepted the first time it detects standalone display-mode on a fiche whose a2hsStatus is not yet "enrolled" (US 59). NOT iOS-only — also serves as the cross-platform safety net for the rare Android race where S10 — A2HS Android (bouton install post-cart + tracking enrolled) #462's appinstalled event was missed because the tab closed too quickly. Single-fire guarded via useRef. Uses existing self-scoped customerMutation (no backend changes — re-uses recordA2hsAccepted from S10 — A2HS Android (bouton install post-cart + tracking enrolled) #462).

Tested how : 34 new pure unit tests (is-ios-safari UA matrix : iPhone/iPad/iPod Safari + 10.x → 17.x + rejects of in-app browsers ; decideIosBottomSheetVisibility precedence ; decideIosStandaloneHeuristic flip/noop matrix). Full pnpm typecheck && pnpm lint && pnpm test green locally (311/311 tests, 4 preexisting warnings on apps/web/src/components/ui/carousel.tsx + use-mobile.ts, both untouched).

Backend untouched. Touches only apps/web/src/{lib,components}/a2hs-ios/ + 2 wiring spots (app/c/[orderId]/page.tsx adds the sheet ; app/layout.tsx mounts the runner inside the Convex provider).

Plan de test E2E

Aligné sur le format des groupes A2H/CHK/WAL de docs/tests/PWA-CLIENT-E2E-checklist.md (domaine kitchen-boost.com).

A2H — Test A2H.3 : iOS Safari sur tracking T+0 → bottom-sheet visible + dismiss session-scoped

  • Acteur : iPhone Safari (cookie + cache vidés), mode privé. Tester aussi sur iPad Safari si dispo.
  • Pré-requis : tenant test-t1 actif (seeds e2e OK), customer pushEnrollment.a2hsStatus absent ou not_enrolled, Stripe sandbox + Uber Direct sandbox configurés, dev tunnel HTTPS.
  • URL de départ : https://test-t1.kitchen-boost.com/
  • Étapes :
    1. Address-first → menu → add cart → /checkout → push enrollment (Wallet OR noChannelPossible=true pour débloquer) → payer carte test 4242 4242 4242 4242.
    2. Observer la page /c/<orderId> directement après redirect post-paiement.
    3. Toucher « OK plus tard » dans la bottom-sheet.
    4. Recharger /c/<orderId>.
    5. Naviguer /menu puis revenir /c/<orderId>.
    6. Fermer Safari complètement (swipe-up app switcher → close tab), ré-ouvrir https://test-t1.kitchen-boost.com/c/<orderId> dans un nouvel onglet.
  • Attendu : étape 2 : bottom-sheet Vaul s'ouvre depuis le bas avec titre « Ajoute ce resto à ton écran d'accueil », illustration 3 étapes (1. Touche l'icône Partager + icône share / 2. Choisis Sur l'écran d'accueil / 3. Confirme avec Ajouter — animation pulse sur l'icône finale) + bouton « OK plus tard » ; étape 3 : drawer se ferme ; étape 4-5 : bottom-sheet ne réapparaît PAS (sessionStorage kb_a2hs_ios_sheet_dismissed = "1") ; étape 6 : bottom-sheet réapparaît (nouvelle session = nouveau sessionStorage).
  • Couvre : US 58, slice S11 — A2HS iOS (bottom-sheet GIF instructions post-tracking + heuristique standalone) #463, modules decideIosBottomSheetVisibility, isIosSafari, A2HS_IOS_SHEET_DISMISS_KEY.

A2H — Test A2H.4 : Install A2HS iOS → revisit standalone → a2hsStatus = "enrolled" flip + sheet disparaît

  • Acteur : iPhone Safari (suite de A2H.3).
  • Pré-requis : A2H.3 effectué (au moins étape 2 OK pour avoir le orderId), accès Convex dashboard pour vérif backend.
  • URL de départ : https://test-t1.kitchen-boost.com/c/<orderId> (sheet ouverte ou dismissed peu importe).
  • Étapes :
    1. Dans Safari, tap l'icône Partager (rectangle avec flèche vers le haut, en bas de l'écran).
    2. Faire défiler la liste, taper « Sur l'écran d'accueil ».
    3. Confirmer le nom du raccourci, taper « Ajouter ».
    4. Sortir de Safari (Home button / swipe up) → lancer la PWA depuis l'icône fraîchement ajoutée à l'écran d'accueil.
    5. Naviguer une page quelconque (/, /menu, ou re-ouvrir /c/<orderId> via partage SMS).
    6. Vérifier la doc customers correspondante dans Convex dashboard.
  • Attendu :
    • Étape 4 : la PWA s'ouvre sans barre d'URL Safari (display-mode: standalone).
    • Étape 5 : bottom-sheet n'apparaît PAS sur /c/<orderId> (déjà standalone → décision retourne hidden / already-standalone + <IOSStandaloneHeuristicRunner> fire la mutation).
    • Étape 6 : doc customers a pushEnrollment.a2hsStatus = "enrolled" ; nouveau row auditLog avec action: "customer.pushEnrollment.recordA2hsAccepted", actorRole: "customer", targetType: "customer", targetId: <customerId>. Un seul row par installation (single-fire ref + idempotence pure decision).
  • Couvre : US 59, slice S11 — A2HS iOS (bottom-sheet GIF instructions post-tracking + heuristique standalone) #463, modules decideIosStandaloneHeuristic, <IOSStandaloneHeuristicRunner>, recordA2hsAccepted mutation.

A2H — Test A2H.5 : Android Chrome + desktop + in-app browsers → bottom-sheet jamais visible (iOS-only)

  • Acteur : 3 devices/contextes en parallèle — Android Chrome, Desktop Safari macOS (si dispo), Instagram in-app browser sur iOS (tap un lien KitchenBoost depuis un story).
  • Pré-requis : tenant test-t1 actif, possibilité de commander pour atteindre /c/<orderId>.
  • URL de départ : https://test-t1.kitchen-boost.com/c/<orderId> (depuis chaque device).
  • Étapes :
    1. Sur Android Chrome : compléter un flow checkout jusqu'à /c/<orderId>.
    2. Sur Desktop Safari : coller l'URL /c/<orderId> (partage SMS depuis le téléphone Android).
    3. Sur Instagram in-app browser iOS : ouvrir un lien kitchen-boost.com/c/<orderId> depuis un message direct ou story (force ouverture dans la WebView Instagram).
  • Attendu : sur les 3 devices, la bottom-sheet n'apparaît JAMAIS (AC 4 « Android → bottom sheet n'apparaît jamais » + extension : aussi desktop + in-app browsers). Sur Android, le bouton flottant <AndroidInstallButton> (S10 — A2HS Android (bouton install post-cart + tracking enrolled) #462) reste fonctionnel — c'est sa branche dédiée. Sur Desktop / Instagram, aucun bouton d'install n'est rendu (palier soft, ces plateformes n'ont pas la capabilité native).
  • Couvre : US 58 AC 4, slice S11 — A2HS iOS (bottom-sheet GIF instructions post-tracking + heuristique standalone) #463, module isIosSafari (rejection matrix).

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
kitchen-boost-repo-admin Ready Ready Preview, Comment Jun 10, 2026 8:42pm
kitchen-boost-repo-web Ready Ready Preview, Comment Jun 10, 2026 8:42pm

@alexpmichelet
alexpmichelet merged commit 37450ca into main Jun 10, 2026
4 checks passed
@alexpmichelet
alexpmichelet deleted the agent/463 branch June 10, 2026 20:44
alexpmichelet added a commit that referenced this pull request Jun 10, 2026
…on retour) (#481)

* docs(e2e): peupler groupe A2H iOS (slice #463 / PR #480)

3 scénarios E2E filtrés/inscrits depuis la PR #480 :
- A2H.3 iOS Safari sur tracking T+0 → bottom-sheet + dismiss session-scoped
- A2H.4 Install A2HS iOS → revisit standalone → flip a2hsStatus
- A2H.5 Android Chrome → bottom-sheet iOS jamais visible (iOS-only assertion)

Statut groupe A2H : 2 Android + 3 iOS = 5 scénarios prêts à tester.
Note A2H.5 : matrice complète in-app browsers iOS (Insta/FB/TikTok)
couverte par 34 unit tests `is-ios-safari` côté PR — pas dupliqué en E2E.

* test(PWA-S12): scaffold decideReturnGreeting + NotMeLink handlers tests

* feat(PWA-S12): recognition retour banner + Ce nest pas moi disown link

- decideReturnGreeting pure decision (banner / silent / none) — Q3 surveillance
  guardrail enforced by type (firstName only, never address/history).
- GreetingBanner RSC + NotMeLink client shell + makeNotMeHandlers factory
  (signOut → POST /api/signout → reload, each step best-effort to guarantee
  the disown UX always reaches the reload).
- /api/signout route deletes the three Convex Auth cookies (__Host- prefix
  on prod, bare on localhost) — lock-stepped with SDK via pure
  convexAuthCookieNames helper (pinned test on regex + naming).
- Home RSC reads preloaded fiche → renders banner / prefill / disown link;
  subtitle switches to 'Confirme ton adresse' when prefill visible (Q3
  hospitality reframing of the deprecated Valider/Confirmer button cue).
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.

S11 — A2HS iOS (bottom-sheet GIF instructions post-tracking + heuristique standalone)

1 participant