Files
reservas/resources/js/pages/auth/login.tsx
João Miranda fb04d71a8d
Some checks failed
tests / ci (push) Has been cancelled
first commit
2026-10-27 11:01:11 +00:00

171 lines
7.1 KiB
TypeScript

import { Form, Head } from '@inertiajs/react';
import { Laptop2, ShieldCheck } from 'lucide-react';
import InputError from '@/components/input-error';
import PasskeyVerify from '@/components/passkey-verify';
import PasswordInput from '@/components/password-input';
import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Spinner } from '@/components/ui/spinner';
import { store } from '@/routes/login';
import { request } from '@/routes/password';
type Props = {
status?: string;
canResetPassword: boolean;
microsoftEnabled: boolean;
};
export default function Login({
status,
canResetPassword,
microsoftEnabled,
}: Props) {
return (
<>
<Head title="Entrar" />
<div className="mb-8 text-center">
<div className="mx-auto mb-4 flex size-16 items-center justify-center rounded-2xl bg-gradient-to-br from-primary/20 to-primary/5 dark:from-primary/10 dark:to-primary/5">
<Laptop2 className="size-8 text-primary" />
</div>
<h1 className="text-2xl font-bold tracking-tight">
Portal de Reservas
</h1>
<p className="mt-2 text-sm text-muted-foreground">
Sistema de gestão de equipamentos da escola
</p>
</div>
<PasskeyVerify
label="Entrar com chave de acesso"
loadingLabel="A autenticar..."
separator="Ou continuar com email"
/>
{microsoftEnabled && (
<>
<Button variant="outline" className="w-full" asChild>
<a href="/auth/microsoft/redirect">
Entrar com a conta Microsoft
</a>
</Button>
<div className="relative text-center text-sm">
<span className="relative z-10 bg-background px-2 text-muted-foreground">
ou utilize a conta local
</span>
<span className="absolute inset-x-0 top-1/2 border-t" />
</div>
</>
)}
<Form
{...store.form()}
resetOnSuccess={['password']}
className="flex flex-col gap-6"
>
{({ processing, errors }) => (
<>
<div className="grid gap-5">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
name="email"
required
autoFocus
tabIndex={1}
autoComplete="email"
placeholder="nome@escola.pt"
className="h-11"
/>
<InputError message={errors.email} />
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">
Palavra-passe
</Label>
{canResetPassword && (
<TextLink
href={request()}
className="ml-auto text-sm"
tabIndex={5}
>
Recuperar palavra-passe
</TextLink>
)}
</div>
<PasswordInput
id="password"
name="password"
required
tabIndex={2}
autoComplete="current-password"
placeholder="Palavra-passe"
className="h-11"
/>
<InputError message={errors.password} />
</div>
<div className="flex items-center space-x-3">
<Checkbox
id="remember"
name="remember"
tabIndex={3}
/>
<Label htmlFor="remember" className="text-sm">
Manter sessão
</Label>
</div>
<Button
type="submit"
className="mt-2 h-11 w-full"
tabIndex={4}
disabled={processing}
data-test="login-button"
>
{processing && <Spinner />}
Entrar
</Button>
</div>
<Card className="border-primary/20 bg-primary/5 dark:border-primary/10 dark:bg-primary/5">
<CardContent className="flex items-start gap-3 p-4">
<ShieldCheck className="mt-0.5 size-5 shrink-0 text-primary" />
<div className="text-sm">
<p className="font-medium text-foreground">
Acesso seguro
</p>
<p className="mt-1 text-muted-foreground">
O acesso é atribuído pela escola.
Contacte os Serviços de Informática se
ainda não tiver conta.
</p>
</div>
</CardContent>
</Card>
</>
)}
</Form>
{status && (
<div className="mb-4 text-center text-sm font-medium text-green-600">
{status}
</div>
)}
</>
);
}
Login.layout = {
title: 'Entrar no Portal de Reservas',
description: 'Utilize o seu endereço institucional e palavra-passe.',
};