122 lines
5.9 KiB
TypeScript
122 lines
5.9 KiB
TypeScript
import Link from "next/link";
|
|
import Image from "next/image";
|
|
|
|
import { Button } from "@/components/ui";
|
|
import { getLocale, getTranslator } from "@/lib/i18n";
|
|
import { getSession } from "@/lib/auth";
|
|
|
|
export default async function LoginPage({
|
|
searchParams
|
|
}: {
|
|
searchParams?: Promise<{ error?: string; next?: string }>;
|
|
}) {
|
|
const locale = await getLocale();
|
|
const t = getTranslator(locale);
|
|
|
|
const params = await (searchParams ?? Promise.resolve({ error: undefined, next: undefined }));
|
|
const error = params?.error;
|
|
const next = params?.next ?? "";
|
|
const session = await getSession();
|
|
|
|
const errorMessage = error === "credentials_required"
|
|
? t("login", "error_credentials_required")
|
|
: error === "invalid_credentials"
|
|
? t("login", "error_invalid_credentials")
|
|
: error === "rate_limited"
|
|
? t("login", "error_rate_limited")
|
|
: null;
|
|
|
|
return (
|
|
<main className="flex min-h-screen items-center justify-center bg-background px-6 py-14">
|
|
<div className="grid w-full max-w-5xl overflow-hidden rounded-[2rem] bg-surface-container-lowest shadow-floating">
|
|
<section className="bg-surface-container-lowest border-b border-line px-10 py-16 text-center md:border-r md:border-b-0 md:px-14 md:py-20">
|
|
<Image
|
|
src="/logo_zappcare.png"
|
|
alt="ZappCare"
|
|
width={56}
|
|
height={56}
|
|
className="mx-auto h-14 w-auto rounded-full"
|
|
priority
|
|
/>
|
|
<h1 className="mt-8 text-4xl font-extrabold font-headline text-on-surface">{t("login", "title")}</h1>
|
|
<p className="mx-auto mt-3 max-w-sm text-sm text-on-surface-variant">
|
|
{t("login", "signin_subtitle")}
|
|
</p>
|
|
<div className="mx-auto mt-10 flex w-full max-w-sm flex-col gap-3">
|
|
<div className="rounded-[1.5rem] bg-surface-container-low p-4">
|
|
<p className="text-2xl font-black text-on-surface">3</p>
|
|
<p className="mt-1 text-sm text-on-surface-variant">Role aktif saat ini</p>
|
|
</div>
|
|
<div className="rounded-[1.5rem] bg-surface-container-low p-4">
|
|
<p className="text-2xl font-black text-on-surface">10+</p>
|
|
<p className="mt-1 text-sm text-on-surface-variant">Modul operasi aktif</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<section className="px-8 py-10 md:px-12 md:py-16">
|
|
<div className="mx-auto max-w-md">
|
|
<p className="text-sm font-black uppercase tracking-[0.22em] text-primary">{t("login", "signin_label")}</p>
|
|
<h2 className="mt-3 text-3xl font-black font-headline text-on-surface">{t("login", "signin_subtitle")}</h2>
|
|
<p className="mt-3 text-sm text-on-surface-variant">{t("login", "signin_help")}</p>
|
|
{session ? (
|
|
<p className="mt-4 rounded-[1rem] border border-outline-variant bg-surface-container-high p-4 text-sm text-on-surface-variant">
|
|
Session aktif: {session.fullName} • {session.role} • {session.tenantName}
|
|
</p>
|
|
) : null}
|
|
{errorMessage ? (
|
|
<p className="mt-4 rounded-[1rem] border border-error-container bg-error-container p-3 text-sm text-on-error-container">
|
|
{errorMessage}
|
|
</p>
|
|
) : null}
|
|
<form action="/auth/login" method="post" className="mt-8 space-y-4">
|
|
<input type="hidden" name="next" value={next} />
|
|
<label className="block text-sm text-on-surface-variant">
|
|
{t("login", "email_label")}
|
|
<div className="mt-1.5">
|
|
<input
|
|
name="email"
|
|
autoComplete="email"
|
|
required
|
|
className="h-12 w-full rounded-full border-none bg-surface-container-highest px-4 text-sm outline-none ring-1 ring-outline/40 focus:ring-2 focus:ring-primary"
|
|
placeholder={t("login", "work_email_placeholder")}
|
|
/>
|
|
</div>
|
|
</label>
|
|
<label className="block text-sm text-on-surface-variant">
|
|
{t("login", "password_label")}
|
|
<div className="mt-1.5 relative">
|
|
<input
|
|
name="password"
|
|
type="password"
|
|
autoComplete="current-password"
|
|
required
|
|
className="h-12 w-full rounded-full border-none bg-surface-container-highest px-4 text-sm outline-none ring-1 ring-outline/40 focus:ring-2 focus:ring-primary"
|
|
placeholder={t("login", "password_placeholder")}
|
|
/>
|
|
<span className="material-symbols-outlined absolute right-4 top-1/2 -translate-y-1/2 text-outline">visibility</span>
|
|
</div>
|
|
</label>
|
|
<Button type="submit" className="w-full">{t("login", "sign_in_button")}</Button>
|
|
<button
|
|
type="button"
|
|
className="inline-flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-line bg-surface-container-low px-4 py-2 text-sm font-semibold text-on-surface transition hover:bg-surface-container-high"
|
|
>
|
|
<span className="material-symbols-outlined text-[20px]">fingerprint</span>
|
|
<span>{t("login", "sso_button")}</span>
|
|
</button>
|
|
<p className="text-center text-sm text-on-surface-variant">
|
|
{t("login", "no_account_label")} <Link href="/" className="font-bold text-primary hover:text-on-primary-container">{t("login", "contact_admin")}</Link>
|
|
</p>
|
|
<div className="flex flex-wrap gap-4 text-sm text-on-surface-variant">
|
|
<Link href="/forgot-password" className="font-semibold text-primary hover:text-on-primary-container">
|
|
{t("login", "remember_label")}
|
|
</Link>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|