-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #282 from ShivanshPlays/admin-FE
- Loading branch information
Showing
4 changed files
with
244 additions
and
46 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,30 @@ | ||
'use server'; | ||
import { generateAndSendOTP } from '@/lib/auth'; | ||
import prismadb from '@/lib/prismadb'; | ||
import { Prisma, Admin } from '@prisma/client'; | ||
|
||
export async function AdminVerify({ | ||
email, | ||
}: { | ||
email: string; | ||
}): Promise<{ success: boolean; error?: string; data?: Admin }> { | ||
const exitingAdmin = await prismadb.admin.findUnique({ | ||
where: { | ||
email: email, | ||
}, | ||
}); | ||
|
||
if (!exitingAdmin) { | ||
return { | ||
success: false, | ||
error: 'Admin does not exists', | ||
}; | ||
} | ||
const resp = await generateAndSendOTP(email, 'admin'); | ||
|
||
if (!resp) { | ||
return { success: false, error: 'Error occured in sending otp' }; | ||
} | ||
|
||
return { success: true }; | ||
} |
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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
const AdminPage = () => { | ||
return ( | ||
<div> hi from admin</div> | ||
<div>hiiii</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 |
---|---|---|
@@ -1,15 +1,17 @@ | ||
"use client"; | ||
'use client'; | ||
|
||
import * as React from "react"; | ||
import { Button } from "@/components/ui/button"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
import { Spinner } from "@/components/ui/spinner"; | ||
import { cn } from "@/lib/utils"; | ||
import toast, { Toaster } from "react-hot-toast"; | ||
import * as React from 'react'; | ||
import { Button } from '@/components/ui/button'; | ||
import { Input } from '@/components/ui/input'; | ||
import { Label } from '@/components/ui/label'; | ||
import { Spinner } from '@/components/ui/spinner'; | ||
import { OtpForm } from './otp-form'; | ||
import { AdminVerify } from '@/actions/Admin/admin-login'; | ||
import { cn } from '@/lib/utils'; | ||
import toast, { Toaster } from 'react-hot-toast'; | ||
|
||
interface AdminAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { | ||
authType: "signup" | "login"; | ||
authType: 'signup' | 'login'; | ||
} | ||
|
||
export function AdminLoginForm({ | ||
|
@@ -18,52 +20,72 @@ export function AdminLoginForm({ | |
...props | ||
}: AdminAuthFormProps) { | ||
const [isLoading, setIsLoading] = React.useState<boolean>(false); | ||
const [email, setEmail] = React.useState(""); | ||
const [email, setEmail] = React.useState(''); | ||
const [otpOpen, setOtpOpen] = React.useState(false); | ||
|
||
async function onSubmit(event: React.SyntheticEvent) { | ||
event.preventDefault(); | ||
setIsLoading(true); | ||
|
||
setIsLoading(false); | ||
if (!email) { | ||
toast.error('Please enter an email.'); | ||
setIsLoading(false); | ||
return; | ||
} | ||
|
||
try { | ||
const res = await AdminVerify({ email }); | ||
|
||
if (!res.success) { | ||
toast.error(res.error || 'Error verifying admin.'); | ||
setIsLoading(false); | ||
return; | ||
} | ||
|
||
toast.success('Admin verified! Please enter the OTP.'); | ||
setOtpOpen(true); | ||
} catch (error) { | ||
toast.error('Verification failed, please try again.'); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
} | ||
|
||
return ( | ||
<div className={cn("grid gap-6", className)} {...props}> | ||
<div className={cn('grid gap-6', className)} {...props}> | ||
<Toaster /> | ||
|
||
<form onSubmit={onSubmit}> | ||
<div className="grid gap-2"> | ||
<div className="grid gap-1"> | ||
<Label className="sr-only" htmlFor="email"> | ||
</Label> | ||
<Input | ||
id="email" | ||
placeholder="[email protected]" | ||
type="email" | ||
autoCapitalize="none" | ||
autoComplete="email" | ||
autoCorrect="off" | ||
disabled={isLoading} | ||
value={email} | ||
onChange={(e) => setEmail(e.target.value)} | ||
/> | ||
{!otpOpen && ( | ||
<form onSubmit={onSubmit}> | ||
<div className="grid gap-2"> | ||
<div className="grid gap-1"> | ||
<Label className="sr-only" htmlFor="email"> | ||
</Label> | ||
<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" className="bg-gradient-to-r from-purple-600 via-blue-600 to-indigo-600" disabled={isLoading}> | ||
{isLoading ? ( | ||
<Spinner className="mr-2" /> | ||
) : authType === 'signup' ? ( | ||
'Sign Up with Email' | ||
) : ( | ||
'Sign In with Email' | ||
)} | ||
</Button> | ||
</div> | ||
<Button | ||
type="submit" | ||
className="bg-gradient-to-r from-purple-600 via-blue-600 to-indigo-600" | ||
disabled={isLoading} | ||
> | ||
{isLoading ? ( | ||
<Spinner className="mr-2" /> | ||
) : authType === "signup" ? ( | ||
"Sign Up with Email" | ||
) : ( | ||
"Sign In with Email" | ||
)} | ||
</Button> | ||
</div> | ||
</form> | ||
</form> | ||
)} | ||
{otpOpen && <OtpForm email={email} setOtpOpen={setOtpOpen} roleType="admin" />} | ||
</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,146 @@ | ||
'use client'; | ||
|
||
import { | ||
InputOTP, | ||
InputOTPGroup, | ||
InputOTPSlot, | ||
} from '@/components/ui/input-otp'; | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from '@/components/ui/form'; | ||
import { z } from 'zod'; | ||
import { zodResolver } from '@hookform/resolvers/zod'; | ||
import * as React from 'react'; | ||
import { cn } from '@/lib/utils'; | ||
import { Button } from '@/components/ui/button'; | ||
import { Toaster, toast } from 'react-hot-toast'; | ||
import { signIn, useSession } from 'next-auth/react'; | ||
import { useForm } from 'react-hook-form'; | ||
import { ChevronLeftCircleIcon } from 'lucide-react'; | ||
import { useRouter } from 'next/navigation'; // use 'next/navigation' for Next.js 13 App Router | ||
|
||
interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> { | ||
roleType: 'user' | 'seller' | 'admin'; | ||
email: string; | ||
setOtpOpen: (otp: boolean) => void; | ||
} | ||
|
||
const FormSchema = z.object({ | ||
pin: z | ||
.string() | ||
.length(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 [redirectUrl, setRedirectUrl] = React.useState<string | null>(null); | ||
const { data: session } = useSession(); // Access the session | ||
const router = useRouter(); | ||
|
||
const form = useForm<z.infer<typeof FormSchema>>({ | ||
resolver: zodResolver(FormSchema), | ||
defaultValues: { pin: '' }, | ||
}); | ||
|
||
async function onOTPSubmit(data: z.infer<typeof FormSchema>) { | ||
setIsLoading(true); | ||
|
||
console.log(email,data,roleType) | ||
|
||
|
||
const result = await signIn('credentials', { | ||
email, | ||
otp: data.pin, | ||
role: roleType, | ||
redirect: false, | ||
}); | ||
console.log(result) | ||
if (!result?.ok) { | ||
toast.error('Invalid email or OTP'); | ||
} else { | ||
toast.success('Welcome!'); | ||
|
||
// Set redirect URL based on user role | ||
if (roleType === 'user') { | ||
setRedirectUrl('/'); // Redirect to home for user | ||
} else if (roleType === 'seller') { | ||
setRedirectUrl(`/seller/${email}`); // Temporarily set to seller's page | ||
} | ||
else{ | ||
setRedirectUrl(`/admin/${email}`); | ||
} | ||
} | ||
setIsLoading(false); | ||
} | ||
|
||
React.useEffect(() => { | ||
if (redirectUrl && session) { | ||
const userId = session.user?.id; | ||
const userRole = session.user?.role; | ||
|
||
if (userRole === "seller" && userId) { | ||
router.push(`/seller/${userId}`); // Redirect to seller's page | ||
} else if (userRole === "user") { | ||
router.push(redirectUrl); // Redirect to the specified URL or home for a user | ||
} else if (userRole === "admin") { | ||
router.push(`/admin/${userId}`); // Redirect to admin dashboard | ||
} | ||
} | ||
}, [redirectUrl, session, router]); | ||
|
||
|
||
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 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> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button className="bg-gradient-to-r from-purple-600 via-blue-600 to-indigo-600 w-full" type="submit" disabled={isLoading}> | ||
{isLoading ? 'Loading...' : 'Submit'} | ||
</Button> | ||
</form> | ||
</Form> | ||
</div> | ||
); | ||
} |