Skip to content

Commit

Permalink
Merge pull request #282 from ShivanshPlays/admin-FE
Browse files Browse the repository at this point in the history
  • Loading branch information
Vimall03 authored Nov 10, 2024
2 parents 66ed023 + a592a9d commit c3a099b
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 46 deletions.
30 changes: 30 additions & 0 deletions alimento-nextjs/actions/Admin/admin-login.tsx
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 };
}
2 changes: 1 addition & 1 deletion alimento-nextjs/app/admin/[adminId]/page.tsx
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>
);
}

Expand Down
112 changes: 67 additions & 45 deletions alimento-nextjs/app/admin/auth/components/login-form.tsx
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({
Expand All @@ -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">
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">
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>
);
}
146 changes: 146 additions & 0 deletions alimento-nextjs/app/admin/auth/components/otp-form.tsx
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>
);
}

0 comments on commit c3a099b

Please sign in to comment.