Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin: schema , admin Role Type-in nextauth , loginPage , auth.ts modification #281

Merged
merged 1 commit into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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