Skip to content

Commit

Permalink
Merge pull request #281 from ShivanshPlays/admin-BE
Browse files Browse the repository at this point in the history
  • Loading branch information
Vimall03 authored Nov 10, 2024
2 parents 0ad1269 + a7920bc commit 66ed023
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 30 deletions.
7 changes: 7 additions & 0 deletions alimento-nextjs/app/admin/[adminId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const AdminPage = () => {
return (
<div> hi from admin</div>
);
}

export default AdminPage;
69 changes: 69 additions & 0 deletions alimento-nextjs/app/admin/auth/components/login-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"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";

interface AdminAuthFormProps extends React.HTMLAttributes<HTMLDivElement> {
authType: "signup" | "login";
}

export function AdminLoginForm({
className,
authType,
...props
}: AdminAuthFormProps) {
const [isLoading, setIsLoading] = React.useState<boolean>(false);
const [email, setEmail] = React.useState("");

async function onSubmit(event: React.SyntheticEvent) {
event.preventDefault();
setIsLoading(true);

setIsLoading(false);
}

return (
<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)}
/>
</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>
</div>
);
}
45 changes: 45 additions & 0 deletions alimento-nextjs/app/admin/auth/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Metadata } from 'next';
import Image from 'next/image';
import { AdminLoginForm } from '@/app/admin/auth/components/login-form';

export const metadata: Metadata = {
title: 'Authentication',
description: 'Authentication forms built using the components.',
};

export default function AuthenticationPage() {
return (
<>
<div className="flex flex-col md:flex-row items-center justify-center min-h-screen bg-gradient-to-r from-purple-600 via-blue-600 to-indigo-600">
{/* Background Image Section for larger screens */}

<Image
src="/adminLogin.png"
width={1280}
height={843}
alt="Authentication"
className="object-contain w-2/4 h-2/4 rounded-xl"
/>


{/* Main Content Section */}
<div className="z-10 w-full max-w-2xl px-6 py-8 mx-auto text-white rounded-xl bg-black bg-opacity-70">
<div className="space-y-6">
{/* Title and Description */}
<div className="text-center">
<h1 className="text-3xl font-semibold">Welcome Back, Admin!</h1>
<p className="text-sm text-muted-foreground">Enter your credentials to access your admin panel.</p>
</div>

{/* Admin Login Form */}
<AdminLoginForm className='w-full' authType="login" />

{/* Alternative Links
<div className="flex justify-between text-sm text-center text-white">
</div> */}
</div>
</div>
</div>
</>
);
}
98 changes: 71 additions & 27 deletions alimento-nextjs/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
import CredentialsProvider from 'next-auth/providers/credentials';
import { NextAuthOptions } from 'next-auth';
import prismadb from './prismadb';
import sendEmail from './sendEmail';

import CredentialsProvider from "next-auth/providers/credentials";
import { NextAuthOptions } from "next-auth";
import sendEmail from "@/lib/sendEmail"; // Ensure this points to your sendEmail function
import prismadb from "./prismadb";

// const prisma = new PrismaClient();

export const NEXT_AUTH_CONFIG: NextAuthOptions = {
providers: [
CredentialsProvider({
name: 'Credentials',
name: "Credentials",
credentials: {
email: { label: 'Email', type: 'text' },
otp: { label: 'OTP', type: 'text' },
role: { label: 'Role', type: 'text' },
email: { label: "Email", type: "text" },
otp: { label: "OTP", type: "text" },
role: { label: "Role", type: "text" },
},
async authorize(credentials) {

console.log(credentials+"controlp0")

if (!credentials?.email || !credentials?.otp || !credentials?.role) {
throw new Error('Invalid credentials');
throw new Error("Invalid credentials");
}

console.log(credentials)

console.log(credentials+"control1")
let account;
if (credentials.role === 'customer') {
if (credentials.role === "customer") {
account = await prismadb.customer.findUnique({
where: { email: credentials.email },
});
} else {
} else if (credentials.role === "vendor"){
account = await prismadb.vendor.findUnique({
where: { email: credentials.email },
});
}else if (credentials.role === "admin"){
account = await prismadb.admin.findUnique({
where: { email: credentials.email },
});
}
else{
return null
}

console.log(account+"control2")

if (!account) {
return null;
}
Expand All @@ -42,23 +58,33 @@ export const NEXT_AUTH_CONFIG: NextAuthOptions = {

const updateData = { otp: null };
// Clear OTP after successful login
if (credentials.role === 'customer') {
if (credentials.role === "customer") {
await prismadb.customer.update({
where: { email: credentials.email },
data: updateData, // Reset OTP or delete it after use
});
} else {
} else if(credentials.role === "vendor"){
await prismadb.vendor.update({
where: { email: credentials.email },
data: updateData, // Reset OTP or delete it after use
});
}else if (credentials.role === "admin"){
await prismadb.admin.update({
where: { email: credentials.email },
data: updateData, // Reset OTP or delete it after use
});
}
else{
return null
}

const role = account.role == "customer" ? "customer" : account.role == "vendor"? "vendor" : "admin"

return {
id: account.id,
name: account.name,
email: account.email,
role: account.role == 'customer' ? 'customer' : 'vendor',
role: role
};
},
}),
Expand All @@ -82,37 +108,52 @@ export const NEXT_AUTH_CONFIG: NextAuthOptions = {
},
};


// Function to generate and send OTP
export const generateAndSendOTP = async (
email: string,
role: 'vendor' | 'customer'
role: string
) => {
const otp = Math.floor(100000 + Math.random() * 900000).toString(); // Generate 6-digit OTP

// Store OTP in the customer or vendor record
// Store OTP in the user or vendor record

if (role === 'customer') {
if (role === "user") {
try {
await prismadb.customer.update({
where: { email },
data: { otp }, // Ensure 'otp' field exists in your customer model
data: { otp }, // Ensure 'otp' field exists in your User model
});
} catch (err) {
console.error(
'DB Error sending OTP for customer:',
"DB Error sending OTP for user:",
err instanceof Error ? err.message : err
);
return false;
}
} else if (role === 'vendor') {
} else if (role === "vendor") {
try {
await prismadb.vendor.update({
where: { email },
data: { otp },
data: { otp }, // Ensure 'otp' field exists in your User model
});
} catch (err) {
console.error(
'DB Error sending OTP for vendor:',
"DB Error sending OTP for vendor:",
err instanceof Error ? err.message : err
);
return false;
}
}

else if (role === "admin") {
try {
await prismadb.admin.update({
where: { email },
data: { otp }, // Ensure 'otp' field exists in your User model
});
} catch (err) {
console.error(
"DB Error sending OTP for admin:",
err instanceof Error ? err.message : err
);
return false;
Expand All @@ -122,18 +163,21 @@ export const generateAndSendOTP = async (
try {
const response = await sendEmail({
to: email,
subject: 'Your OTP Code',
subject: "Your OTP Code",
text: `Your OTP code is ${otp}`,
html: `<strong>Your OTP code is ${otp}</strong>`,
});

console.log('OTP email sent successfully:', response);
console.log("OTP email sent successfully:", response);
return true;
// Handle success response if needed (e.g., logging messageId)
} catch (err) {
console.error(
'Error sending OTP:',
"Error sending OTP:",
err instanceof Error ? err.message : err
);
return false;
}
};
};

// Call generateAndSendOTP(email) before redirecting to the login page to send OTP to the user
12 changes: 12 additions & 0 deletions alimento-nextjs/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ datasource db {
url = env("DATABASE_URL")
}

model Admin {
id String @id @default(uuid()) @map("_id")
name String?
email String? @unique
otp String?
role String @default("admin")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Customer {
id String @id @default(uuid()) @map("_id")
name String
Expand Down
Binary file added alimento-nextjs/public/adminLogin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions alimento-nextjs/types/next-auth.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ declare module 'next-auth' {
id: string;
name?: string;
email?: string;
role: 'customer' | 'vendor'; // Extend with the role property
role: 'customer' | 'vendor' | 'admin'; // Extend with the role property
};
}

interface User extends DefaultUser {
role: 'customer' | 'vendor'; // Add role to User object
role: 'customer' | 'vendor' | 'admin'; // Add role to User object
}
}

declare module 'next-auth/jwt' {
interface JWT {
uid: string;
role: 'customer' | 'vendor'; // Add role to JWT token
role: 'customer' | 'vendor' | 'admin'; // Add role to JWT token
}
}

Expand Down

0 comments on commit 66ed023

Please sign in to comment.