Files
lib-auth/react/InviteAcceptForm.tsx
T

110 lines
3.2 KiB
TypeScript

import { useEffect, useState, type ChangeEvent, type FormEvent } from "react";
import { Alert, AlertDescription, AlertIcon, Button, FormControl, FormLabel, Input, Spinner, Stack, Text } from "./chakra-compat";
import { FcGoogle } from "react-icons/fc";
import type { AccountInviteTokenState } from "./types";
type InviteAcceptFormTexts = {
loadingLabel: string;
invalidLinkLabel: string;
emailLabel: string;
nameLabel: string;
passwordLabel: string;
passwordConfirmLabel: string;
submitLabel: string;
googleLabel: string;
};
type InviteAcceptFormProps = {
texts: InviteAcceptFormTexts;
tokenState: AccountInviteTokenState;
loading?: boolean;
initialName?: string | null;
showGoogleSignIn?: boolean;
googleLoading?: boolean;
onSubmit: (values: { name: string; password: string; passwordConfirm: string }) => void | Promise<void>;
onGoogleSignIn?: () => void | Promise<void>;
};
export function InviteAcceptForm({
texts,
tokenState,
loading = false,
initialName = null,
showGoogleSignIn = false,
googleLoading = false,
onSubmit,
onGoogleSignIn
}: InviteAcceptFormProps) {
const [name, setName] = useState(initialName ?? "");
useEffect(() => {
setName(initialName ?? "");
}, [initialName, tokenState.status]);
function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const form = new FormData(event.currentTarget);
void onSubmit({
name: String(form.get("name") ?? ""),
password: String(form.get("password") ?? ""),
passwordConfirm: String(form.get("passwordConfirm") ?? "")
});
}
if (tokenState.status === "loading") {
return (
<Stack align="center" py={6} gap={3}>
<Spinner />
<Text color="gray.600">{texts.loadingLabel}</Text>
</Stack>
);
}
if (tokenState.status === "invalid") {
return (
<Alert status="error" borderRadius="md">
<AlertIcon />
<AlertDescription>{tokenState.error || texts.invalidLinkLabel}</AlertDescription>
</Alert>
);
}
return (
<Stack gap={4}>
<FormControl>
<FormLabel>{texts.emailLabel}</FormLabel>
<Input value={tokenState.email} readOnly disabled />
</FormControl>
<form onSubmit={handleSubmit}>
<Stack gap={4}>
<FormControl isRequired>
<FormLabel>{texts.nameLabel}</FormLabel>
<Input name="name" value={name} onChange={(event: ChangeEvent<HTMLInputElement>) => setName(event.target.value)} />
</FormControl>
<FormControl isRequired>
<FormLabel>{texts.passwordLabel}</FormLabel>
<Input name="password" type="password" minLength={8} />
</FormControl>
<FormControl isRequired>
<FormLabel>{texts.passwordConfirmLabel}</FormLabel>
<Input name="passwordConfirm" type="password" minLength={8} />
</FormControl>
<Button type="submit" loading={loading}>
{texts.submitLabel}
</Button>
</Stack>
</form>
{showGoogleSignIn && onGoogleSignIn ? (
<Button variant="outline" loading={googleLoading} leftIcon={<FcGoogle />} onClick={() => void onGoogleSignIn()}>
{texts.googleLabel}
</Button>
) : null}
</Stack>
);
}