170 lines
7.7 KiB
TypeScript
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>
|
|
);
|
|
}
|