feat(PWA-S11): A2HS iOS bottom-sheet on tracking T+0 + standalone heuristique (#463)#480
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 inapps/web/src/lib/a2hs-ios/, vitest-pinned in node env, mirror of the #462 / #460 sibling pattern):<IOSInstallBottomSheet>— Vaul Drawer rendered onapp/c/[orderId]/page.tsx(state T+0 « Cmd reçue », post-paiement endorphin moment, decisions-log Q4 / US 58). 4-gate visibility viadecideIosBottomSheetVisibility:isIosSafariUA 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).matchMedia('(display-mode: standalone)')viauseSyncExternalStore).pushEnrollment.a2hsStatus !== "enrolled"(Convex sub ongetCurrentCustomer).kb_a2hs_ios_sheet_dismissed, same shape as<WalletPromptBanner>palier 2 S9a — Wallet install button + 3 paliers de prompt (sans bridge identité) #460).<IOSStandaloneHeuristicRunner>— root-layout-mounted, firescustomer.pushEnrollment.recordA2hsAcceptedthe first time it detects standalone display-mode on a fiche whosea2hsStatusis 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'sappinstalledevent was missed because the tab closed too quickly. Single-fire guarded viauseRef. Uses existing self-scopedcustomerMutation(no backend changes — re-usesrecordA2hsAcceptedfrom S10 — A2HS Android (bouton install post-cart + tracking enrolled) #462).Tested how : 34 new pure unit tests (
is-ios-safariUA matrix : iPhone/iPad/iPod Safari + 10.x → 17.x + rejects of in-app browsers ;decideIosBottomSheetVisibilityprecedence ;decideIosStandaloneHeuristicflip/noop matrix). Fullpnpm typecheck && pnpm lint && pnpm testgreen locally (311/311 tests, 4 preexisting warnings onapps/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.tsxadds the sheet ;app/layout.tsxmounts 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(domainekitchen-boost.com).A2H — Test A2H.3 : iOS Safari sur tracking T+0 → bottom-sheet visible + dismiss session-scoped
test-t1actif (seeds e2e OK), customerpushEnrollment.a2hsStatusabsent ounot_enrolled, Stripe sandbox + Uber Direct sandbox configurés, dev tunnel HTTPS.https://test-t1.kitchen-boost.com//checkout→ push enrollment (Wallet ORnoChannelPossible=truepour débloquer) → payer carte test4242 4242 4242 4242./c/<orderId>directement après redirect post-paiement./c/<orderId>./menupuis revenir/c/<orderId>.https://test-t1.kitchen-boost.com/c/<orderId>dans un nouvel onglet.kb_a2hs_ios_sheet_dismissed = "1") ; étape 6 : bottom-sheet réapparaît (nouvelle session = nouveau sessionStorage).decideIosBottomSheetVisibility,isIosSafari,A2HS_IOS_SHEET_DISMISS_KEY.A2H — Test A2H.4 : Install A2HS iOS → revisit standalone →
a2hsStatus = "enrolled"flip + sheet disparaîthttps://test-t1.kitchen-boost.com/c/<orderId>(sheet ouverte ou dismissed peu importe)./,/menu, ou re-ouvrir/c/<orderId>via partage SMS).customerscorrespondante dans Convex dashboard.display-mode: standalone)./c/<orderId>(déjà standalone → décision retournehidden / already-standalone+<IOSStandaloneHeuristicRunner>fire la mutation).customersapushEnrollment.a2hsStatus = "enrolled"; nouveau rowauditLogavecaction: "customer.pushEnrollment.recordA2hsAccepted",actorRole: "customer",targetType: "customer",targetId: <customerId>. Un seul row par installation (single-fire ref + idempotence pure decision).decideIosStandaloneHeuristic,<IOSStandaloneHeuristicRunner>,recordA2hsAcceptedmutation.A2H — Test A2H.5 : Android Chrome + desktop + in-app browsers → bottom-sheet jamais visible (iOS-only)
test-t1actif, possibilité de commander pour atteindre/c/<orderId>.https://test-t1.kitchen-boost.com/c/<orderId>(depuis chaque device)./c/<orderId>./c/<orderId>(partage SMS depuis le téléphone Android).kitchen-boost.com/c/<orderId>depuis un message direct ou story (force ouverture dans la WebView Instagram).<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).isIosSafari(rejection matrix).🤖 Generated with Claude Code