diff options
| author | MohamedBassem <me@mbassem.com> | 2024-03-13 21:43:44 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2024-03-14 16:40:45 +0000 |
| commit | 04572a8e5081b1e4871e273cde9dbaaa44c52fe0 (patch) | |
| tree | 8e993acb732a50d1306d4d6953df96c165c57f57 /apps/web/components/signin/CredentialsForm.tsx | |
| parent | 2df08ed08c065e8b91bc8df0266bd4bcbb062be4 (diff) | |
| download | karakeep-04572a8e5081b1e4871e273cde9dbaaa44c52fe0.tar.zst | |
structure: Create apps dir and copy tooling dir from t3-turbo repo
Diffstat (limited to 'apps/web/components/signin/CredentialsForm.tsx')
| -rw-r--r-- | apps/web/components/signin/CredentialsForm.tsx | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/apps/web/components/signin/CredentialsForm.tsx b/apps/web/components/signin/CredentialsForm.tsx new file mode 100644 index 00000000..5296e163 --- /dev/null +++ b/apps/web/components/signin/CredentialsForm.tsx @@ -0,0 +1,222 @@ +"use client"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { ActionButton } from "@/components/ui/action-button"; +import { zSignUpSchema } from "@hoarder/trpc/types/users"; +import { signIn } from "next-auth/react"; +import { useState } from "react"; +import { api } from "@/lib/trpc"; +import { useRouter } from "next/navigation"; +import { TRPCClientError } from "@trpc/client"; + +const signInSchema = z.object({ + email: z.string().email(), + password: z.string(), +}); + +function SignIn() { + const [signinError, setSigninError] = useState(false); + const router = useRouter(); + const form = useForm<z.infer<typeof signInSchema>>({ + resolver: zodResolver(signInSchema), + }); + + return ( + <Form {...form}> + <form + onSubmit={form.handleSubmit(async (value) => { + const resp = await signIn("credentials", { + redirect: false, + email: value.email, + password: value.password, + }); + if (!resp || !resp?.ok) { + setSigninError(true); + return; + } + router.replace("/"); + })} + > + <div className="flex w-full flex-col space-y-2"> + {signinError && ( + <p className="w-full text-center text-red-500"> + Incorrect username or password + </p> + )} + <FormField + control={form.control} + name="email" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Email</FormLabel> + <FormControl> + <Input type="text" placeholder="Email" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <FormField + control={form.control} + name="password" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Password</FormLabel> + <FormControl> + <Input type="password" placeholder="Password" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <ActionButton type="submit" loading={form.formState.isSubmitting}> + Sign In + </ActionButton> + </div> + </form> + </Form> + ); +} + +function SignUp() { + const form = useForm<z.infer<typeof zSignUpSchema>>({ + resolver: zodResolver(zSignUpSchema), + }); + const [errorMessage, setErrorMessage] = useState(""); + + const router = useRouter(); + + const createUserMutation = api.users.create.useMutation(); + + return ( + <Form {...form}> + <form + onSubmit={form.handleSubmit(async (value) => { + try { + await createUserMutation.mutateAsync(value); + } catch (e) { + if (e instanceof TRPCClientError) { + setErrorMessage(e.message); + } + return; + } + const resp = await signIn("credentials", { + redirect: false, + email: value.email, + password: value.password, + }); + if (!resp || !resp.ok) { + setErrorMessage("Hit an unexpected error while signing in"); + return; + } + router.replace("/"); + })} + > + <div className="flex w-full flex-col space-y-2"> + {errorMessage && ( + <p className="w-full text-center text-red-500">{errorMessage}</p> + )} + <FormField + control={form.control} + name="name" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Name</FormLabel> + <FormControl> + <Input type="text" placeholder="Name" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <FormField + control={form.control} + name="email" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Email</FormLabel> + <FormControl> + <Input type="text" placeholder="Email" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <FormField + control={form.control} + name="password" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Password</FormLabel> + <FormControl> + <Input type="password" placeholder="Password" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <FormField + control={form.control} + name="confirmPassword" + render={({ field }) => { + return ( + <FormItem> + <FormLabel>Confirm Password</FormLabel> + <FormControl> + <Input + type="password" + placeholder="Confirm Password" + {...field} + /> + </FormControl> + <FormMessage /> + </FormItem> + ); + }} + /> + <ActionButton type="submit" loading={form.formState.isSubmitting}> + Sign Up + </ActionButton> + </div> + </form> + </Form> + ); +} + +export default function CredentialsForm() { + return ( + <Tabs defaultValue="signin" className="w-full"> + <TabsList className="grid w-full grid-cols-2"> + <TabsTrigger value="signin">Sign In</TabsTrigger> + <TabsTrigger value="signup">Sign Up</TabsTrigger> + </TabsList> + <TabsContent value="signin"> + <SignIn /> + </TabsContent> + <TabsContent value="signup"> + <SignUp /> + </TabsContent> + </Tabs> + ); +} |
