forked from vercel/commerce
-
Notifications
You must be signed in to change notification settings - Fork 0
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
21 changed files
with
1,070 additions
and
21 deletions.
There are no files selected for viewing
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,31 @@ | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardFooter, | ||
CardHeader, | ||
CardTitle | ||
} from '@/ui-components/ui/card'; | ||
import Link from 'next/link'; | ||
import {SignInForm} from "@/components/account/sign-in-form"; | ||
|
||
export default async function SignIn() { | ||
return ( | ||
<section className="flex mt-24 items-center justify-center"> | ||
<Card className="w-full max-w-sm"> | ||
<CardHeader> | ||
<CardTitle>Sign in</CardTitle> | ||
<CardDescription>Sign in to your account</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<SignInForm /> | ||
</CardContent> | ||
<CardFooter> | ||
<Link className="text-center text-neutral-500 underline" href="/forgot-password"> | ||
Forgot your password? | ||
</Link> | ||
</CardFooter> | ||
</Card> | ||
</section> | ||
); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
'use server'; | ||
|
||
import { authenticateCustomer } from '@/lib/vendure'; | ||
import { revalidateTag } from 'next/cache'; | ||
import { AUTH_COOKIE_KEY, TAGS } from '@/lib/constants'; | ||
import { cookies } from 'next/headers'; | ||
|
||
export type SignInState = | ||
| { | ||
type: 'success'; | ||
id: string; | ||
} | ||
| { | ||
type: 'error'; | ||
message: string; | ||
} | ||
| null; | ||
|
||
export async function signIn( | ||
prevState: SignInState | null, | ||
formData: FormData | ||
): Promise<SignInState> { | ||
const username = formData.get('username'); | ||
const password = formData.get('password'); | ||
|
||
if (!username || !password) { | ||
return { | ||
type: 'error', | ||
message: 'Missing username or password' | ||
}; | ||
} | ||
|
||
try { | ||
const res = await authenticateCustomer(username.toString(), password.toString()); | ||
revalidateTag(TAGS.customer); | ||
|
||
if (res.__typename === 'CurrentUser') { | ||
return { | ||
type: 'success', | ||
id: res.id | ||
}; | ||
} | ||
|
||
if (res.__typename === 'InvalidCredentialsError' || res.__typename === 'NotVerifiedError') { | ||
return { | ||
type: 'error', | ||
message: res.message | ||
}; | ||
} | ||
|
||
return { | ||
type: 'error', | ||
message: 'Error signing in' | ||
}; | ||
} catch (e) { | ||
return { | ||
type: 'error', | ||
message: 'Error signing in' | ||
}; | ||
} | ||
} |
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,14 @@ | ||
import { UserIcon } from '@heroicons/react/24/outline'; | ||
import clsx from 'clsx'; | ||
import Link from 'next/link'; | ||
|
||
export default function OpenSignIn({ className }: { className?: string }) { | ||
return ( | ||
<Link | ||
href={'/sign-in'} | ||
className="relative flex h-11 w-11 items-center justify-center rounded-md border border-neutral-200 text-black transition-colors dark:border-neutral-700 dark:text-white" | ||
> | ||
<UserIcon className={clsx('h-4 transition-all ease-in-out hover:scale-110', className)} /> | ||
</Link> | ||
); | ||
} |
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,94 @@ | ||
'use client'; | ||
|
||
import { z } from 'zod'; | ||
import { useForm } from 'react-hook-form'; | ||
import { zodResolver } from '@hookform/resolvers/zod'; | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage | ||
} from '@/ui-components/ui/form'; | ||
import { Input } from '@/ui-components/ui/input'; | ||
import { LoaderButton } from '@/components/loader-button'; | ||
import { signIn, SignInState } from '@/components/account/actions'; | ||
import { useActionState, useEffect, useTransition } from 'react'; | ||
import { useToast } from '@/ui-components/hooks/use-toast'; | ||
|
||
const formSchema = z.object({ | ||
username: z.string().min(3), | ||
password: z.string().min(6) | ||
}); | ||
|
||
type FormSchema = z.infer<typeof formSchema>; | ||
|
||
export function SignInForm() { | ||
const { toast } = useToast(); | ||
const form = useForm<FormSchema>({ | ||
mode: 'all', | ||
resolver: zodResolver(formSchema) | ||
}); | ||
const [state, formAction] = useActionState<SignInState, FormData>(signIn, null); | ||
const [pending, startTransaction] = useTransition(); | ||
|
||
useEffect(() => { | ||
if (state?.type === 'error') { | ||
toast({ | ||
variant: 'destructive', | ||
title: 'Error', | ||
description: state.message | ||
}); | ||
} else if (state?.type === 'success') { | ||
toast({ | ||
variant: 'default', | ||
title: 'Success', | ||
description: 'Welcome back!' | ||
}); | ||
} | ||
}, [state]); | ||
|
||
return ( | ||
<Form {...form}> | ||
<form | ||
action={(formData) => startTransaction(() => formAction(formData))} | ||
className="space-y-4" | ||
> | ||
<FormField | ||
control={form.control} | ||
name="username" | ||
render={({ field }) => { | ||
return ( | ||
<FormItem> | ||
<FormLabel>E-Mail</FormLabel> | ||
<FormControl> | ||
<Input placeholder="[email protected]" {...field} /> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
); | ||
}} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="password" | ||
render={({ field }) => { | ||
return ( | ||
<FormItem> | ||
<FormLabel>Password</FormLabel> | ||
<FormControl> | ||
<Input type="password" {...field} /> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
); | ||
}} | ||
/> | ||
<LoaderButton loading={pending} className="w-full" type="submit"> | ||
Sign in | ||
</LoaderButton> | ||
</form> | ||
</Form> | ||
); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { ComponentProps } from 'react'; | ||
import { Button } from '@/ui-components/ui/button'; | ||
import { CgSpinner } from 'react-icons/cg'; | ||
|
||
type LoaderButtonProps = { | ||
loading?: boolean; | ||
}; | ||
|
||
export function LoaderButton({ | ||
loading, | ||
children, | ||
...props | ||
}: LoaderButtonProps & ComponentProps<typeof Button>) { | ||
return ( | ||
<Button {...props} disabled={loading}> | ||
{loading ? <CgSpinner /> : children} | ||
</Button> | ||
); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import gql from 'graphql-tag'; | ||
|
||
export const authenticate = gql` | ||
mutation authenticate($input: AuthenticationInput!) { | ||
authenticate(input: $input) { | ||
... on CurrentUser { | ||
__typename | ||
id | ||
identifier | ||
} | ||
... on InvalidCredentialsError { | ||
__typename | ||
message | ||
} | ||
... on NotVerifiedError { | ||
__typename | ||
message | ||
} | ||
} | ||
} | ||
`; |
Oops, something went wrong.