feat(client): magic link sign-in
Signed-off-by: Noa Virellia <noa@requiem.garden>
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
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 {
|
||||
@@ -6,42 +11,70 @@ import {
|
||||
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>
|
||||
<form ref={formRef} onSubmit={handleSubmit}>
|
||||
<FieldGroup>
|
||||
<div className="flex flex-col items-center gap-2 text-center">
|
||||
<a
|
||||
href="#"
|
||||
className="flex flex-col items-center gap-2 font-medium"
|
||||
>
|
||||
<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>
|
||||
</a>
|
||||
<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">发送登录链接</Button>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user