Files
server-serverless-e2e-mqxya0re/apps/app/src/components/AuthCard.tsx
2026-06-28 17:35:09 +02:00

106 lines
3.1 KiB
TypeScript

import type { FormEvent } from 'react'
import type { I18nNode, I18nString } from '@pikku/react'
import {
Box,
Button,
Card,
Container,
PasswordInput,
Stack,
Text,
TextInput,
Title,
} from '@pikku/mantine/core'
import { m } from '@/i18n/messages'
import { useLocale } from '@/i18n/config'
type AuthCardProps = {
title: I18nString
description: I18nString
cta: I18nString
email: string
password: string
// 'current-password' on login (let the browser fill a saved password),
// 'new-password' on signup (let it suggest a strong one).
passwordAutoComplete: 'current-password' | 'new-password'
busy: boolean
message: I18nString | null
error: I18nString | null
footer: I18nNode
onEmailChange: (value: string) => void
onPasswordChange: (value: string) => void
onSubmit: (event: FormEvent<HTMLFormElement>) => void
}
export function AuthCard(props: AuthCardProps) {
useLocale()
return (
<Box
mih="100vh"
style={{
background:
'radial-gradient(circle at top left, rgba(96, 165, 250, 0.16), transparent 30%), linear-gradient(180deg, #10203a 0%, #07111e 56%, #040913 100%)',
}}
py="xl"
>
<Container size={560}>
<Card radius="xl" padding="xl" withBorder shadow="xl" bg="rgba(10, 20, 36, 0.86)">
<Stack gap="lg">
<div>
<Text
tt="uppercase"
fw={700}
fz="xs"
c="blue.3"
mb="sm"
style={{ letterSpacing: '0.18em' }}
>
{m.auth__eyebrow()}
</Text>
<Title order={1}>{props.title}</Title>
<Text c="dimmed" mt="sm" maw={440}>
{props.description}
</Text>
</div>
<form onSubmit={props.onSubmit}>
<Stack gap="md">
<TextInput
label={m.common__email()}
placeholder={m.common__email_placeholder()}
value={props.email}
onChange={(event) => props.onEmailChange(event.currentTarget.value)}
required
radius="md"
type="email"
autoComplete="email"
/>
<PasswordInput
label={m.common__password()}
placeholder={m.common__password_placeholder()}
value={props.password}
onChange={(event) => props.onPasswordChange(event.currentTarget.value)}
required
radius="md"
autoComplete={props.passwordAutoComplete}
/>
<Button type="submit" loading={props.busy} radius="md" size="md">
{props.cta}
</Button>
</Stack>
</form>
{props.message ? <Text c="teal.3">{props.message}</Text> : null}
{props.error ? <Text c="red.3">{props.error}</Text> : null}
<Text c="dimmed" size="sm">
{props.footer}
</Text>
</Stack>
</Card>
</Container>
</Box>
)
}