110 lines
3.2 KiB
TypeScript
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>
|
|
);
|
|
}
|