Files
perauset-e2e-mrfzot2p/apps/app/src/pages/login.tsx
2026-07-11 08:34:30 +02:00

97 lines
2.8 KiB
TypeScript

import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useState } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import {
Box,
Card,
TextInput,
PasswordInput,
Button,
Text,
Stack,
Alert,
Group,
} from '@pikku/mantine/core'
import { m } from '@/i18n/messages'
import { useLocale } from '@/i18n/config'
import type { I18nString } from '@pikku/react'
import { signIn, INVALID_CREDENTIALS } from '../lib/auth'
function LoginPage() {
useLocale()
const navigate = useNavigate()
const qc = useQueryClient()
const [email, setEmail] = useState(import.meta.env.DEV ? 'admin@perauset.org' : '')
const [password, setPassword] = useState(import.meta.env.DEV ? 'test' : '')
const [isPending, setIsPending] = useState(false)
const [error, setError] = useState<I18nString | null>(null)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setIsPending(true)
setError(null)
try {
await signIn(email, password)
await qc.invalidateQueries({ queryKey: ['me'] })
navigate({ to: '/' })
} catch (err: any) {
setError(err.message === INVALID_CREDENTIALS ? m.login_invalid_credentials() : m.login_error())
} finally {
setIsPending(false)
}
}
return (
<Box
style={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#F5F0E8',
padding: 16,
}}
>
<Card shadow="lg" padding="xl" radius="lg" w={400} maw="100%" style={{ backgroundColor: '#ffffff' }}>
<form onSubmit={handleSubmit}>
<Stack gap="md">
<Group justify="center">
<Text size="xl" fw={700} style={{ color: '#2A7B88', fontSize: 28 }}>
{m.brand()}
</Text>
</Group>
<Text ta="center" size="sm" c="dimmed">
{m.login_subtitle()}
</Text>
{error && (
<Alert color="red" variant="light">
{error}
</Alert>
)}
<TextInput
label={m.common_email()}
type="email"
required
value={email}
onChange={(e) => setEmail(e.currentTarget.value)}
/>
<PasswordInput
label={m.common_password()}
required
value={password}
onChange={(e) => setPassword(e.currentTarget.value)}
/>
<Button type="submit" fullWidth loading={isPending} color="teal" size="md" radius="md" mt="sm">
{m.login_cta()}
</Button>
</Stack>
</form>
</Card>
</Box>
)
}
export const Route = createFileRoute('/login')({
component: LoginPage,
})