165 lines
5.9 KiB
TypeScript
165 lines
5.9 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { LanguageToggle } from "@/components/language-toggle";
|
|
import { useLanguage } from "@/lib/i18n-context";
|
|
|
|
const steps = [
|
|
{ href: "/onboarding/business", icon: "storefront", labelKey: "business" as const, step: 1 },
|
|
{ href: "/onboarding/store-detail", icon: "store", labelKey: "storeDetail" as const, step: 2 },
|
|
{ href: "/onboarding/plan", icon: "payments", labelKey: "plan" as const, step: 3 },
|
|
];
|
|
|
|
export default function OnboardingLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const pathname = usePathname();
|
|
const { t } = useLanguage();
|
|
const lo = t.onboarding.layout;
|
|
|
|
const isSuccessPage = pathname.startsWith("/onboarding/success");
|
|
const currentStep = steps.find((s) => pathname.startsWith(s.href));
|
|
const stepNumber = currentStep?.step ?? (isSuccessPage ? steps.length : 1);
|
|
|
|
if (isSuccessPage) {
|
|
return (
|
|
<div className="min-h-screen bg-surface text-on-surface font-body antialiased">
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-surface text-on-surface font-body antialiased">
|
|
{/* Top Header */}
|
|
<header className="fixed top-0 w-full z-50 bg-white/85 backdrop-blur-md shadow-sm flex justify-between items-center px-6 py-4">
|
|
<div className="flex items-center gap-8">
|
|
<Link href="/">
|
|
<Image src="/ina_logo.png" alt="Ina Trading" width={140} height={42} priority />
|
|
</Link>
|
|
<div className="hidden md:flex items-center gap-2 px-3 py-1 bg-surface-container-high rounded-full">
|
|
<span className="text-xs font-bold text-primary">
|
|
Step {stepNumber} {lo.stepOf} {steps.length}
|
|
</span>
|
|
<div className="w-24 h-1.5 bg-outline-variant/30 rounded-full overflow-hidden">
|
|
<div
|
|
className="h-full bg-primary transition-all duration-500"
|
|
style={{ width: `${(stepNumber / steps.length) * 100}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<LanguageToggle />
|
|
</header>
|
|
|
|
<div className="flex min-h-screen pt-20">
|
|
{/* Sidebar */}
|
|
<aside className="sticky top-20 hidden h-[calc(100vh-5rem)] w-64 flex-col gap-6 overflow-y-auto bg-surface-container-low py-8 md:flex">
|
|
<div className="px-8 mb-4">
|
|
<h2 className="text-xl font-black text-primary font-headline">{lo.setupGuide}</h2>
|
|
<p className="text-xs text-on-surface-variant font-medium">{lo.progress}</p>
|
|
</div>
|
|
<nav className="flex flex-col gap-1">
|
|
{steps.map((s) => {
|
|
const isActive = pathname.startsWith(s.href);
|
|
const isDone = s.step < stepNumber;
|
|
const isLocked = s.step > stepNumber;
|
|
const label = lo[s.labelKey];
|
|
const className = `flex items-center gap-3 py-3 pl-4 transition-all duration-300 font-semibold ${
|
|
isActive
|
|
? "text-primary font-bold border-l-4 border-primary"
|
|
: isLocked
|
|
? "cursor-not-allowed text-outline/70"
|
|
: "text-on-surface-variant hover:bg-primary/5"
|
|
}`;
|
|
|
|
const content = (
|
|
<>
|
|
<span
|
|
className="material-symbols-outlined"
|
|
style={{
|
|
fontVariationSettings: isDone ? "'FILL' 1" : "'FILL' 0",
|
|
}}
|
|
>
|
|
{isDone ? "check_circle" : s.icon}
|
|
</span>
|
|
<span>{label}</span>
|
|
</>
|
|
);
|
|
|
|
if (isLocked) {
|
|
return (
|
|
<span key={s.href} className={className} aria-disabled="true">
|
|
{content}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Link key={s.href} href={s.href} className={className}>
|
|
{content}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
<div className="mt-auto px-6 pb-2">
|
|
<div className="rounded-xl bg-surface-container-highest p-4 shadow-sm">
|
|
<p className="text-[10px] uppercase tracking-widest font-bold text-outline mb-2">{lo.proTip}</p>
|
|
<p className="text-xs leading-relaxed text-on-surface-variant">
|
|
{lo.proTipText}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Content */}
|
|
<main className="flex-1 overflow-y-auto pb-24 md:pb-0">{children}</main>
|
|
</div>
|
|
|
|
{/* Bottom Nav Mobile */}
|
|
<nav className="md:hidden fixed bottom-0 left-0 right-0 bg-white/95 backdrop-blur-md flex justify-around items-center py-4 px-2 z-50">
|
|
{steps.map((s) => {
|
|
const isActive = pathname.startsWith(s.href);
|
|
const isLocked = s.step > stepNumber;
|
|
const className = `flex flex-col items-center gap-1 ${
|
|
isActive
|
|
? "text-primary"
|
|
: isLocked
|
|
? "cursor-not-allowed text-outline/70"
|
|
: "text-on-surface-variant"
|
|
}`;
|
|
const content = (
|
|
<>
|
|
<span
|
|
className="material-symbols-outlined"
|
|
style={{ fontVariationSettings: isActive ? "'FILL' 1" : "'FILL' 0" }}
|
|
>
|
|
{s.icon}
|
|
</span>
|
|
<span className="text-[10px] font-bold">{lo[s.labelKey]}</span>
|
|
</>
|
|
);
|
|
|
|
if (isLocked) {
|
|
return (
|
|
<span key={s.href} className={className} aria-disabled="true">
|
|
{content}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Link key={s.href} href={s.href} className={className}>
|
|
{content}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
</div>
|
|
);
|
|
}
|