detect PWA install state, skip install screen if installed, show warning banner in browser
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,8 +17,19 @@ function detectPlatform(): "ios" | "android" | "unknown" {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function isInstalledPwa(): boolean {
|
||||
if (window.matchMedia("(display-mode: standalone)").matches) return true;
|
||||
if (
|
||||
"standalone" in navigator &&
|
||||
(navigator as { standalone?: boolean }).standalone
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function OnboardingForm() {
|
||||
const navigate = useNavigate();
|
||||
const installed = useMemo(() => isInstalledPwa(), []);
|
||||
const [step, setStep] = useState(0);
|
||||
const [dbReady, setDbReady] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
@@ -55,8 +66,8 @@ export function OnboardingForm() {
|
||||
<div className="flex min-h-[80vh] flex-col items-center justify-center">
|
||||
<div className="w-full max-w-md space-y-6">
|
||||
{step === 0 && <IntroScreen />}
|
||||
{step === 1 && <InstallScreen />}
|
||||
{step === 2 && (
|
||||
{!installed && step === 1 && <InstallScreen />}
|
||||
{step === (installed ? 1 : 2) && (
|
||||
<>
|
||||
<div className="space-y-2 text-center">
|
||||
<h1 className="text-2xl font-bold">Über dich</h1>
|
||||
@@ -167,13 +178,13 @@ export function OnboardingForm() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{step < 2 && (
|
||||
{step < (installed ? 1 : 2) && (
|
||||
<Button className="w-full" onClick={() => setStep(step + 1)}>
|
||||
Weiter
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<DotIndicator current={step} />
|
||||
<DotIndicator current={step} installed={installed} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -267,8 +278,16 @@ function InstallScreen() {
|
||||
);
|
||||
}
|
||||
|
||||
function DotIndicator({ current }: { current: number }) {
|
||||
const dots = ["intro", "install", "form"] as const;
|
||||
function DotIndicator({
|
||||
current,
|
||||
installed,
|
||||
}: {
|
||||
current: number;
|
||||
installed: boolean;
|
||||
}) {
|
||||
const dots = installed
|
||||
? (["intro", "form"] as const)
|
||||
: (["intro", "install", "form"] as const);
|
||||
return (
|
||||
<div className="flex justify-center gap-2">
|
||||
{dots.map((id, i) => (
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
useMatchRoute,
|
||||
} from "@tanstack/react-router";
|
||||
import { ListChecks, Settings, Users } from "lucide-react";
|
||||
import { useMemo } from "react";
|
||||
import { isInstalledPwa } from "@/features/onboarding/components/onboarding-form";
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: () => {
|
||||
@@ -12,9 +14,16 @@ export const Route = createRootRoute({
|
||||
const isOnboarding = matchRoute({ to: "/onboarding" });
|
||||
const isRoot = matchRoute({ to: "/" });
|
||||
const hideNav = isOnboarding || isRoot;
|
||||
const installed = useMemo(() => isInstalledPwa(), []);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-background text-foreground">
|
||||
{!hideNav && !installed && (
|
||||
<div className="bg-amber-500 px-4 py-2 text-center text-sm font-medium text-white dark:bg-amber-600">
|
||||
App nicht installiert — füge TherapyFinder zum Home-Bildschirm
|
||||
hinzu, um Datenverlust zu vermeiden.
|
||||
</div>
|
||||
)}
|
||||
<main className="mx-auto w-full max-w-2xl flex-1 px-4 pb-20 pt-6">
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user