From 64d67dbb37d8339a4cca0bdf4ca91d4b26e551e1 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:12:12 +0530 Subject: [PATCH 01/10] Add framer-motion and react-icons dependencies --- package-lock.json | 34 ++++++++++++++++++++++++++++++++++ package.json | 2 ++ 2 files changed, 36 insertions(+) diff --git a/package-lock.json b/package-lock.json index 21c9e00..ee37443 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "bullmq": "^5.13.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "framer-motion": "^11.9.0", "ioredis": "^5.4.1", "jest": "^29.7.0", "lodash.debounce": "^4.0.8", @@ -39,6 +40,7 @@ "react": "^18", "react-dom": "^18", "react-email": "^3.0.1", + "react-icons": "^5.3.0", "resend": "^4.0.0", "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7", @@ -6139,6 +6141,30 @@ "node": ">=12.20.0" } }, + "node_modules/framer-motion": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.9.0.tgz", + "integrity": "sha512-nCfGxvsQecVLjjYDu35G2F5ls+ArE3FBfhxV0RSiisMaUKqteq5DMBFNRKwMyVj+VqKTNhawt+BV480YCHKFlQ==", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10070,6 +10096,14 @@ "semver": "bin/semver.js" } }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index fb5f991..b128735 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "bullmq": "^5.13.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "framer-motion": "^11.9.0", "ioredis": "^5.4.1", "jest": "^29.7.0", "lodash.debounce": "^4.0.8", @@ -42,6 +43,7 @@ "react": "^18", "react-dom": "^18", "react-email": "^3.0.1", + "react-icons": "^5.3.0", "resend": "^4.0.0", "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7", From 3186222657dc98a1be3d6f79180c22341f7ab58c Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:13:02 +0530 Subject: [PATCH 02/10] Refactor middleware to include admin role check --- src/middleware.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index 3ad4bba..18a1562 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -5,17 +5,17 @@ import { getToken } from "next-auth/jwt"; // This function can be marked `async` if using `await` inside export async function middleware(request: NextRequest) { - const token = await getToken({ req: request }); - const url = request.nextUrl; + const token = await getToken({ req: request }); + const url = request.nextUrl; - if (url.pathname === "/admin") { - if (token?.role!=="ADMIN") { - return NextResponse.redirect(new URL("/", request.url)); + if (url.pathname.includes("/admin")) { + if (token?.role !== "ADMIN") { + return NextResponse.redirect(new URL("/", request.url)); + } } - } } // See "Matching Paths" below to learn more export const config = { - matcher: ["/:path*", "/"], -}; \ No newline at end of file + matcher: ["/:path*", "/"], +}; From 2cd582df68f2ac09f7b55a072e28f2d65211eb28 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:13:08 +0530 Subject: [PATCH 03/10] Add getUserById function to fetch user details by ID --- src/app/actions/get-user-by-id.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/app/actions/get-user-by-id.ts diff --git a/src/app/actions/get-user-by-id.ts b/src/app/actions/get-user-by-id.ts new file mode 100644 index 0000000..a79c5c9 --- /dev/null +++ b/src/app/actions/get-user-by-id.ts @@ -0,0 +1,13 @@ +import prisma from "@/server/db"; // Adjust the import based on your structure + +export async function getUserById(userId: string) { + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { + id: true, + role: true, // Include any other fields you need + }, + }); + + return user; +} From 7bad0c2dad0f463bbf5458ce9ba99bf8b985b392 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:13:20 +0530 Subject: [PATCH 04/10] Add global CSS styles for admin panel --- src/app/admin/globals.css | 88 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/app/admin/globals.css diff --git a/src/app/admin/globals.css b/src/app/admin/globals.css new file mode 100644 index 0000000..f4447b4 --- /dev/null +++ b/src/app/admin/globals.css @@ -0,0 +1,88 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} + +@layer utilities { + .text-balance { + text-wrap: balance; + } +} + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem; + } + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} From 72ff748fabc01f99681173419b05766c31ac59ea Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:13:37 +0530 Subject: [PATCH 05/10] Layout for admin --- src/app/admin/layout.tsx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/app/admin/layout.tsx diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx new file mode 100644 index 0000000..eb9547e --- /dev/null +++ b/src/app/admin/layout.tsx @@ -0,0 +1,27 @@ +"use client"; +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; +import Providers from "@/components/Layout/Provider"; +import { AdminNavbar } from "@/components/Admin/Navbar/navbar"; + +const inter = Inter({ subsets: ["latin"] }); + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + +
+ + {children} +
+
+ + + ); +} From c351f9aadd2e8b7ce93040b8da8911150970f5d7 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:13:43 +0530 Subject: [PATCH 06/10] Add admin navbar component --- src/components/Admin/Navbar/navbar.tsx | 177 +++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/components/Admin/Navbar/navbar.tsx diff --git a/src/components/Admin/Navbar/navbar.tsx b/src/components/Admin/Navbar/navbar.tsx new file mode 100644 index 0000000..438bbaf --- /dev/null +++ b/src/components/Admin/Navbar/navbar.tsx @@ -0,0 +1,177 @@ +"use client"; +import React, { Dispatch, SetStateAction, useState } from "react"; +import { IconType } from "react-icons"; +import { FiChevronDown, FiChevronsRight, FiUser } from "react-icons/fi"; +import { RiCoupon3Line } from "react-icons/ri"; +import { motion } from "framer-motion"; +import Link from "next/link"; +import Image from "next/image"; + +export const AdminNavbar = () => { + return ( +
+ + +
+ ); +}; + +const Sidebar = () => { + const [open, setOpen] = useState(true); + const [selected, setSelected] = useState("Dashboard"); + + return ( + + + +
+
+ + +
+ ); +}; + +const Option = ({ + Icon, + title, + selected, + setSelected, + open, + notifs, + href, +}: { + Icon: IconType; + title: string; + selected: string; + setSelected: Dispatch>; + open: boolean; + notifs?: number; + href?: string; +}) => { + return ( + + setSelected(title)} + className={`relative flex h-10 w-full items-center rounded-md transition-colors ${ + selected === title ? "bg-indigo-100 text-indigo-800" : "text-slate-500 hover:bg-slate-100" + }`} + > + + + + {open && ( + + {title} + + )} + + {notifs && open && ( + + {notifs} + + )} + + + ); +}; + +const TitleSection = ({ open }: { open: boolean }) => { + return ( +
+
+
+ + {open && ( + + Tedxsjec + Admin Page + + )} +
+ {open && } +
+
+ ); +}; + +const Logo = () => { + // Temp logo from https://logoipsum.com/ + return ( + + logo + + ); +}; + +const ToggleClose = ({ open, setOpen }: { open: boolean; setOpen: Dispatch> }) => { + return ( + setOpen((pv) => !pv)} + className="absolute bottom-0 left-0 right-0 border-t border-slate-300 transition-colors hover:bg-slate-100" + > +
+ + + + {open && ( + + Hide + + )} +
+
+ ); +}; + +const NavbarContent = () =>
; From 73b60c57a2a836577c6f22fae0235e9cfe55f580 Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:14:00 +0530 Subject: [PATCH 07/10] Refactor authOptions to update user role in token if ID is provided --- src/lib/auth-options.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/auth-options.ts b/src/lib/auth-options.ts index 7ae3e61..11e253a 100644 --- a/src/lib/auth-options.ts +++ b/src/lib/auth-options.ts @@ -5,6 +5,7 @@ import { PrismaAdapter } from "@next-auth/prisma-adapter"; import prisma from "@/server/db"; import { UserRoleType } from "@/types"; import { JWT } from "next-auth/jwt"; +import { getUserById } from "@/app/actions/get-user-by-id"; declare module "next-auth" { interface Session { @@ -39,6 +40,13 @@ export const authOptions: NextAuthOptions = { role: user.role, }; } + if (token.id) { + const updatedUser = await getUserById(token.id); + return { + ...token, + role: updatedUser?.role, + }; + } return token; }, async session({ session, token }: { session: NextAuthSession; token: JWT }): Promise { From c202a2a7963f68777606b1281f4c5ea95c8163ed Mon Sep 17 00:00:00 2001 From: vyshnav Date: Sat, 28 Sep 2024 16:15:16 +0530 Subject: [PATCH 08/10] Refactor admin navbar component and update logo styling --- src/components/Admin/Navbar/navbar.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/Admin/Navbar/navbar.tsx b/src/components/Admin/Navbar/navbar.tsx index 438bbaf..5b7cbce 100644 --- a/src/components/Admin/Navbar/navbar.tsx +++ b/src/components/Admin/Navbar/navbar.tsx @@ -5,7 +5,6 @@ import { FiChevronDown, FiChevronsRight, FiUser } from "react-icons/fi"; import { RiCoupon3Line } from "react-icons/ri"; import { motion } from "framer-motion"; import Link from "next/link"; -import Image from "next/image"; export const AdminNavbar = () => { return ( @@ -141,8 +140,21 @@ const TitleSection = ({ open }: { open: boolean }) => { const Logo = () => { // Temp logo from https://logoipsum.com/ return ( - - logo + + + + + ); }; From 10d76a11330ecb5ed33a744f53f20dcf7266b02c Mon Sep 17 00:00:00 2001 From: Vyshnav <120462272+Vyshnav001@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:17:09 +0530 Subject: [PATCH 09/10] Update auth-options.ts --- src/lib/auth-options.ts | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/lib/auth-options.ts b/src/lib/auth-options.ts index 514d195..11e253a 100644 --- a/src/lib/auth-options.ts +++ b/src/lib/auth-options.ts @@ -1,8 +1,4 @@ -import { - DefaultSession, - type NextAuthOptions, - type Session as NextAuthSession, -} from "next-auth"; +import { DefaultSession, type NextAuthOptions, type Session as NextAuthSession } from "next-auth"; import NextAuth from "next-auth/next"; import GoogleProvider from "next-auth/providers/google"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; @@ -12,18 +8,18 @@ import { JWT } from "next-auth/jwt"; import { getUserById } from "@/app/actions/get-user-by-id"; declare module "next-auth" { - interface Session { - user: { - id: string; - role: UserRoleType; - } & DefaultSession["user"]; - } + interface Session { + user: { + id: string; + role: UserRoleType; + } & DefaultSession["user"]; + } } declare module "next-auth/jwt" { - interface JWT { - role: UserRoleType; - } + interface JWT { + role: UserRoleType; + } } export const authOptions: NextAuthOptions = { @@ -64,15 +60,13 @@ export const authOptions: NextAuthOptions = { }, }; }, - }; }, - }, - session: { - strategy: "jwt", - }, - secret: process.env.NEXTAUTH_SECRET, - // debug: process.env.NODE_ENV === "development", + session: { + strategy: "jwt", + }, + secret: process.env.NEXTAUTH_SECRET, + // debug: process.env.NODE_ENV === "development", }; export const handlers = NextAuth(authOptions); From 19cb6dfc91755e2041f007404b712c54ae75487f Mon Sep 17 00:00:00 2001 From: Vyshnav <120462272+Vyshnav001@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:19:35 +0530 Subject: [PATCH 10/10] Update middleware.ts --- src/middleware.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/middleware.ts b/src/middleware.ts index 43b5b85..5872c07 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,14 +7,15 @@ import { getToken } from "next-auth/jwt"; export async function middleware(request: NextRequest) { const token = await getToken({ req: request }); const url = request.nextUrl; - + if (url.pathname.startsWith("/admin")) { if (token?.role !== "ADMIN") { return NextResponse.redirect(new URL("/", request.url)); } + } +} // See "Matching Paths" below to learn more export const config = { - matcher: ["/:path*", "/"], };