Files
web-probindo/resources/js/pages/auth/login.tsx
T
afriadirahman 8c6dad2a31
tests / ci (push) Canceled after 0s
Admin Panel
2026-09-29 14:57:37 +07:00

170 lines
7.7 KiB
TypeScript

import { Form, Head, Link } from '@inertiajs/react';
import InputError from '@/components/input-error';
import PasswordInput from '@/components/password-input';
import { Button } from '@/components/site/button';
import Card from '@/components/site/card';
import { TextInput } from '@/components/site/form-field';
import Glow, { GridPattern } from '@/components/site/glow';
import Icon from '@/components/site/icon';
import LanguageToggle from '@/components/site/language-toggle';
import ThemeToggle from '@/components/site/theme-toggle';
import { common } from '@/content/common';
import { company } from '@/data/site';
import { useContent } from '@/hooks/use-locale';
import { home } from '@/routes';
import { store } from '@/routes/login';
import { request } from '@/routes/password';
type Props = {
status?: string;
canResetPassword: boolean;
};
/**
* Admin panel sign-in. Public registration is disabled; admin accounts are
* created with `php artisan admin:create`.
*/
export default function Login({ status, canResetPassword }: Props) {
const t = useContent(common).login;
return (
<div className="probindo-site bg-surface-container-lowest text-on-surface relative flex min-h-svh flex-col items-center justify-center overflow-hidden p-6 font-sans antialiased">
<Head title={t.pageTitle} />
<GridPattern />
<Glow className="-top-40 -left-20 h-[500px] w-[640px]" />
<Glow className="bg-primary/15 -right-20 bottom-0 h-[420px] w-[520px]" />
<div className="absolute top-5 right-5 flex items-center gap-2">
<LanguageToggle />
<ThemeToggle />
</div>
<div className="relative flex w-full max-w-md flex-col gap-6">
<Link
href={home()}
className="flex flex-col items-center gap-3 self-center"
>
<div className="border-outline-variant/50 dark:bg-surface-container-low rounded-2xl border bg-white p-3">
<img
src={company.logo}
alt={company.name}
className="h-12 w-auto object-contain"
/>
</div>
<span className="text-on-surface-variant font-mono text-xs font-medium">
{company.name}
</span>
</Link>
<Card padding="lg" className="shadow-xl">
<div className="mb-6 flex flex-col gap-1 text-center">
<h1 className="font-display text-on-surface text-2xl font-extrabold">
{t.title}
</h1>
<p className="text-on-surface-variant text-sm">
{t.description}
</p>
</div>
{status && (
<div
role="status"
className="border-primary/40 text-on-surface mb-4 rounded-lg border p-3 text-center text-sm"
>
{status}
</div>
)}
<Form
{...store.form()}
resetOnSuccess={['password']}
className="flex flex-col gap-5"
>
{({ processing, errors }) => (
<>
<div className="flex flex-col gap-1.5">
<label
htmlFor="email"
className="text-on-surface font-mono text-xs font-medium"
>
{t.email}
</label>
<TextInput
id="email"
type="email"
name="email"
required
autoFocus
autoComplete="email"
placeholder={t.emailPlaceholder}
/>
<InputError message={errors.email} />
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between">
<label
htmlFor="password"
className="text-on-surface font-mono text-xs font-medium"
>
{t.password}
</label>
{canResetPassword && (
<Link
href={request()}
className="text-primary text-xs font-semibold hover:underline"
>
{t.forgot}
</Link>
)}
</div>
<PasswordInput
id="password"
name="password"
required
autoComplete="current-password"
placeholder={t.passwordPlaceholder}
className="border-outline-variant/60 bg-surface-container-lowest text-on-surface focus-visible:border-primary h-auto rounded-xl px-4 py-2.5 text-sm"
/>
<InputError message={errors.password} />
</div>
<label className="text-on-surface-variant flex cursor-pointer items-center gap-2 text-sm">
<input
type="checkbox"
name="remember"
className="h-4 w-4"
/>
{t.remember}
</label>
<Button
type="submit"
size="block"
icon={
processing
? 'progress_activity'
: 'login'
}
disabled={processing}
data-test="login-button"
>
{t.submit}
</Button>
</>
)}
</Form>
</Card>
<Link
href={home()}
className="text-on-surface-variant hover:text-primary flex items-center gap-1.5 self-center text-sm"
>
<Icon name="arrow_back" className="text-base" />
{t.back}
</Link>
</div>
</div>
);
}