-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initialised next app and added homepage * setup email, prisma, DB schema, nextAUTH * fic * seller signup * merge
- Loading branch information
1 parent
f409745
commit 12eb665
Showing
25 changed files
with
1,184 additions
and
123 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,52 @@ | ||
"use server" | ||
import { generateAndSendOTP } from '@/lib/auth'; | ||
import prismadb from '@/lib/prismadb'; | ||
import { Prisma, Seller } from '@prisma/client'; | ||
|
||
export async function SellerCreate({ | ||
name,email | ||
}:{ | ||
name:string, | ||
email:string | ||
}): Promise<{ success: boolean; error?: string ; data?:Seller}> { | ||
|
||
const exitingSeller = await prismadb.seller.findUnique({ | ||
where: { | ||
email: email, | ||
}, | ||
}); | ||
|
||
if (exitingSeller) { | ||
return { | ||
success: false, | ||
error: 'seller already exists', | ||
}; | ||
} | ||
|
||
try { | ||
const res = await prismadb.seller.create({ | ||
data: { | ||
name: name, | ||
email: email, | ||
}, | ||
}); | ||
|
||
if(!res){ | ||
return {success:false, error:"Error occured in seller creation"}; | ||
} | ||
|
||
const resp=await generateAndSendOTP(res.email,"seller"); | ||
|
||
if(!resp){ | ||
return {success:false, error:"Error occured in sending otp"}; | ||
} | ||
|
||
return { success: true , data:res}; | ||
|
||
} catch (err) { | ||
if (err instanceof Prisma.PrismaClientKnownRequestError) { | ||
console.log(err.message); | ||
} | ||
return { success: false, error: 'An unexpected error occurred.' }; | ||
} | ||
} |
135 changes: 135 additions & 0 deletions
135
scruter-nextjs/app/(routes)/auth/components/otp-form.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,135 @@ | ||
'use client'; | ||
|
||
import { | ||
InputOTP, | ||
InputOTPGroup, | ||
InputOTPSeparator, | ||
InputOTPSlot, | ||
} from '@/components/ui/input-otp'; | ||
|
||
import { | ||
Form, | ||
FormControl, | ||
FormDescription, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form"; | ||
|
||
import { z } from "zod"; | ||
|
||
import * as React from 'react'; | ||
|
||
import { cn } from '@/lib/utils'; | ||
import { Icons } from '@/components/ui/icons'; | ||
import { Label } from '@/components/ui/label'; | ||
import { Input } from '@/components/ui/input'; | ||
import { Button } from '@/components/ui/button'; | ||
import { Toaster, toast } from 'react-hot-toast'; | ||
import { SellerCreate } from '@/actions/seller/signup-action'; | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
|
||
import { signIn } from "next-auth/react"; | ||
import { useForm } from 'react-hook-form'; | ||
import { ChevronLeftCircleIcon } from 'lucide-react'; | ||
|
||
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { | ||
roleType: 'user' | 'seller'; | ||
email:string; | ||
setOtpOpen:(otp:boolean)=>void | ||
} | ||
|
||
const FormSchema = z.object({ | ||
pin: z.string().min(6, { | ||
message: "Your one-time password must be 6 characters.", | ||
}), | ||
}); | ||
|
||
|
||
export function OtpForm({ | ||
className, | ||
roleType, | ||
email, | ||
setOtpOpen, | ||
...props | ||
}: UserAuthFormProps) { | ||
const [isLoading, setIsLoading] = React.useState<boolean>(false); | ||
|
||
const form = useForm<z.infer<typeof FormSchema>>({ | ||
resolver: zodResolver(FormSchema), | ||
defaultValues: { | ||
pin: "", | ||
}, | ||
}); | ||
|
||
async function onOTPSubmit(data: z.infer<typeof FormSchema>) { | ||
// console.log(data.pin+email); | ||
setIsLoading(true); | ||
|
||
// toast.success(data.pin) | ||
const result = await signIn("credentials", { | ||
email, | ||
otp: data.pin, | ||
role: "seller", | ||
redirect: false, | ||
}); | ||
console.log(result); | ||
if (!result?.ok) { | ||
toast.error("Invalid email or otp"); | ||
} else { | ||
toast.success(`Welcome!`); | ||
|
||
// setTimeout(() => { | ||
// window.location.href = `"/`; // Redirect on success | ||
// }, 2000); | ||
} | ||
setIsLoading(false); | ||
} | ||
|
||
|
||
return ( | ||
<div className={cn('grid gap-6', className)} {...props}> | ||
<Toaster /> | ||
<Form {...form}> | ||
<form | ||
onSubmit={form.handleSubmit(onOTPSubmit)} | ||
className="flex flex-col dark:text-gray-200 z-10 items-start justify-center py-10 md:py-0 pl-14 gap-4 w-2/4" | ||
> | ||
<FormField | ||
control={form.control} | ||
name="pin" | ||
render={({ field }) => ( | ||
<FormItem className="flex gap-2 items-start justify-center flex-col"> | ||
<FormLabel className="text-2xl gap-2 flex items-center justify-center text-customTeal dark:text-Green font-bold"> | ||
<ChevronLeftCircleIcon onClick={()=>{setOtpOpen(false)}} className="h-5 w-5"/> | ||
One-Time Password | ||
</FormLabel> | ||
<FormControl> | ||
<InputOTP maxLength={6} {...field}> | ||
<InputOTPGroup> | ||
<InputOTPSlot index={0} /> | ||
<InputOTPSlot index={1} /> | ||
<InputOTPSlot index={2} /> | ||
<InputOTPSlot index={3} /> | ||
<InputOTPSlot index={4} /> | ||
<InputOTPSlot index={5} /> | ||
</InputOTPGroup> | ||
</InputOTP> | ||
</FormControl> | ||
<FormDescription> | ||
Please enter the one-time password sent to your email. | ||
</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
|
||
<Button className="bg-customTeal dark:bg-Green" type="submit"> | ||
Submit | ||
</Button> | ||
</form> | ||
</Form> | ||
</div> | ||
); | ||
} |
119 changes: 119 additions & 0 deletions
119
scruter-nextjs/app/(routes)/auth/components/signup-form.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,119 @@ | ||
'use client'; | ||
|
||
import { | ||
InputOTP, | ||
InputOTPGroup, | ||
InputOTPSeparator, | ||
InputOTPSlot, | ||
} from '@/components/ui/input-otp'; | ||
|
||
import * as React from 'react'; | ||
|
||
import { cn } from '@/lib/utils'; | ||
import { Icons } from '@/components/ui/icons'; | ||
import { Label } from '@/components/ui/label'; | ||
import { Input } from '@/components/ui/input'; | ||
import { Button } from '@/components/ui/button'; | ||
import { Toaster, toast } from 'react-hot-toast'; | ||
import { SellerCreate } from '@/actions/seller/signup-action'; | ||
import { OtpForm } from './otp-form'; | ||
|
||
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { | ||
authType: 'signup' | 'login'; | ||
} | ||
|
||
export function SellerSignupForm({ | ||
className, | ||
authType, | ||
...props | ||
}: UserAuthFormProps) { | ||
const [isLoading, setIsLoading] = React.useState<boolean>(false); | ||
|
||
const [name, setName] = React.useState(''); | ||
const [email, setEmail] = React.useState(''); | ||
const [otpOpen, setOtpOpen] = React.useState(false); | ||
|
||
async function onSubmit(event: React.SyntheticEvent) { | ||
event.preventDefault(); | ||
setIsLoading(true); | ||
|
||
if (!name || !email) { | ||
toast.error('missing details'); | ||
return; | ||
} | ||
// toast.success(name+email); | ||
const res = await SellerCreate({ | ||
name: name, | ||
email: email, | ||
}); | ||
|
||
if (!res.success && res.error) { | ||
toast.error(res.error); | ||
return; | ||
} | ||
|
||
toast.success('user created successfully, please enter OTP'); | ||
|
||
setOtpOpen(true); | ||
setIsLoading(false); | ||
} | ||
|
||
return ( | ||
<div className={cn('grid gap-6', className)} {...props}> | ||
<Toaster /> | ||
{!otpOpen && ( | ||
<form onSubmit={onSubmit}> | ||
<div className="grid gap-2"> | ||
<div className="grid gap-1"> | ||
<Label className="sr-only" htmlFor="email"> | ||
Name | ||
</Label> | ||
{/* : {name} */} | ||
<Input | ||
id="email" | ||
placeholder="John Doe" | ||
type="text" | ||
autoComplete="text" | ||
autoCorrect="off" | ||
disabled={isLoading} | ||
value={name} | ||
onChange={e => { | ||
setName(e.target.value); | ||
}} | ||
/> | ||
<Label className="sr-only" htmlFor="email"> | ||
</Label> | ||
{/* : {email} */} | ||
<Input | ||
id="email" | ||
placeholder="[email protected]" | ||
type="email" | ||
autoCapitalize="none" | ||
autoComplete="email" | ||
autoCorrect="off" | ||
disabled={isLoading} | ||
value={email} | ||
onChange={e => { | ||
setEmail(e.target.value); | ||
}} | ||
/> | ||
</div> | ||
<Button type="submit" disabled={isLoading}> | ||
{isLoading && ( | ||
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" /> | ||
)} | ||
{authType === 'signup' ? ( | ||
<p>Sign Up with Email</p> | ||
) : ( | ||
<p>Sign In with Email</p> | ||
)} | ||
</Button> | ||
</div> | ||
</form> | ||
)} | ||
|
||
{otpOpen && <OtpForm email={email} setOtpOpen={setOtpOpen} roleType='seller'/>} | ||
</div> | ||
); | ||
} |
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,79 @@ | ||
import { Metadata } from 'next'; | ||
import Image from 'next/image'; | ||
import Link from 'next/link'; | ||
|
||
import { cn } from '@/lib/utils'; | ||
import { buttonVariants } from '@/components/ui/button'; | ||
import { SellerSignupForm} from '../../components/signup-form'; | ||
|
||
export const metadata: Metadata = { | ||
title: 'Authentication', | ||
description: 'Authentication forms built using the components.', | ||
}; | ||
|
||
export default function AuthenticationPage() { | ||
return ( | ||
<> | ||
<div className="md:hidden"> | ||
<Image | ||
src="/signupPattern.svg" | ||
width={1280} | ||
height={843} | ||
alt="Authentication" | ||
className="block dark:hidden" | ||
/> | ||
<Image | ||
src="/signupPattern.svg" | ||
width={1280} | ||
height={843} | ||
alt="Authentication" | ||
className="hidden dark:block" | ||
/> | ||
</div> | ||
<div className="container relative hidden h-[700px] flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0"> | ||
<Link | ||
href="/auth/seller/login" | ||
className={cn( | ||
buttonVariants({ variant: 'ghost' }), | ||
'absolute right-4 top-4 md:right-8 md:top-8' | ||
)} | ||
> | ||
Login | ||
</Link> | ||
<div className={`hidden bg-[url("/signupPattern.svg")] bg-opacity-50 h-full flex-col p-10 text-white dark:border-r lg:flex`}> | ||
|
||
</div> | ||
<div className="lg:p-8"> | ||
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]"> | ||
<div className="flex flex-col space-y-2 text-center"> | ||
<h1 className="text-2xl font-semibold tracking-tight"> | ||
Create an account | ||
</h1> | ||
<p className="text-sm text-muted-foreground"> | ||
Enter your email below to create your account | ||
</p> | ||
</div> | ||
<SellerSignupForm authType='signup'/> | ||
<p className="px-8 text-center text-sm text-muted-foreground"> | ||
By clicking continue, you agree to our{' '} | ||
<Link | ||
href="/terms" | ||
className="underline underline-offset-4 hover:text-primary" | ||
> | ||
Terms of Service | ||
</Link>{' '} | ||
and{' '} | ||
<Link | ||
href="/privacy" | ||
className="underline underline-offset-4 hover:text-primary" | ||
> | ||
Privacy Policy | ||
</Link> | ||
. | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} |
Oops, something went wrong.