rework onboarding screen 2: PWA install instructions with platform detection
screen 1 now combines app intro + endurance message + privacy note. screen 2 shows platform-specific PWA install steps (iOS/Android/fallback) with warning to install before entering data. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { ClipboardList, Loader2, Lock, Route } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Loader2, Lock, Route, Smartphone } from "lucide-react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Input } from "@/shared/components/ui/input";
|
||||
import { Label } from "@/shared/components/ui/label";
|
||||
@@ -10,6 +10,13 @@ import { dbExec } from "@/shared/hooks/use-db";
|
||||
import { GKV_KASSEN } from "@/shared/lib/gkv-kassen";
|
||||
import { cn } from "@/shared/lib/utils";
|
||||
|
||||
function detectPlatform(): "ios" | "android" | "unknown" {
|
||||
const ua = navigator.userAgent;
|
||||
if (/iPad|iPhone|iPod/.test(ua)) return "ios";
|
||||
if (/Android/.test(ua)) return "android";
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function OnboardingForm() {
|
||||
const navigate = useNavigate();
|
||||
const [step, setStep] = useState(0);
|
||||
@@ -47,8 +54,8 @@ export function OnboardingForm() {
|
||||
return (
|
||||
<div className="flex min-h-[80vh] flex-col items-center justify-center">
|
||||
<div className="w-full max-w-md space-y-6">
|
||||
{step === 0 && <IntroScreen1 />}
|
||||
{step === 1 && <IntroScreen2 />}
|
||||
{step === 0 && <IntroScreen />}
|
||||
{step === 1 && <InstallScreen />}
|
||||
{step === 2 && (
|
||||
<>
|
||||
<div className="space-y-2 text-center">
|
||||
@@ -172,7 +179,7 @@ export function OnboardingForm() {
|
||||
);
|
||||
}
|
||||
|
||||
function IntroScreen1() {
|
||||
function IntroScreen() {
|
||||
return (
|
||||
<div className="space-y-4 text-center">
|
||||
<div className="mx-auto flex size-16 items-center justify-center rounded-full bg-primary/10">
|
||||
@@ -184,41 +191,86 @@ function IntroScreen1() {
|
||||
hilft dir, Kontaktversuche zu dokumentieren, Absagen festzuhalten und
|
||||
deinen Kostenerstattungsantrag vorzubereiten.
|
||||
</p>
|
||||
<div className="flex flex-col gap-3 pt-2 text-left">
|
||||
<div className="flex items-start gap-3">
|
||||
<ClipboardList className="mt-0.5 size-5 shrink-0 text-primary" />
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Verwalte deine Therapeutensuche an einem Ort — vom Erstgespräch bis
|
||||
zum fertigen Antrag.
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Einen Therapieplatz zu finden dauert oft Wochen oder Monate. Der Weg ist
|
||||
bürokratisch und braucht Ausdauer. TherapyFinder behält den Überblick,
|
||||
damit du dich auf das Wesentliche konzentrieren kannst.
|
||||
</p>
|
||||
<div className="flex items-start gap-3 pt-2 text-left">
|
||||
<Lock className="mt-0.5 size-5 shrink-0 text-primary" />
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Alle Daten bleiben auf deinem Gerät — es gibt keine Accounts und keine
|
||||
Cloud.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function IntroScreen2() {
|
||||
function InstallScreen() {
|
||||
const platform = useMemo(() => detectPlatform(), []);
|
||||
|
||||
return (
|
||||
<div className="space-y-4 text-center">
|
||||
<div className="mx-auto flex size-16 items-center justify-center rounded-full bg-primary/10">
|
||||
<Lock className="size-8 text-primary" />
|
||||
<Smartphone className="size-8 text-primary" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold">Dein Begleiter im Prozess</h1>
|
||||
<h1 className="text-2xl font-bold">Als App installieren</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Einen Therapieplatz zu finden dauert oft Wochen oder Monate. Der Weg ist
|
||||
bürokratisch und braucht Ausdauer. TherapyFinder behält den Überblick,
|
||||
damit du dich auf das Wesentliche konzentrieren kannst.
|
||||
Füge TherapyFinder zu deinem Home-Bildschirm hinzu, damit du die App
|
||||
jederzeit wie eine normale App öffnen kannst — auch offline.
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Alle Daten bleiben auf deinem Gerät — es gibt keine Accounts und keine
|
||||
Cloud.
|
||||
|
||||
{platform === "ios" && (
|
||||
<div className="space-y-2 rounded-lg border p-4 text-left">
|
||||
<p className="text-sm font-medium">So geht's auf dem iPhone/iPad:</p>
|
||||
<ol className="list-inside list-decimal space-y-1 text-sm text-muted-foreground">
|
||||
<li>
|
||||
Tippe auf das Teilen-Symbol{" "}
|
||||
<span className="inline-block align-text-bottom text-base">
|
||||
⎙
|
||||
</span>
|
||||
</li>
|
||||
<li>Wähle „Zum Home-Bildschirm"</li>
|
||||
<li>Tippe auf „Hinzufügen"</li>
|
||||
</ol>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{platform === "android" && (
|
||||
<div className="space-y-2 rounded-lg border p-4 text-left">
|
||||
<p className="text-sm font-medium">So geht's auf Android:</p>
|
||||
<ol className="list-inside list-decimal space-y-1 text-sm text-muted-foreground">
|
||||
<li>
|
||||
Tippe auf das Menü <span className="font-mono font-bold">⋮</span>{" "}
|
||||
oben rechts
|
||||
</li>
|
||||
<li>Wähle „Zum Startbildschirm hinzufügen"</li>
|
||||
<li>Bestätige mit „Hinzufügen"</li>
|
||||
</ol>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{platform === "unknown" && (
|
||||
<div className="space-y-2 rounded-lg border p-4 text-left">
|
||||
<p className="text-sm font-medium">So geht's:</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Nutze die „Zum Home-Bildschirm hinzufügen"-Funktion deines Browsers,
|
||||
um TherapyFinder als App zu installieren.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-sm font-medium text-amber-600 dark:text-amber-400">
|
||||
Wichtig: Installiere die App jetzt, bevor du Daten eingibst. Nach der
|
||||
Installation startet der Prozess von vorne.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DotIndicator({ current }: { current: number }) {
|
||||
const dots = ["intro", "motivation", "form"] as const;
|
||||
const dots = ["intro", "install", "form"] as const;
|
||||
return (
|
||||
<div className="flex justify-center gap-2">
|
||||
{dots.map((id, i) => (
|
||||
|
||||
Reference in New Issue
Block a user