aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/signin/CredentialsForm.tsx
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-13 21:43:44 +0000
committerMohamed Bassem <me@mbassem.com>2024-03-14 16:40:45 +0000
commit04572a8e5081b1e4871e273cde9dbaaa44c52fe0 (patch)
tree8e993acb732a50d1306d4d6953df96c165c57f57 /apps/web/components/signin/CredentialsForm.tsx
parent2df08ed08c065e8b91bc8df0266bd4bcbb062be4 (diff)
downloadkarakeep-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.tsx222
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>
+ );
+}