fix(landing): masque « Ouvrir dans l'application » dans l'app native (#103)
All checks were successful
CI / lint (push) Successful in 2m49s
CI / build (push) Successful in 4m5s
CI / intent-service-test (push) Successful in 6m9s
CI / e2e (push) Successful in 10m31s
CI / test (push) Successful in 29m20s
CI / build-android (push) Has been skipped

`isMobile = isAndroidPhoneBrowser()` est une détection d'user-agent : la
WebView Capacitor contient « Android »/« Mobile », donc le bouton
« Ouvrir dans l'application » s'affichait aussi *dans* l'app packagée — où
le taper tente de relancer l'app via le scheme, échoue, et retombe sur
`/telecharger`.

- Nouveau `canOfferApp = isMobile && !Capacitor.isNativePlatform()` — « un
  navigateur *téléphone* où pousser l'app native a du sens ». Gate le
  bouton et la rétrogradation de « Créer un compte » en secondaire.
- Le lien `/telecharger` (variante desktop) gagne aussi `&&
  !Capacitor.isNativePlatform()` : sur tablette la WebView Capacitor peut
  ne pas avoir « Mobile » dans son UA, donc `!isMobile` ne suffisait pas.

Aucun changement sur le web (`Capacitor.isNativePlatform()` y est toujours
`false`, donc `canOfferApp === isMobile`) — `landing.feature`
(navigateur téléphone + desktop) revérifiée, 7/7. Le chemin natif n'a pas
de couture de test depuis un run web (limitation déjà documentée, cf.
`app-settings-page.cy.ts`).

Closes #103

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Nicolas 2026-09-08 01:50:22 +02:00
parent 3d9f93e204
commit 126cd840f5

View file

@ -1,3 +1,4 @@
import { Capacitor } from "@capacitor/core";
import { CalendarDays, HeartPulse, Smartphone, Sparkles, Users } from "lucide-react";
import type { ReactNode } from "react";
import { useTranslation } from "react-i18next";
@ -29,6 +30,13 @@ export function LandingPage() {
// whether the viewport is narrow (a resized desktop window shouldn't
// attempt a scheme navigation just because it's a small window).
const isMobile = isAndroidPhoneBrowser();
// ...but the Capacitor WebView's UA *also* contains "Android"/"Mobile",
// so `isMobile` alone is true inside the packaged app too — where
// "Ouvrir dans l'application" is nonsense (you're already in it; tapping
// it just tries to re-launch via the scheme, fails, and lands on
// `/telecharger`). `canOfferApp` is the real "a phone *browser* where
// pushing the native app is worthwhile" flag (issue #103).
const canOfferApp = isMobile && !Capacitor.isNativePlatform();
function handleOpenApp() {
attemptOpenNativeApp({ onFallback: () => navigate("/telecharger") });
@ -69,7 +77,7 @@ export function LandingPage() {
* this button doesn't render at all (see the plain `/telecharger`
* link below instead, replacing the old direct-APK link).
*/}
{isMobile && (
{canOfferApp && (
<button
type="button"
className="landing__cta landing__cta--primary"
@ -81,7 +89,7 @@ export function LandingPage() {
)}
<Link
className={
isMobile
canOfferApp
? "landing__cta landing__cta--secondary"
: "landing__cta landing__cta--primary"
}
@ -94,14 +102,16 @@ export function LandingPage() {
</Link>
</div>
{/*
* Desktop only — a scheme-open attempt (the mobile button above)
* has no meaning here. Routed through `/telecharger` (the same
* fallback page a failed mobile attempt lands on) rather than
* linking `${API_BASE_URL}/mobile/download` directly, so "get
* the app" has exactly one canonical destination app-wide
* instead of two slightly different mechanisms to keep in sync.
* Desktop browser only — a phone browser gets the scheme-open
* button above instead, and inside the packaged app "get the app"
* is meaningless (a tablet Capacitor WebView can lack "Mobile" in
* its UA, so `!isMobile` isn't enough on its own — issue #103).
* Routed through `/telecharger` (the same fallback page a failed
* mobile attempt lands on) rather than linking
* `${API_BASE_URL}/mobile/download` directly, so "get the app"
* has exactly one canonical destination app-wide.
*/}
{!isMobile && (
{!isMobile && !Capacitor.isNativePlatform() && (
<Link className="landing__mobile-link" to="/telecharger">
<Smartphone aria-hidden />
{t("landing.hero.mobileDownload")}