From 954de712a78aaa0b0eb5649902a88d07b00263e3 Mon Sep 17 00:00:00 2001 From: Shaily Mishra Date: Mon, 27 Jul 2026 19:05:11 +0530 Subject: [PATCH] Admin part is added and navbar context file is added --- app/dashboard/admin/dynamicDashboard/page.tsx | 19 + app/dashboard/admin/language/page.tsx | 20 + app/dashboard/admin/mobileFlow/page.tsx | 21 + app/dashboard/admin/modules/page.tsx | 19 + app/dashboard/admin/overview/page.tsx | 18 + app/dashboard/admin/security/page.tsx | 23 + app/dashboard/admin/site/page.tsx | 20 + app/dashboard/admin/tenants/page.tsx | 19 + app/dashboard/admin/users/page.tsx | 20 + app/dashboard/layout.tsx | 46 +- .../admin/Configuration/dynamicDashboard.tsx | 173 ++++++++ .../admin/Configuration/language.tsx | 256 +++++++++++ .../admin/Configuration/mobileFlows.tsx | 45 ++ .../dashboard/admin/Configuration/modules.tsx | 219 +++++++++ .../dashboard/admin/Platform/overview.tsx | 190 ++++++++ .../dashboard/admin/Platform/security.tsx | 416 ++++++++++++++++++ components/dashboard/admin/Platform/site.tsx | 228 ++++++++++ .../dashboard/admin/Platform/tenants.tsx | 244 ++++++++++ components/dashboard/admin/Platform/users.tsx | 305 +++++++++++++ components/layouts/context/navContext.tsx | 31 ++ components/layouts/navbar.tsx | 188 +++++--- components/layouts/sidebar.tsx | 90 ++-- constants/constant.ts | 46 +- 23 files changed, 2525 insertions(+), 131 deletions(-) create mode 100644 app/dashboard/admin/dynamicDashboard/page.tsx create mode 100644 app/dashboard/admin/language/page.tsx create mode 100644 app/dashboard/admin/mobileFlow/page.tsx create mode 100644 app/dashboard/admin/modules/page.tsx create mode 100644 app/dashboard/admin/overview/page.tsx create mode 100644 app/dashboard/admin/security/page.tsx create mode 100644 app/dashboard/admin/site/page.tsx create mode 100644 app/dashboard/admin/tenants/page.tsx create mode 100644 app/dashboard/admin/users/page.tsx create mode 100644 components/dashboard/admin/Configuration/dynamicDashboard.tsx create mode 100644 components/dashboard/admin/Configuration/language.tsx create mode 100644 components/dashboard/admin/Configuration/mobileFlows.tsx create mode 100644 components/dashboard/admin/Configuration/modules.tsx create mode 100644 components/dashboard/admin/Platform/overview.tsx create mode 100644 components/dashboard/admin/Platform/security.tsx create mode 100644 components/dashboard/admin/Platform/site.tsx create mode 100644 components/dashboard/admin/Platform/tenants.tsx create mode 100644 components/dashboard/admin/Platform/users.tsx create mode 100644 components/layouts/context/navContext.tsx diff --git a/app/dashboard/admin/dynamicDashboard/page.tsx b/app/dashboard/admin/dynamicDashboard/page.tsx new file mode 100644 index 0000000..e63a1ba --- /dev/null +++ b/app/dashboard/admin/dynamicDashboard/page.tsx @@ -0,0 +1,19 @@ +"use client" + +import DynamicDashboardPortal from "@/components/dashboard/admin/Configuration/dynamicDashboard"; + + + + + +export default function DynamicDashboardPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/language/page.tsx b/app/dashboard/admin/language/page.tsx new file mode 100644 index 0000000..55e6221 --- /dev/null +++ b/app/dashboard/admin/language/page.tsx @@ -0,0 +1,20 @@ +"use client" + +import LanguagePortal from "@/components/dashboard/admin/Configuration/language"; +import ModulesPortal from "@/components/dashboard/admin/Configuration/modules"; + + + + + +export default function LanguagePage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/mobileFlow/page.tsx b/app/dashboard/admin/mobileFlow/page.tsx new file mode 100644 index 0000000..14b015a --- /dev/null +++ b/app/dashboard/admin/mobileFlow/page.tsx @@ -0,0 +1,21 @@ +"use client" + + +import MobileFlowsPortal from "@/components/dashboard/admin/Configuration/mobileFlows"; + + + + + + +export default function MobileFlowPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/modules/page.tsx b/app/dashboard/admin/modules/page.tsx new file mode 100644 index 0000000..9f6a969 --- /dev/null +++ b/app/dashboard/admin/modules/page.tsx @@ -0,0 +1,19 @@ +"use client" + +import ModulesPortal from "@/components/dashboard/admin/Configuration/modules"; + + + + + +export default function ModulesPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/overview/page.tsx b/app/dashboard/admin/overview/page.tsx new file mode 100644 index 0000000..9d0e51a --- /dev/null +++ b/app/dashboard/admin/overview/page.tsx @@ -0,0 +1,18 @@ +"use client" + +import AdminOverviewPortal from "@/components/dashboard/admin/overview"; + + + + +export default function OverviewPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/security/page.tsx b/app/dashboard/admin/security/page.tsx new file mode 100644 index 0000000..090c43e --- /dev/null +++ b/app/dashboard/admin/security/page.tsx @@ -0,0 +1,23 @@ + + + +"use client" + + +import SecurityPortal from "@/components/dashboard/admin/Platform/security"; + + + + + +export default function SecurityPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/site/page.tsx b/app/dashboard/admin/site/page.tsx new file mode 100644 index 0000000..06e6175 --- /dev/null +++ b/app/dashboard/admin/site/page.tsx @@ -0,0 +1,20 @@ +"use client" + + +import SitePortal from "@/components/dashboard/admin/site"; + + + + + +export default function AuditSurveyPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/tenants/page.tsx b/app/dashboard/admin/tenants/page.tsx new file mode 100644 index 0000000..c022c44 --- /dev/null +++ b/app/dashboard/admin/tenants/page.tsx @@ -0,0 +1,19 @@ +"use client" + + +import TenantsPortal from "@/components/dashboard/admin/tenants"; + + + + +export default function TenantsPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/admin/users/page.tsx b/app/dashboard/admin/users/page.tsx new file mode 100644 index 0000000..3325518 --- /dev/null +++ b/app/dashboard/admin/users/page.tsx @@ -0,0 +1,20 @@ +"use client" + + + +import UserPortal from "@/components/dashboard/admin/users"; + + + + +export default function UsersPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index c75d24c..6400c3b 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -1,7 +1,9 @@ -"use client"// app/dashboard/layout.tsx +"use client"; + import Sidebar from "@/components/layouts/sidebar"; import Navbar from "@/components/layouts/navbar"; import { Sparkles } from "lucide-react"; +import { NavProvider } from "@/components/layouts/context/navContext"; export default function DashboardLayout({ children, @@ -9,27 +11,29 @@ export default function DashboardLayout({ children: React.ReactNode; }) { return ( -
- {/* Shared Sidebar */} - - -
- {/*Common Navbar for every webpage */} - - + -
- {children} -
-
+ {/* Shared Sidebar - Now inside NavProvider */} + - {/* Ask AI Floating Button common */} - -
+
+ {/* Shared Navbar - Now inside NavProvider */} + + + {/* Main Page Content */} +
+ {children} +
+
+ + {/* Ask AI Floating Button */} + + + ); } \ No newline at end of file diff --git a/components/dashboard/admin/Configuration/dynamicDashboard.tsx b/components/dashboard/admin/Configuration/dynamicDashboard.tsx new file mode 100644 index 0000000..daa6258 --- /dev/null +++ b/components/dashboard/admin/Configuration/dynamicDashboard.tsx @@ -0,0 +1,173 @@ +import { ChevronDown, Trash2, X, Plus, Sparkles } from "lucide-react"; + +const initialRows = [ + // Row 1 (2 cards) + { + id: "row-1", + widgets: [ + { id: "w1", title: "TFM Requests · Monthly", type: "report.widget" }, + { id: "w2", title: "Recent Activity", type: "report.widget" }, + ], + }, + // Row 2 (2 cards) + { + id: "row-2", + widgets: [ + { id: "w3", title: "Schedule Performance", type: "report.widget" }, + { id: "w4", title: "Energy · Today", type: "report.widget" }, + ], + }, + // Row 3 (3 cards) + { + id: "row-3", + widgets: [ + { id: "w5", title: "Top 5 Requester", type: "report.widget" }, + { id: "w6", title: "Asset Register", type: "report.widget" }, + { id: "w7", title: "PM Plan vs Started", type: "report.widget" }, + ], + }, +]; + +// Note the 'export default' keyword here: +export default function DynamicDashboardPortal() { + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + DYNAMIC DASHBOARD +
+

+ Dynamic dashboard +

+

+ Design the dashboard each tenant's users land on in Operations. Arrange rows, + drop in report widgets, then publish. +

+
+ + {/* Action Buttons */} +
+ + + PUBLISHED + + + +
+
+ + {/* --- CONTROL BAR: DESIGNING FOR TENANT --- */} +
+
+ + Designing for + +
+ + +
+
+ +
+ 3 rows · 7 widgets +
+
+ + {/* --- CANVAS GRID AREA --- */} +
+ {initialRows.map((row) => ( +
+ {/* Delete Row Button */} + + + {/* Row Widgets Layout */} +
+ {row.widgets.map((widget) => ( +
+ {/* Widget Top Header */} +
+
+

+ {widget.title} +

+

+ {widget.type} +

+
+ +
+ + {/* Widget Placeholder Bar Chart */} +
+
+
+
+
+
+
+
+ ))} +
+
+ ))} +
+ + {/* --- BOTTOM ADD ROW CONTROLS --- */} +
+ + Add row: + + + + +
+ + + +
+ ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Configuration/language.tsx b/components/dashboard/admin/Configuration/language.tsx new file mode 100644 index 0000000..bc1961f --- /dev/null +++ b/components/dashboard/admin/Configuration/language.tsx @@ -0,0 +1,256 @@ +"use client"; + +import { useState } from "react"; +import { Plus, ChevronDown } from "lucide-react"; + +const initialLanguageValues = [ + { + id: 1, + app: "Web Console", + menu: "Tenant", + screen: "Tenant List", + uiKey: "btn.add_tenant", + code: "EN", + value: "Add Tenant", + }, + { + id: 2, + app: "Web Console", + menu: "Site", + screen: "Site List", + uiKey: "btn.add_site", + code: "EN", + value: "Add Site", + }, + { + id: 3, + app: "Mobile App", + menu: "Inspections", + screen: "QR Round", + uiKey: "lbl.scan_qr", + code: "EN", + value: "Scan QR to begin round", + }, +]; + +export default function LanguagePortal() { + + + const [languageValues, setLanguageValues] = useState(initialLanguageValues); + + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+ PLATFORM + + LANGUAGE +
+

Language

+

+ Manage translation keys across apps, menus and screens — then resolve their values per tenant. +

+
+ + {/* --- FORM SECTION: LANGUAGE KEY MASTER --- */} +
+
+

+ Language key master +

+

+ Scope a translation key to an app, menu and screen +

+
+ +
+ {/* Top Row Selects */} +
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+
+ + {/* Bottom Row Inputs & Action Button */} +
+
+ + +
+ +
+ +
+ + +
+
+ +
+ + +
+ +
+ +
+
+
+
+ + {/* --- TABLE SECTION: LANGUAGE VALUES --- */} +
+ {/* Table Header Controls */} +
+
+

+ Language values +

+

+ Resolved strings — filtered to the selected tenant's locales +

+
+ +
+ + +
+
+ + {/* Locale Tag */} +
+ + + EN + +
+ + {/* Data Table */} +
+ + + + + + + + + + + + + {languageValues.map((row) => ( + + + + + + + + + ))} + +
APPMENUSCREENUI KEYCODEVALUE
{row.app}{row.menu}{row.screen} + + {row.uiKey} + + + + + {row.code} + + {row.value}
+
+
+ + +
+ ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Configuration/mobileFlows.tsx b/components/dashboard/admin/Configuration/mobileFlows.tsx new file mode 100644 index 0000000..6dd09c0 --- /dev/null +++ b/components/dashboard/admin/Configuration/mobileFlows.tsx @@ -0,0 +1,45 @@ +import { Smartphone } from "lucide-react"; + +export default function MobileFlowsPortal() { + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+ {/* Breadcrumb */} +
+ PLATFORM + + MOBILE +
+ + {/* Title */} +

+ KAFM Field — mobile flows +

+ + {/* Subtitle / Description */} +

+ The technician mobile app, embedded live: two flow variations (1a Field Deck · dark, 1b Day Runner · light), 17 screens each — jobs, checklists, QR, inventory, chat, incidents, reports. Every phone is fully interactive. +

+
+ + {/* Action Button */} +
+ +
+
+ + {/* --- EMBEDDED PHONE DISPLAY AREA --- */} +
+ {/* Mobile preview frame container goes here */} +

+ [ Live Mobile App Frames ] +

+
+
+ ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Configuration/modules.tsx b/components/dashboard/admin/Configuration/modules.tsx new file mode 100644 index 0000000..0a80589 --- /dev/null +++ b/components/dashboard/admin/Configuration/modules.tsx @@ -0,0 +1,219 @@ +"use client"; + +import { useState } from "react"; +import { + LayoutGrid, + CheckSquare, + Crosshair, + FileText, + Box, + Zap, + ClipboardCheck, + BarChart2, + Pencil, + Plus, + Sparkles, +} from "lucide-react"; + +// Mock Data matching the design +const initialModules = [ + { + id: "MOD-01", + title: "Dashboard", + description: "Operational overview & live KPIs", + icon: LayoutGrid, + menus: [], // Currently empty as per screenshot + }, + { + id: "MOD-02", + title: "Helpdesk", + description: "Tickets, requests & SLA tracking", + icon: CheckSquare, + menus: ["Tickets", "SLA Settings", "Queues"], + }, + { + id: "MOD-03", + title: "Equipment", + description: "Asset register & equipment groups", + icon: Crosshair, + menus: ["Asset Register", "Categories"], + }, + { + id: "MOD-04", + title: "Request", + description: "Service requests & approvals", + icon: FileText, + menus: ["My Requests", "Approvals"], + }, + { + id: "MOD-05", + title: "Inventory", + description: "Stock, spares & consumables", + icon: Box, + menus: ["Stock Levels", "Suppliers"], + }, + { + id: "MOD-06", + title: "Energy", + description: "Meters, consumption & analytics", + icon: Zap, + menus: ["Meters", "Analytics"], + }, + { + id: "MOD-07", + title: "Inspections", + description: "QR rounds & checklists", + icon: ClipboardCheck, + menus: ["Rounds", "Checklists"], + }, + { + id: "MOD-08", + title: "Reports", + description: "Analytics & export tools", + icon: BarChart2, + menus: ["Scheduled Reports", "Custom Builder"], + }, +]; + +export default function ModulesPortal() { + const [selectedModuleId, setSelectedModuleId] = useState("MOD-01"); + + const activeModule = initialModules.find((m) => m.id === selectedModuleId); + + return ( +
+ {/* Header Section */} +
+
+ PLATFORM + + MODULES +
+

Modules

+

+ The catalog of system modules and their menus. These are what you switch on per tenant under feature access. +

+
+ + {/* Main Grid Container */} +
+ {/* Left Column: Modules List */} +
+ {/* Section Header */} +
+
+

Modules

+ + {initialModules.length} available + +
+ +
+ + {/* Module Items */} +
+ {initialModules.map((module) => { + const Icon = module.icon; + const isSelected = module.id === selectedModuleId; + + return ( +
setSelectedModuleId(module.id)} + className={`group relative flex items-center justify-between p-3.5 rounded-lg border cursor-pointer transition-all ${ + isSelected + ? "bg-teal-950/30 border-teal-500/40" + : "bg-[#09111E]/40 border-slate-800/60 hover:border-slate-700 hover:bg-[#0D1726]" + }`} + > +
+
+ +
+
+

+ {module.title} +

+

+ {module.description} +

+
+
+ +
+ + {module.id} + + +
+
+ ); + })} +
+
+ + {/* Right Column: Menus Panel */} +
+
+ {/* Menus Header */} +
+
+

Menus

+ + Under {activeModule?.title || "Module"} + +
+ +
+ + {/* Empty State / Menus List */} + {activeModule?.menus && activeModule.menus.length > 0 ? ( +
+ {activeModule.menus.map((menu, idx) => ( +
+ {menu} + +
+ ))} +
+ ) : ( +
+

+ No menus under this module yet. +

+
+ )} +
+
+
+ + +
+ ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Platform/overview.tsx b/components/dashboard/admin/Platform/overview.tsx new file mode 100644 index 0000000..09c039f --- /dev/null +++ b/components/dashboard/admin/Platform/overview.tsx @@ -0,0 +1,190 @@ +import { useState } from 'react'; +import { + ClipboardCheck, + Clock, + AlertTriangle, + Activity, + Building2, + Users, + MapPin, + Grid, + ArrowRight, + Sparkles +} from "lucide-react"; +import StatCard from "@/components/common/dashStatCard"; + +export default function AdminOverviewPortal() { + // Sample data for the recent audits table below + const recentAudits = [ + { id: 'AUD-1004', location: 'Local 1', lead: 'Local Admin', date: '2026-02-02', status: 'ACTIVE' }, + { id: 'AUD-1003', location: 'SRM Campus', lead: 'Estates Office', date: '2026-01-08', status: 'ACTIVE' }, + { id: 'AUD-1002', location: 'Novotel Pune', lead: 'Site FM Lead', date: '2025-12-12', status: 'ACTIVE' }, + { id: 'AUD-1001', location: 'Apple One', lead: 'Dhananjay T.', date: '2025-11-04', status: 'ACTIVE' }, + ]; + + // Sample data for module/checklist adoption progress bars + const adoptionModules = [ + { name: 'Dashboard', score: 100, count: '4/4' }, + { name: 'Helpdesk', score: 75, count: '3/4' }, + { name: 'Equipment', score: 75, count: '3/4' }, + { name: 'Request', score: 75, count: '3/4' }, + { name: 'Inventory', score: 50, count: '2/4' }, + { name: 'Energy', score: 75, count: '3/4' }, + ]; + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + KAFM +
+

+ Platform overview +

+

+ Live snapshot of every organization, user, and site managed across the KAFM facility platform. +

+
+ + {/* Top Right Status Badge */} +
+ + PRODUCTION + + region us-east-1 +
+
+ + {/* --- STAT CARDS --- */} +
+ {/* Card 1: Total Tenants */} + + + {/* Card 2: Platform users */} + + + {/* Card 3: Managed sites */} + + + {/* Card 4: System modules */} + +
+ + {/* --- LOWER SECTION (ADDITION FROM SCREENSHOT) --- */} +
+ + {/* Left 2-Columns: Recently Onboarded Tenants Table */} +
+
+
+
+

Recently onboarded tenants

+

Newest organizations on the platform

+
+ +
+ + {/* Table Header */} +
+ Organization + Tenant ID + Created + Status +
+ + {/* Table Rows */} +
+ {recentAudits.map((item, index) => ( +
+
+
+ {item.location.substring(0, 2).toUpperCase()} +
+
+
{item.location}
+
{item.lead}
+
+
+ {item.id} + {item.date} +
+ + + {item.status} + +
+
+ ))} +
+
+
+ + {/* Right 1-Column: Module Adoption */} +
+
+

Module adoption

+ +
+ {adoptionModules.map((module, idx) => ( +
+
+ {module.name} + {module.count} +
+ {/* Progress Bar Container */} +
+
+
+
+ ))} +
+
+
+ +
+ + +
+ ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Platform/security.tsx b/components/dashboard/admin/Platform/security.tsx new file mode 100644 index 0000000..87f4324 --- /dev/null +++ b/components/dashboard/admin/Platform/security.tsx @@ -0,0 +1,416 @@ +import { useState } from "react"; +import { + Shield, + Users, + AlertTriangle, + ShieldCheck, + BarChart3, + Sparkles, + ChevronDown +} from "lucide-react"; +import Button from "@/components/common/button"; +import StatCard from "@/components/common/dashStatCard"; +import InfoBanner from '@/components/common/infoBanner'; +import Table from '@/components/common/dataTable'; +import { StatusBadge } from "@/components/common/statusBadge"; + +export const trustedDeviceHeaders = [ + "USER", + "DEVICE", + "IP", + "LAST SEEN", + "EXPIRES", + "STATUS", + "ACTIONS", +]; + +export const trustedDeviceRows = [ + [ + Dhananjay T., + "Chrome 126 · Windows 11", + 103.212.14.8, + Today, 08:12, + Jul 30, 2026, + , + , + ], + + [ + Kavya Raghunathan, + "Safari 18 · macOS", + 49.37.201.55, + Yesterday, 17:40, + Jul 21, 2026, + , + , + ], + + [ + Rahul Iyer, + "KAFM Mobile · Android 15", + 152.58.33.104, + Today, 06:58, + Jul 12, 2026, + , + , + ], + + [ + Meera Pillai, + "Edge 126 · Windows 10", + 103.212.14.31, + Jun 18, 2026, + Expired, + , + , + ], +]; + +export const auditLogHeaders = [ + "WHEN", + "USER", + "EVENT", + "IP", + "RESULT", +]; + +export const auditLogRows = [ + [ + Today 08:12, + dhananjay@kafm.io, + Sign-in · password + MFA, + 103.212.14.8, + , + ], + + [ + Today 07:56, + kavya@kafm.io, + + Role changed · Technician → M&E Supervisor + , + 49.37.201.55, + , + ], + + [ + Today 07:31, + unknown@ext.net, + + Sign-in · wrong password (3rd attempt) + , + 91.240.118.7, + , + ], + + [ + Today 06:58, + rahul@kafm.io, + + Device trusted · KAFM Mobile (30 days) + , + 152.58.33.104, + , + ], + + [ + Yesterday 17:40, + kavya@kafm.io, + + Password reset · self-service link + , + 49.37.201.55, + , + ], + + [ + Yesterday 14:05, + meera@kafm.io, + + MFA reset by admin · device revoked + , + 103.212.14.31, + , + ], + + [ + Jun 30 09:12, + admin@kafm.io, + + Sign-in policy updated · idle timeout 30 min + , + 103.212.14.8, + , + ], +]; + +export default function SecurityPortal() { + const [enforceMfa, setEnforceMfa] = useState(true); + const [keepMeSignedIn, setKeepMeSignedIn] = useState(true); + const [reAuthenticate, setReAuthenticate] = useState(false); + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + SECURITY +
+

+ Security & sessions +

+

+ Platform-wide sign-in policy, trusted devices and the immutable authentication audit trail. Sign-ins, MFA, resets and policy changes are logged automatically. +

+
+ + {/* --- HEADER BUTTONS --- */} +
+ + + +
+
+ + {/* --- STAT CARDS --- */} +
+ + + + + + + +
+ + {/* --- TOP GRID SECTION: AUDIT LOG + SIGN-IN POLICY --- */} +
+ + {/* --- LEFT: AUDIT LOG TABLE CONTAINER --- */} +
+
+
+

+ Authentication audit trail +

+
+ immutable + + 90-day retention +
+
+ + {/* AUDIT LOG TABLE */} + + + + + {/* --- RIGHT: SIGN-IN POLICY PANEL --- */} +
+

+ Sign-in policy +

+ +
+ {/* Toggle 1: Enforce MFA */} +
+
+

Enforce MFA for all users

+

+ 6-digit code required on every untrusted device +

+
+ +
+ + {/* Select 1: Idle Session Timeout */} +
+
+

Idle session timeout

+

+ Auto sign-out after inactivity +

+
+
+ + +
+
+ + {/* Toggle 2: Keep me signed in */} +
+
+

“Keep me signed in” by default

+

+ Pre-checks the persistent-session option at sign-in +

+
+ +
+ + {/* Toggle 3: Re-authenticate */} +
+
+

Re-authenticate for sensitive actions

+

+ Password prompt before user, role or policy changes +

+
+ +
+ + {/* Select 2: Trusted device window */} +
+
+

Trusted device window

+

+ Days MFA is skipped on a trusted device +

+
+
+ + +
+
+
+
+ + + {/* --- BOTTOM SECTION: TRUSTED DEVICES TABLE CONTAINER --- */} +
+
+
+

+ Trusted devices +

+

+ MFA skipped until expiry +

+
+ +
+ + {/* TRUSTED DEVICES TABLE */} +
+ +

+ Revoking forces MFA on the next sign-in from that device. Password changes revoke all devices automatically. +

+ + + {/* --- INFO BANNER --- */} +
+ +
+ + + + ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Platform/site.tsx b/components/dashboard/admin/Platform/site.tsx new file mode 100644 index 0000000..d73baf5 --- /dev/null +++ b/components/dashboard/admin/Platform/site.tsx @@ -0,0 +1,228 @@ +import { useState } from 'react'; +import { + Building2, + Users, + MapPin, + Grid, + Plus, + Eye, + Settings, + Pencil, + GitBranch, + Search, + ChevronDown, + Sparkles +} from "lucide-react"; +import Button from "@/components/common/button"; + +import Table from '@/components/common/dataTable'; +import { StatusBadge } from '@/components/common/statusBadge'; +import ActionButtons from '@/components/common/actionButton'; + +export const siteHeaders = [ + "Site", + "Tenant", + "Coordinates", + "Radius", + "Status", + "Actions", +]; + +export const siteRows = [ + [ +
+

Apple One — HQ Tower

+

AO-HQ · SIT-3001

+
, + "Apple One", + 19.0760, 72.8777, + 200 m, +
+
+
+
+ +
, + , + ], + + [ +
+

Apple One — Annexe

+

AO-AX · SIT-3002

+
, + "Apple One", + 19.1020, 72.8895, + 150 m, +
+
+
+
+ +
, + , + ], + + [ +
+

Novotel Pune — Main

+

NP-M · SIT-3003

+
, + "Novotel Pune", + 18.5604, 73.9090, + 180 m, +
+
+
+
+ +
, + , + ], + + [ +
+

+ SRM Campus — Academic Block +

+

SRM-AB · SIT-3004

+
, + "SRM Campus", + 12.8230, 80.0444, + 400 m, +
+
+
+
+ +
, + , + ], + + [ +
+

+ SRM Campus — Hostel Block +

+

SRM-HB · SIT-3005

+
, + "SRM Campus", + 12.8255, 80.0478, + 350 m, +
+
+
+
+ +
, + , + ], + + [ +
+

Local 1 — Site

+

L1-S · SIT-3006

+
, + "Local 1", + 19.2183, 72.9781, + 120 m, +
+
+
+
+ +
, + , + ], +]; + +export default function SitePortal() { + const [searchQuery, setSearchQuery] = useState(''); + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + SITES +
+

+ Sites +

+

+ Physical locations under each tenant. Define geofences with map coordinates and a working radius. Operations site pickers read from here. +

+
+ + {/* --- HEADER BUTTON --- */} +
+ +
+
+ + {/* --- TABLE CONTAINER WITH UPPER BAR --- */} +
+ {/* Table Upper UI (Search Bar & Filter Dropdown) */} +
+ {/* Search Bar Input */} +
+ + setSearchQuery(e.target.value)} + placeholder="Search sites..." + className="w-full pl-10 pr-4 py-2 bg-slate-950/80 border border-slate-800 rounded-lg text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-slate-700 transition" + /> +
+ + {/* All Tenants Filter Select Dropdown */} +
+ + +
+
+ + {/* --- TABLE --- */} +
+ + {/* Footer Record Count */} +
+ {siteRows.length} records +
+ + + + + ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Platform/tenants.tsx b/components/dashboard/admin/Platform/tenants.tsx new file mode 100644 index 0000000..243bcce --- /dev/null +++ b/components/dashboard/admin/Platform/tenants.tsx @@ -0,0 +1,244 @@ +import { useState } from 'react'; +import { + Building2, + Users, + MapPin, + Grid, + Plus, + Eye, + Settings, + Pencil, + GitBranch, + Search, + ChevronDown +} from "lucide-react"; +import Button from "@/components/common/button"; +import StatCard from "@/components/common/dashStatCard"; +import Table from '@/components/common/dataTable'; +import { StatusBadge } from '@/components/common/statusBadge'; + +export const organizationHeaders = [ + "Organization", + "Tenant ID", + "Contact", + "Time Zone", + "Status", + "Actions", +]; + +const ActionButtons = () => ( +
+ + + + + + + +
+); + +export const organizationRows = [ + [ +
+
+ AO +
+ +
+
Apple One
+
ops@appleone.com
+
+
, + + + TNT-1001 + , + +
+
Dhananjay T.
+
+91 98200 10001
+
, + + Asia/Kolkata, + + , + + , + ], + + [ +
+
+ NP +
+ +
+
Novotel Pune
+
fm@novotelpune.com
+
+
, + + + TNT-1002 + , + +
+
Site FM Lead
+
+91 98220 20002
+
, + + Asia/Kolkata, + + , + + , + ], + + [ +
+
+ SC +
+ +
+
SRM Campus
+
estates@srm.edu
+
+
, + + + TNT-1003 + , + +
+
Estates Office
+
+91 98430 30003
+
, + + Asia/Kolkata, + + , + + , + ], + + [ +
+
+ L1 +
+ +
+
Local 1
+
admin@local1.com
+
+
, + + + TNT-1004 + , + +
+
Local Admin
+
+91 98000 40004
+
, + + Asia/Kolkata, + + , + + , + ], +]; + +export default function TenantsPortal() { + + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + TENANTS +
+

+ Tenants +

+

+ Every organization provisioned on the platform. Manage onboarding, feature access, branding, and status. +

+
+ + {/* --- HEADER BUTTON --- */} +
+ +
+
+ + + + {/* --- TABLE CONTAINER WITH UPPER BAR --- */} +
+ {/* Table Upper UI (Search Bar & Filter Dropdown) */} +
+ {/* Search Bar Input */} +
+ + +
+ + {/* All Statuses Filter Select Dropdown */} +
+ + +
+
+ + {/* --- TABLE --- */} +
+ + {/* Footer Record Count */} +
+ {organizationRows.length} records +
+ + + ); +} \ No newline at end of file diff --git a/components/dashboard/admin/Platform/users.tsx b/components/dashboard/admin/Platform/users.tsx new file mode 100644 index 0000000..1453d79 --- /dev/null +++ b/components/dashboard/admin/Platform/users.tsx @@ -0,0 +1,305 @@ +import { useState } from 'react'; +import { + Plus, + Eye, + KeyRound, + Search, + Sparkles +} from "lucide-react"; +import Button from "@/components/common/button"; +import Table from '@/components/common/dataTable'; +import { StatusBadge } from '@/components/common/statusBadge'; + +export const userHeaders = [ + "Name", + "Email", + "Phone", + "Tenants", + "MFA", + "User ID", + "Actions", +]; + +const UserActionButtons = () => ( +
+ + + +
+); + +export const userRows = [ + [ +
+
+ DT +
+ + + Dhananjay T. + +
, + + + dhananjay@kafm.io + , + + + +91 98200 10001 + , + + + 4 assigned + , + + , + + + USR-5001 + , + + , + ], + + [ +
+
+ MS +
+ + + ME Supervisor + +
, + + + me.local@kafm.io + , + + + +91 98201 10010 + , + + + 1 assigned + , + + , + + + USR-5002 + , + + , + ], + + [ +
+
+ T +
+ + + Technician + +
, + + + tech.local@kafm.io + , + + + +91 98202 10011 + , + + + 2 assigned + , + + , + + + USR-5003 + , + + , + ], + + [ +
+
+ TC +
+ + + Tenant Customer + +
, + + + tenant@kafm.io + , + + + +91 98203 10012 + , + + + 1 assigned + , + + , + + + USR-5004 + , + + , + ], + + [ +
+
+ HA +
+ + + Helpdesk Agent + +
, + + + help@kafm.io + , + + + +91 98204 10013 + , + + + 2 assigned + , + + , + + + USR-5005 + , + + , + ], + + [ +
+
+ EA +
+ + + Energy Analyst + +
, + + + energy@kafm.io + , + + + +91 98430 30030 + , + + + 1 assigned + , + + , + + + USR-5006 + , + + , + ], +]; + +export default function UserPortal() { + const [searchQuery, setSearchQuery] = useState(''); + + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ PLATFORM + + USERS +
+

+ Users +

+

+ All platform user accounts. Create credentials, assign tenants, and manage passwords. This is the single account store — Operations role access reads from here. +

+
+ + {/* --- HEADER BUTTON --- */} +
+ +
+
+ + {/* --- TABLE CONTAINER WITH UPPER BAR --- */} +
+ {/* Table Upper UI (Full-width Search Bar matching screenshot) */} +
+
+ + setSearchQuery(e.target.value)} + placeholder="Search users by name, email or ID..." + className="w-full pl-10 pr-4 py-2.5 bg-slate-950/80 border border-slate-800 rounded-lg text-sm text-slate-200 placeholder-slate-500 focus:outline-none focus:border-slate-700 transition" + /> +
+
+ + {/* --- TABLE --- */} +
+ + {/* Footer Record Count */} +
+ {userRows.length} records +
+ + + + + ); +} \ No newline at end of file diff --git a/components/layouts/context/navContext.tsx b/components/layouts/context/navContext.tsx new file mode 100644 index 0000000..bb96ccd --- /dev/null +++ b/components/layouts/context/navContext.tsx @@ -0,0 +1,31 @@ +"use client"; + +import React, { createContext, useContext, useState } from "react"; + +type Mode = "operations" | "admin"; + +interface NavContextType { + mode: Mode; + setMode: (mode: Mode) => void; +} + +// 1. Provide default values so useContext never returns null/undefined +const NavContext = createContext({ + mode: "operations", + setMode: () => {}, +}); + +export function NavProvider({ children }: { children: React.ReactNode }) { + const [mode, setMode] = useState("operations"); + + return ( + + {children} + + ); +} + +export function useNav() { + const context = useContext(NavContext); + return context; +} \ No newline at end of file diff --git a/components/layouts/navbar.tsx b/components/layouts/navbar.tsx index fad6250..098e144 100644 --- a/components/layouts/navbar.tsx +++ b/components/layouts/navbar.tsx @@ -1,83 +1,133 @@ -import { Search, HelpCircle, Globe, Sun, Bell, ChevronDown, MapPin } from 'lucide-react'; +"use client"; + +import { Search, HelpCircle, Globe, Sun, Bell, ChevronDown, MapPin, ShieldCheck } from "lucide-react"; +import { useNav } from "./context/navContext"; + export default function Navbar() { + const { mode } = useNav(); + return ( - /* - - 'fixed top-0 right-0 left-64' anchors the navbar to the top of the screen, - leaving room exactly for your 64-width sidebar. - - 'bg-[#071321]' matches your master UI background. - - 'h-16' gives it a consistent height. - */
- - {/* Left Group */} -
- {/* Company Selector */} -
- - Apple One - -
+ {mode === "operations" ? ( + /* ================= OPERATIONS NAVBAR ================= */ + <> + {/* Left Group */} +
+ {/* Company Selector */} +
+ - {/* Location Selector */} -
- - - Apple One — HQ Tower - - -
+ - {/* Search Bar */} -
- - -
-
+ +
+ {/* Location Selector */} +
+ - {/* Right Utilities */} -
- {/* Tour */} - - - {/* Language */} -
- - English - -
+ - {/* Live Indicator */} -
- - LIVE -
+ +
- {/* Theme Toggle */} - + {/* Search Bar */} +
+ + +
+
- {/* Notifications */} -
- - - 8 - -
+ {/* Right Utilities */} +
+ - {/* Profile Avatar */} -
- DH -
-
+
+ + English + +
+ +
+ + LIVE +
+ + + +
+ + + 8 + +
+ +
+ DH +
+
+ + ) : ( + /* ================= ADMIN NAVBAR ================= */ + <> + {/* Left Breadcrumb */} +
+ + Administration + + Mobile Flows +
+ + {/* Right Utilities */} +
+
+ + +
+ +
+ + PRODUCTION • us-east-1 +
+ + + +
+ SA +
+
+ + )}
); } \ No newline at end of file diff --git a/components/layouts/sidebar.tsx b/components/layouts/sidebar.tsx index 9ad551b..59c7d0b 100644 --- a/components/layouts/sidebar.tsx +++ b/components/layouts/sidebar.tsx @@ -1,65 +1,78 @@ -import { SIDEBAR_ITEMS } from "@/constants/constant"; +"use client"; + +import { OPERATIONS_SIDEBAR_ITEMS, ADMIN_SIDEBAR_ITEMS } from "@/constants/constant"; import SidebarItem from "./sideBarItem"; -import { - ShieldCheck, - Activity, - ChevronDown, - ChevronsLeft, -} from "lucide-react"; +import { ShieldCheck, Activity, ChevronDown, ChevronsLeft } from "lucide-react"; import { useSession, signOut } from "next-auth/react"; +import { useNav } from "./context/navContext"; + + export default function Sidebar() { const { data: session } = useSession(); - console.log("Session data ",session?.user?.name) -console.log("Session data ",session?.user?.email) + const { mode, setMode } = useNav(); + + const currentItems = mode === "operations" ? OPERATIONS_SIDEBAR_ITEMS : ADMIN_SIDEBAR_ITEMS; + return ( - ); } \ No newline at end of file diff --git a/constants/constant.ts b/constants/constant.ts index f7c79ec..3bef635 100644 --- a/constants/constant.ts +++ b/constants/constant.ts @@ -1,5 +1,4 @@ - import { TableRowData } from '@/types/types'; import { LayoutGrid, Smile, @@ -36,11 +35,16 @@ import { Wallet, Radar, Cog, + Smartphone, + Users, + Database, + Globe, + LayoutDashboard, } from "lucide-react"; //Side bar Drop Down menu -export const SIDEBAR_ITEMS = [ +export const OPERATIONS_SIDEBAR_ITEMS = [ { title: "Overview", icon: LayoutGrid, @@ -130,6 +134,31 @@ export const SIDEBAR_ITEMS = [ { title: "Settings", href: "/configure/settings", icon: Sun },], }, ]; +export const ADMIN_SIDEBAR_ITEMS = [ + { + title: "Platform", + icon: Building2, + children: [ + { title: "Overview", href: "/admin/overview", icon: LayoutGrid }, + { title: "Tenants", href: "/admin/tenants", icon: Building2 }, + { title: "Users", href: "/admin/users", icon: Users }, + { title: "Sites", href: "/admin/sites", icon: MapPin }, + { title: "Security", href: "/admin/security", icon: Shield }, + ], + }, + { + title: "Configuration", + icon: LayoutGrid, + children: [ + { title: "Modules", href: "/admin/configuration/modules", icon: LayoutGrid }, + { title: "Language", href: "/admin/configuration/language", icon: Globe }, + { title: "Dynamic Dashboard", href: "/admin/configuration/dynamic-dashboard", icon: LayoutDashboard }, + { title: "Mobile Flows", href: "/admin/configuration/mobile-flows", icon: Smartphone }, + ], + }, +]; + + //Overview dashboard data @@ -147,6 +176,8 @@ export const chartData = [ { month: 'N', height: 'h-26' }, { month: 'D', height: 'h-24' }, ]; + + export const energyData = [ { month: "Jan", height: 'h-20' }, { month: "Feb", height: 'h-12' }, @@ -197,8 +228,15 @@ export const equipmentTabs: string[] = [ 'AMC Schedule', 'Maintenance Calendar' ]; - export const helpdeskTtabs: string[] = ['Location', 'Technical', - 'Missed', 'Departments', 'HSQE']; + + + + export const helpdeskTtabs: string[] = + ['Location', + 'Technical', + 'Missed', + 'Departments', + 'HSQE'];