From a0426e8c8ac2f43b3eaf6a17e9e0e230b950053a Mon Sep 17 00:00:00 2001 From: Shaily Mishra Date: Sat, 18 Jul 2026 13:44:32 +0530 Subject: [PATCH] Authentication And Serive Engineer Portal is added --- app/api/auth/[...nextauth]/route.ts | 50 ++++ .../overview/serviceEngineer/page.tsx | 14 + app/dashboard/page.tsx | 18 +- app/layout.tsx | 8 +- app/page.tsx | 2 +- app/sessionWrapper.tsx | 14 + components/auth/loginForm.tsx | 8 +- components/auth/verifyCode.tsx | 5 +- components/dashboard/buildingOwner.tsx | 56 ++-- components/dashboard/engagement.tsx | 186 +++++++------- components/dashboard/propertyManager.tsx | 177 +++++++------ components/dashboard/serviceEngineer.tsx | 243 ++++++++++++++++++ components/dashboard/sidebar.tsx | 12 +- constants/constant.ts | 2 +- middleware.ts | 11 + package-lock.json | 172 +++++++++++++ package.json | 5 + 17 files changed, 762 insertions(+), 221 deletions(-) create mode 100644 app/api/auth/[...nextauth]/route.ts create mode 100644 app/sessionWrapper.tsx create mode 100644 components/dashboard/serviceEngineer.tsx create mode 100644 middleware.ts diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..200784e --- /dev/null +++ b/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,50 @@ + +import NextAuth, { NextAuthOptions } from "next-auth"; +import KeycloakProvider from "next-auth/providers/keycloak"; + + +export const authOptions: NextAuthOptions = { + providers: [ + KeycloakProvider({ + clientId: process.env.KEYCLOAK_CLIENT_ID!, + clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!, + issuer: process.env.KEYCLOAK_ISSUER!, + }), + ], + + secret: process.env.NEXTAUTH_SECRET, + callbacks: { + async jwt({ token, account, profile }) { + console.log("PROFILE =>", profile) + + if (account && profile) { + token.name = + (profile as any).name || + (profile as any).preferred_username || + "Unknown User" + + token.email = (profile as any).email || "no-email" + } + + console.log("TOKEN =>", token) + return token + }, + + async session({ session, token }) { + session.user = { + ...session.user, + name: token.name as string, + email: token.email as string, + } + + console.log("SESSION =>", session) + return session + }, + }, + + debug: true, +}; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; \ No newline at end of file diff --git a/app/dashboard/overview/serviceEngineer/page.tsx b/app/dashboard/overview/serviceEngineer/page.tsx index e69de29..0bbae64 100644 --- a/app/dashboard/overview/serviceEngineer/page.tsx +++ b/app/dashboard/overview/serviceEngineer/page.tsx @@ -0,0 +1,14 @@ +"use client"; + +import ServiceEngineerPortal from "@/components/dashboard/serviceEngineer"; + +export default function EngagementDashboard() { + return ( + + +
+ +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index a02c0f1..5660634 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,7 +1,17 @@ // app/dashboard/page.tsx import { redirect } from "next/navigation"; +import { getServerSession } from "next-auth/next"; +import { authOptions } from "@/app/api/auth/[...nextauth]/route"; // Changed from handler to authOptions -export default function DashboardBasePage() { - // Automatically redirect the user to the actual overview dashboard page - redirect("/dashboard/overview/dashboard"); -} \ No newline at end of file +export default async function DashboardBasePage() { + + const session = await getServerSession(authOptions); + + if (!session) { + redirect("/login"); + } +else{ +redirect("/dashboard/overview/dashboard"); +} +} + \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index de0cf47..2095ca5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,6 @@ import "./globals.css"; - +import SessionWrapper from "./sessionWrapper"; export default function RootLayout({ @@ -12,7 +12,11 @@ export default function RootLayout({ - {children} + + + {children} + + ); } diff --git a/app/page.tsx b/app/page.tsx index b74988e..cf8f13a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,7 +4,7 @@ import OverViewDashboardPage from "./dashboard/overview/buildingOwner/page"; export default function Home() { return (
- + {/* */}
); } diff --git a/app/sessionWrapper.tsx b/app/sessionWrapper.tsx new file mode 100644 index 0000000..ead3c47 --- /dev/null +++ b/app/sessionWrapper.tsx @@ -0,0 +1,14 @@ +"use client"; + +import React from "react"; +import { SessionProvider } from "next-auth/react"; + +interface SessionWrapperProps { + children: React.ReactNode; +} + +export default function SessionWrapper({ + children, +}: SessionWrapperProps) { + return {children}; +} \ No newline at end of file diff --git a/components/auth/loginForm.tsx b/components/auth/loginForm.tsx index b630c97..8a7bb48 100644 --- a/components/auth/loginForm.tsx +++ b/components/auth/loginForm.tsx @@ -4,6 +4,7 @@ import Button from "@/utils/button"; import { useState } from "react"; import {Props} from "@/constants/types" +import { signIn } from "next-auth/react"; export default function LoginForm({ onSuccess,onForgotPassword }: Props) { @@ -41,9 +42,9 @@ export default function LoginForm({ onSuccess,onForgotPassword }: Props) { @@ -85,6 +86,9 @@ export default function LoginForm({ onSuccess,onForgotPassword }: Props) { diff --git a/components/dashboard/buildingOwner.tsx b/components/dashboard/buildingOwner.tsx index 887389a..9d794bb 100644 --- a/components/dashboard/buildingOwner.tsx +++ b/components/dashboard/buildingOwner.tsx @@ -1,20 +1,20 @@ - -import { Building2, ShieldCheck, Database, Leaf, FileSpreadsheet, Sparkles } from "lucide-react"; +import { Building2, ShieldCheck, Database, Leaf, FileSpreadsheet } from "lucide-react"; import StatCard from "@/utils/dashStatCard"; -import { energyData } from "@/constants/constant"; +import { energyData } from "@/constants/constant"; import BarChart from "@/utils/barchart"; import InfoBanner from "@/utils/infoBanner"; import Button from "@/utils/button"; import { ProgressBarRow } from "@/utils/progressBarRow"; -export default function BuildingOwnerPortal() { - // Mock data matching the screenshot chart (Jan - Jun) - +// Import your custom Card components +import { Card } from "@/utils/cardWrapper"; +import { CardHeader } from "@/utils/cardHeader"; +export default function BuildingOwnerPortal() { return ( -
+
- {/* --- HEADER SECTION --- */} + {/* --- HEADER SECTION --- */}
@@ -47,7 +47,7 @@ export default function BuildingOwnerPortal() { iconContainerClassName="bg-[#11233a]/50 border-[#1b2c3f]/40 text-blue-400" /> @@ -67,36 +67,30 @@ export default function BuildingOwnerPortal() {
{/* Left Box: Site Benchmarking Progress Lists (7 Columns) */} -
-
-
-

Site benchmarking

- performance index -
+
+ + -
+
{/* Progress Item 1 */} - + {/* Progress Item 2 */} +
-
+
{/* Right Box: Energy Cost Bar Chart integration (5 Columns) */} -
-
-

- Energy cost outlook · ₹L -

- - forecast ↓ - -
-
-
- -
+
+ + +
+
+ +
+
+
{/* --- BOTTOM INFORMATION VIEW BANNER --- */} diff --git a/components/dashboard/engagement.tsx b/components/dashboard/engagement.tsx index 6bbad37..d620ede 100644 --- a/components/dashboard/engagement.tsx +++ b/components/dashboard/engagement.tsx @@ -1,19 +1,26 @@ "use client"; import { Smile, - ShieldCheck, Database, Leaf, + ShieldCheck, + Database, + Leaf, Plus, } from "lucide-react"; -import {SATISFACTION_DRIVERS,TICKETS_DATA} from "@/constants/constant"; +import { SATISFACTION_DRIVERS, TICKETS_DATA } from "@/constants/constant"; import StatCard from "../../utils/dashStatCard"; import Button from "@/utils/button"; import InfoBanner from "@/utils/infoBanner"; + +// Import your custom Card components +import { Card } from "@/utils/cardWrapper"; +import { CardHeader } from "@/utils/cardHeader"; + export default function EngagementPage() { return ( -
+
-
+
{/* Page Header Section */}
@@ -46,109 +53,108 @@ export default function EngagementPage() {
- {/* Column of StatCard */} + {/* --- STAT CARD GRID --- */} +
+ + + + + + +
-
- - - - - - - -
- - {/* (Drivers & Tickets lists columns) */} -
+ {/* --- TWO COLUMNS (DRIVERS & TICKETS LISTS) --- */} +
{/* Left Column: Satisfaction Drivers */} -
-
-

Satisfaction drivers

- latest pulse -
+
+ + -
- {SATISFACTION_DRIVERS.map((driver) => ( -
-
- {driver.label} - {driver.score} +
+ {SATISFACTION_DRIVERS.map((driver) => ( +
+
+ {driver.label} + {driver.score} +
+ + {/* Track line background */} +
+ {/* Filled bar width */} +
+
- - {/* Track line background */} -
- {/* Filled bar width */} -
-
-
- ))} -
+ ))} +
+
{/* Right Column: Tickets & Suggestions */} -
-
-

Tickets & suggestions

-
+
+ + -
- {TICKETS_DATA.map((ticket, index) => ( -
-
-

{ticket.title}

- - {ticket.type} - -
+
+ {TICKETS_DATA.map((ticket, index) => ( +
+
+

{ticket.title}

+ + {ticket.type} + +
- {/* Status Indicator Badges */} -
- {ticket.status === "OPEN" ? ( - - - OPEN - - ) : ( - - - CLOSED - - )} + {/* Status Indicator Badges */} +
+ {ticket.status === "OPEN" ? ( + + + OPEN + + ) : ( + + + CLOSED + + )} +
-
- ))} -
+ ))} +
+
- - + +
+ +
); diff --git a/components/dashboard/propertyManager.tsx b/components/dashboard/propertyManager.tsx index ed5da83..5dc89b7 100644 --- a/components/dashboard/propertyManager.tsx +++ b/components/dashboard/propertyManager.tsx @@ -1,30 +1,28 @@ - import Button from "@/utils/button"; import StatCard from "@/utils/dashStatCard"; +import InfoBanner from "@/utils/infoBanner"; import { ProgressBarRow } from "@/utils/progressBarRow"; import { FileText, Wrench, - ShieldCheck, - Coins, + ShieldCheck, Smile, ChevronRight, - Sparkles + Database, } from "lucide-react"; +// Import your custom Card components +import { Card } from "@/utils/cardWrapper"; +import { CardHeader } from "@/utils/cardHeader"; export default function PropertyManagerPortal() { return ( -
+
{/* --- HEADER SECTION --- */} -
+
-
+
Apple One — HQ Tower Portal @@ -53,105 +51,116 @@ export default function PropertyManagerPortal() {
{/* --- ROW 1: STATS GRID --- */} -
+
+ + +
{/* --- ROW 2: SPLIT GRID --- */} -
+
{/* Left Box: Work Order Status Tracking (7 Columns wide) */} -
-
-
-

Work order status

-
- -
- - - - - +
+ +
+ +
+ + + +
-
- {/* Inline Sub-metrics Row split container inside the card */} -
-
-
BILLED MTD
-
₹99.4 L
+ {/* Inline Sub-metrics Row split container inside the card */} +
+
+
BILLED MTD
+
₹99.4 L
+
+
+
ENERGY SAVED
+
₹3.5 L/mo
+
-
-
ENERGY SAVED
-
₹3.5 L/mo
-
-
+
{/* Right Box: Quick Actions Accordion Links (5 Columns wide) */} -
-
-

Quick actions

- -
- {[ - "Track work orders", - "Energy optimization", - "Automated billing", - "Budget & approvals", - "Contracts & SLA", - ].map((action, idx) => ( - - ))} +
+ +
+ + +
+ {[ + "Track work orders", + "Energy optimization", + "Automated billing", + "Budget & approvals", + "Contracts & SLA", + ].map((action, idx) => ( + + ))} +
-
+
{/* --- BOTTOM INFO BANNER --- */} -
-

- Manager view: - remote access, digital documentation archive, energy-saving optimisation, work-order tracking, automated billing and occupant-comfort monitoring. -

+
+
- {/* Floating Ask AI Button */} - -
); } \ No newline at end of file diff --git a/components/dashboard/serviceEngineer.tsx b/components/dashboard/serviceEngineer.tsx new file mode 100644 index 0000000..f5af2c4 --- /dev/null +++ b/components/dashboard/serviceEngineer.tsx @@ -0,0 +1,243 @@ +import Button from "@/utils/button"; +import StatCard from "@/utils/dashStatCard"; +import InfoBanner from "@/utils/infoBanner"; +import { + FileText, + Wrench, + Target, + Calendar, + Brain, + Check, +} from "lucide-react"; + +// Import your custom Card components +import { Card } from "@/utils/cardWrapper"; +import { CardHeader } from "@/utils/cardHeader"; + +export default function ServiceEngineerPortal() { + return ( +
+ + {/* --- HEADER SECTION --- */} +
+
+
+ Apple One — HQ Tower + + Portal + + Service Engineer +
+

+ Service engineer portal +

+

+ Field cockpit — real-time asset metrics, actionable alerts, the PM schedule for today and verified task completion. +

+
+ + {/* Action Buttons */} +
+ + +
+
+ + {/* --- ROW 1: STATS GRID --- */} +
+ + + + + + + +
+ + {/* --- ROW 2: SPLIT GRID (METRICS & TIMELINE) --- */} +
+ + {/* Left Section (8 Columns): Real-time Asset Metrics */} +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Asset · ParameterReadingState
Chiller-02 · supply temp6.8 °C + + Normal + +
AHU-07 · vibration4.1 mm/s + + Watch + +
DG-01 · fuel level62% + + Normal + +
Pump-03 · pressure3.2 bar + + Normal + +
+
+
+
+ + {/* Right Section (4 Columns): Today's Schedule Timeline */} +
+ + + + {/* Timeline Node Flow */} +
+ + {/* Timeline Task 1 */} +
+ +
+

Cooling tower cleaning

+

09:00 · PPM

+
+
+ + {/* Timeline Task 2 */} +
+ +
+

AHU filter check

+

11:30 · PPM

+
+
+ + {/* Timeline Task 3 */} +
+ +
+

Lift quarterly service

+

14:00 · AMC

+
+
+ +
+
+
+ +
+ + {/* --- ROW 3: FULL WIDTH ACTIONABLE ALERTS --- */} +
+ + + +
+ {/* Alert 1 */} +
+
+ +
+

Chiller-02 bearing wear

+

Raise condition-based PM

+
+
+ +
+ + {/* Alert 2 */} +
+
+ +
+

AHU-07 belt vibration

+

Inspect within 10 days

+
+
+ +
+
+
+
+ + {/* --- BOTTOM INFO BANNER --- */} +
+ +
+ +
+ ); +} \ No newline at end of file diff --git a/components/dashboard/sidebar.tsx b/components/dashboard/sidebar.tsx index d02984b..7864dcf 100644 --- a/components/dashboard/sidebar.tsx +++ b/components/dashboard/sidebar.tsx @@ -6,8 +6,11 @@ import { ChevronDown, ChevronsLeft, } from "lucide-react"; - +import { useSession, signOut } from "next-auth/react"; export default function Sidebar() { + const { data: session } = useSession(); + console.log("Session data ",session?.user?.name) +console.log("Session data ",session?.user?.email) return (
- + signOut({ callbackUrl: "/login" })} />
diff --git a/constants/constant.ts b/constants/constant.ts index 58ede22..9fa5203 100644 --- a/constants/constant.ts +++ b/constants/constant.ts @@ -45,7 +45,7 @@ export const SIDEBAR_ITEMS = [ { title: "Engagement", href: "/dashboard/overview/engagement", icon: Smile }, { title: "Building Owner", href: "/dashboard/overview/buildingOwner", icon: Building2 }, { title: "Property Manager", href: "/dashboard/overview/propertyManager", icon: User }, - { title: "Service Engineer", href: "/overview/service-engineer", icon: Target }, + { title: "Service Engineer", href: "/dashboard/overview/serviceEngineer", icon: Target }, ], }, { diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..ba2b32a --- /dev/null +++ b/middleware.ts @@ -0,0 +1,11 @@ +import { withAuth } from "next-auth/middleware" + +export default withAuth({ + pages: { + signIn: "/login", + }, +}) + +export const config = { + matcher: ["/dashboard/:path*"], +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d8cbfc6..d6a46e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "lucide-react": "^1.24.0", "next": "16.2.10", + "next-auth": "^4.24.14", "react": "19.2.4", "react-dom": "19.2.4" }, @@ -229,6 +230,15 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", @@ -1307,6 +1317,15 @@ "node": ">=12.4.0" } }, + "node_modules/@panva/hkdf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", + "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -2817,6 +2836,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4629,6 +4657,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5262,6 +5299,38 @@ } } }, + "node_modules/next-auth": { + "version": "4.24.14", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.14.tgz", + "integrity": "sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==", + "license": "ISC", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.7.0", + "jose": "^4.15.5", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "@auth/core": "0.34.3", + "next": "^12.2.5 || ^13 || ^14 || ^15 || ^16", + "nodemailer": "^7.0.7", + "react": "^17.0.2 || ^18 || ^19", + "react-dom": "^17.0.2 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@auth/core": { + "optional": true + }, + "nodemailer": { + "optional": true + } + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -5319,6 +5388,12 @@ "node": ">=18" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==", + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5329,6 +5404,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -5442,6 +5526,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-token-hash": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz", + "integrity": "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, + "node_modules/openid-client": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz", + "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==", + "license": "MIT", + "dependencies": { + "jose": "^4.15.9", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/openid-client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -5608,6 +5734,36 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.29.7", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.7.tgz", + "integrity": "sha512-DCHYrK/B10yUD3ZjLfhZ3WIE/9Vf9VFUODcRE2dRomTYDpJk6z6L9wecSfhfE6M9ZTHUdyQkoC46arIDhEV84Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + }, + "peerDependencies": { + "preact-render-to-string": ">=5" + }, + "peerDependenciesMeta": { + "preact-render-to-string": { + "optional": true + } + } + }, + "node_modules/preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "license": "MIT", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5618,6 +5774,12 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==", + "license": "MIT" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6666,6 +6828,16 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 453e581..3dbe055 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "lucide-react": "^1.24.0", "next": "16.2.10", + "next-auth": "^4.24.14", "react": "19.2.4", "react-dom": "19.2.4" }, @@ -23,5 +24,9 @@ "eslint-config-next": "16.2.10", "tailwindcss": "^4", "typescript": "^5" + }, + "allowScripts": { + "sharp@0.34.5": true, + "unrs-resolver@1.12.2": true } }