Skip to content

Commit

Permalink
Improved singin form with react-hook-form and zod
Browse files Browse the repository at this point in the history
  • Loading branch information
kearfy committed Jul 3, 2023
1 parent 78e0c1f commit 883dcfa
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 19 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build": "next build && rm -rf out/dev"
},
"dependencies": {
"@hookform/resolvers": "^3.1.1",
"@mui/material": "^5.13.4",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 49 additions & 15 deletions src/app/[locale]/account/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,63 @@ import {
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { cn } from '@/lib/utils';
import { zodResolver } from '@hookform/resolvers/zod';
import { ChevronsUpDown, Info, Loader2, XCircle } from 'lucide-react';
import { useTranslations } from 'next-intl';
import Link from 'next-intl/link';
import React, { createRef, useCallback, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

type scope = 'player' | 'manager' | 'admin';

const Schema = z.object({
identifier: z.string().email({ message: 'Enter a valid email address!' }),
});

type Schema = z.infer<typeof Schema>;

export default function Signin() {
const defaultScope =
(typeof window !== 'undefined' &&
(localStorage.getItem('signin.default-scope') as scope)) ||
'player';

const t = useTranslations('pages.account.signin');
const [scope, setScope] = useState<scope>('player');
const [scope, setScope] = useState<scope>(defaultScope);
const [status, setStatus] = useState<{
error?: boolean;
message?: string;
loading?: boolean;
}>({});
const emailRef = createRef<HTMLInputElement>();

const submitEmail = useCallback(async () => {
const identifier = emailRef.current?.value;
if (!identifier) {
setStatus({ message: 'Please enter your email', error: true });
return;
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Schema>({
resolver: zodResolver(Schema),
});

// Dirty solution, will fix later :)
useEffect(() => {
const set = (message: string) => {
if (!status.error && status.message !== message) {
setStatus({
error: true,
message,
});
}
};

if (errors.root?.message) {
set(errors.root.message);
} else if (errors.identifier?.message) {
set(errors.identifier.message);
}
}, [errors, status, setStatus]);

const handler = handleSubmit(async ({ identifier }) => {
setStatus({ message: 'Loading', loading: true });

const raw = await fetch('/api/auth/magic-link', {
Expand All @@ -66,11 +99,14 @@ export default function Signin() {
error: true,
});
}
}, [emailRef, scope]);
});

return (
<Container className="flex flex-grow flex-col items-center justify-center">
<div className="flex flex-col items-center gap-8">
<form
className="flex flex-col items-center gap-8"
onSubmit={handler}
>
<Card className="flex flex-col gap-4">
<CardHeader className="flex flex-row justify-between gap-24">
<div>
Expand Down Expand Up @@ -111,7 +147,7 @@ export default function Signin() {
<CardContent>
<Input
placeholder={t('input.email.placeholder')}
ref={emailRef}
{...register('identifier')}
/>
<div className="h-4 pt-2">
{status.message && (
Expand All @@ -137,9 +173,7 @@ export default function Signin() {
</div>
</CardContent>
<CardFooter>
<Button onClick={submitEmail}>
{t('button.continue')}
</Button>
<Button type="submit">{t('button.continue')}</Button>
</CardFooter>
</Card>
<Link
Expand All @@ -148,7 +182,7 @@ export default function Signin() {
>
{t('link.create-account')}
</Link>
</div>
</form>
</Container>
);
}
13 changes: 9 additions & 4 deletions src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,22 @@ import { create } from 'zustand';
type AnyUser = TAdminRecord | TManagerRecord | TPlayerRecord;

export type AuthStore = {
user?: AnyUser;
user?: AnyUser & { scope: string };
loading: boolean;
setUser: (user: AnyUser) => void;
setUser: (user: AnyUser & { scope: string }) => void;
refreshUser: () => void;
};

export const useAuth = create<AuthStore>((set) => {
function updateAuth() {
surreal
.info<AnyUser>()
.then((user) => set(() => ({ user, loading: false })));
.query<[(AnyUser & { scope: string })[]]>(
/* surrealql */ `SELECT *, scope = meta::tb(id) FROM $auth`
)
.then((res) => {
const user = res?.[0]?.result?.[0];
if (user) set(() => ({ user: user, loading: false }));
});
}

setInterval(updateAuth, 60000);
Expand Down

0 comments on commit 883dcfa

Please sign in to comment.