-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
834 additions
and
489 deletions.
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
starters/shopify-algolia/components/modals/login-modal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod" | ||
import { useForm } from "react-hook-form" | ||
import { toast } from "sonner" | ||
import { z } from "zod" | ||
import { getCurrentUser, loginUser } from "app/actions/user.actions" | ||
import { Button } from "components/ui/button-old" | ||
import { DialogFooter } from "components/ui/dialog" | ||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "components/ui/form" | ||
import { GenericModal } from "components/generic-modal" | ||
import { Input } from "components/ui/input" | ||
import { Logo } from "components/logo" | ||
import { useModalStore } from "stores/modal-store" | ||
import { useUserStore } from "stores/user-store" | ||
|
||
const passwordRegexp = new RegExp(/(?=.*\d)(?=.*\W)(?=.*[a-z])(?=.*[A-Z]).{8,20}$/) | ||
|
||
const formSchema = z.object({ | ||
email: z.string().email().min(3).max(64), | ||
password: z.string().min(8).max(20).regex(passwordRegexp, "Password must have at least one number, one symbol, one uppercase letter, and be at least 8 characters"), | ||
}) | ||
|
||
const formFields = [ | ||
{ label: "Email", name: "email", type: "text", placeholder: "Enter email..." }, | ||
{ label: "Password", name: "password", type: "password", placeholder: "Enter password..." }, | ||
] as const | ||
|
||
export function LoginModal() { | ||
const setUser = useUserStore((s) => s.setUser) | ||
const modals = useModalStore((s) => s.modals) | ||
const closeModal = useModalStore((s) => s.closeModal) | ||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
}) | ||
|
||
async function onSubmit(payload: z.infer<typeof formSchema>) { | ||
const { email, password } = payload | ||
const user = await loginUser({ email, password }) | ||
|
||
if (user) { | ||
const currentUser = await getCurrentUser() | ||
currentUser && setUser(currentUser) | ||
|
||
toast.success("Successfully logged in") | ||
closeModal("login") | ||
|
||
return | ||
} | ||
|
||
form.setError("root", { message: "Couldn't log in. The email address or password is incorrect." }) | ||
} | ||
|
||
return ( | ||
<GenericModal title="Login" open={!!modals["login"]} onOpenChange={() => closeModal("login")}> | ||
<Form {...form}> | ||
<Logo className="mt-6 flex size-24 w-full justify-center" /> | ||
{form.formState.errors.root?.message && <p className="mt-6 w-full text-[14px] leading-tight tracking-tight text-red-400">{form.formState.errors.root?.message}</p>} | ||
<form name="loginForm" id="loginForm" onSubmit={form.handleSubmit(onSubmit)} className="space-y-1"> | ||
{formFields.map((singleField) => ( | ||
<FormField | ||
key={singleField.name} | ||
control={form.control} | ||
name={singleField.name} | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>{singleField.label}</FormLabel> | ||
<FormControl> | ||
<Input type={singleField.type} className="text-sm" placeholder={singleField.placeholder} {...field} /> | ||
</FormControl> | ||
<FormMessage className="text-xs font-normal text-red-400" /> | ||
</FormItem> | ||
)} | ||
/> | ||
))} | ||
</form> | ||
</Form> | ||
|
||
<DialogFooter> | ||
<Button | ||
size="lg" | ||
form="loginForm" | ||
className="hover:text-white" | ||
variant="secondary" | ||
isAnimated={false} | ||
type="submit" | ||
disabled={form.formState.isSubmitting} | ||
isLoading={form.formState.isSubmitting} | ||
> | ||
Submit | ||
</Button> | ||
</DialogFooter> | ||
</GenericModal> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
starters/shopify-algolia/components/modals/signup-modal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod" | ||
import { useForm } from "react-hook-form" | ||
import { toast } from "sonner" | ||
import { z } from "zod" | ||
import { getCurrentUser, signupUser } from "app/actions/user.actions" | ||
import { Button } from "components/ui/button-old" | ||
import { DialogFooter } from "components/ui/dialog" | ||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "components/ui/form" | ||
import { GenericModal } from "components/generic-modal" | ||
import { Input } from "components/ui/input" | ||
import { Logo } from "components/logo" | ||
import { useModalStore } from "stores/modal-store" | ||
import { useUserStore } from "stores/user-store" | ||
|
||
const passwordRegexp = new RegExp(/(?=.*\d)(?=.*\W)(?=.*[a-z])(?=.*[A-Z]).{8,20}$/) | ||
|
||
const formSchema = z.object({ | ||
email: z.string().email().min(3).max(64), | ||
password: z.string().min(8).max(20).regex(passwordRegexp, "Password must have at least one number, one symbol, one uppercase letter, and be at least 8 characters"), | ||
}) | ||
|
||
const formFields = [ | ||
{ label: "Email", name: "email", type: "text", placeholder: "Enter email..." }, | ||
{ label: "Password", name: "password", type: "password", placeholder: "Enter password..." }, | ||
] as const | ||
|
||
export function SignupModal() { | ||
const modals = useModalStore((s) => s.modals) | ||
const setUser = useUserStore((s) => s.setUser) | ||
const closeModal = useModalStore((s) => s.closeModal) | ||
const form = useForm<z.infer<typeof formSchema>>({ | ||
resolver: zodResolver(formSchema), | ||
}) | ||
|
||
async function onSubmit(payload: z.infer<typeof formSchema>) { | ||
const { email, password } = payload | ||
const user = await signupUser({ email, password }) | ||
|
||
if (user) { | ||
const currentUser = await getCurrentUser() | ||
currentUser && setUser(currentUser) | ||
|
||
closeModal("signup") | ||
toast.success("You have successfully signed up! You can now log in.") | ||
return | ||
} | ||
|
||
toast.error("Couldn't create user. The email address may be already in use.") | ||
} | ||
|
||
return ( | ||
<GenericModal title="Signup" open={!!modals["signup"]} onOpenChange={() => closeModal("signup")}> | ||
<Form {...form}> | ||
<Logo className="mt-6 flex size-24 w-full justify-center" /> | ||
{form.formState.errors.root?.message && <p className="mt-6 w-full text-[14px] leading-tight tracking-tight text-red-400">{form.formState.errors.root?.message}</p>} | ||
<form name="loginForm" id="loginForm" onSubmit={form.handleSubmit(onSubmit)} className="space-y-1"> | ||
{formFields.map((singleField) => ( | ||
<FormField | ||
key={singleField.name} | ||
control={form.control} | ||
name={singleField.name} | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>{singleField.label}</FormLabel> | ||
<FormControl> | ||
<Input type={singleField.type} className="text-sm" placeholder={singleField.placeholder} {...field} /> | ||
</FormControl> | ||
<FormMessage className="text-xs font-normal text-red-400" /> | ||
</FormItem> | ||
)} | ||
/> | ||
))} | ||
</form> | ||
</Form> | ||
|
||
<DialogFooter> | ||
<Button | ||
size="lg" | ||
form="loginForm" | ||
className="hover:text-white" | ||
variant="secondary" | ||
isAnimated={false} | ||
type="submit" | ||
disabled={form.formState.isSubmitting} | ||
isLoading={form.formState.isSubmitting} | ||
> | ||
Submit | ||
</Button> | ||
</DialogFooter> | ||
</GenericModal> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.