Files
nixcn-cms/client/src/components/login-form.tsx
2025-12-25 01:38:43 +08:00

81 lines
2.7 KiB
TypeScript

import type { TurnstileInstance } from '@marsidev/react-turnstile';
import { Turnstile } from '@marsidev/react-turnstile';
import { useNavigate } from '@tanstack/react-router';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import NixOSLogo from '@/assets/nixos.svg?react';
import { Button } from '@/components/ui/button';
import {
Field,
FieldGroup,
FieldLabel,
} from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { useGetMagicLink } from '@/hooks/data/useGetMagicLink';
import { cn } from '@/lib/utils';
export function LoginForm({
className,
...props
}: React.ComponentProps<'div'>) {
const formRef = useRef<HTMLFormElement>(null);
const turnstileRef = useRef<TurnstileInstance>(null);
const [token, setToken] = useState<string | null>(null);
const { mutateAsync, isPending } = useGetMagicLink();
const navigate = useNavigate();
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const formData = new FormData(formRef.current!);
const email = formData.get('email')! as string;
mutateAsync({ email, turnstile_token: token! }).then(() => {
void navigate({ to: '/magicLinkSent', search: { email } });
}).catch((error) => {
console.error(error);
toast.error('请求登录链接失败');
turnstileRef.current?.reset();
});
};
return (
<div className={cn('flex flex-col gap-6', className)} {...props}>
<form ref={formRef} onSubmit={handleSubmit}>
<FieldGroup>
<div className="flex flex-col items-center gap-2 text-center">
<div className="flex size-8 items-center justify-center rounded-md">
<NixOSLogo className="size-6" />
</div>
<span className="sr-only">Nix CN Meetup #2</span>
<h1 className="text-xl font-bold"> Nix CN Meetup #2</h1>
</div>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input
id="email"
name="email"
type="email"
placeholder="edolstra@gmail.com"
required
/>
</Field>
<Field>
<Button type="submit" disabled={token === null || isPending}>
{token === null ? '等待 Turnstile' : isPending ? '发送中...' : '发送登录链接'}
</Button>
</Field>
</FieldGroup>
</form>
<Turnstile
ref={turnstileRef}
siteKey="0x4AAAAAACI5pu-lNWFc6Wu1"
options={{
refreshExpired: 'auto',
}}
onSuccess={(token) => {
setToken(token);
}}
/>
</div>
);
}