Changes done in ui screens

This commit is contained in:
2026-07-28 19:11:10 +05:30
parent b8e833dbb9
commit 7ce1f2705e
33 changed files with 1944 additions and 1248 deletions

View File

@@ -4,7 +4,7 @@
import AlarmRulesPortal from "@/components/dashboard/iotapplication/alarmsRules"; import AlarmRulesPortal from "@/components/dashboard/iotapplication/alarmsRules";
import DeviceFleetPortal from "@/components/dashboard/iotapplication/deviceFleet";

View File

@@ -7,7 +7,7 @@ type TableProps = {
export default function Table({ headers, rows }: TableProps) { export default function Table({ headers, rows }: TableProps) {
return ( return (
<div className="w-full overflow-hidden rounded-2xl border <div className="w-full overflow-hidden border
border-slate-800 bg-[#0B1727] shadow-xl"> border-slate-800 bg-[#0B1727] shadow-xl">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<table className="w-full border-collapse text-[12px]"> <table className="w-full border-collapse text-[12px]">

View File

@@ -22,12 +22,12 @@ export default function AuditSurveyPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">COMPLIANCE</span> <span className="text-slate-400">COMPLIANCE</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">AUDIT & SURVEY</span> <span className="text-slate-400">AUDIT & SURVEY</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Audit & survey management Audit & survey management

View File

@@ -21,12 +21,12 @@ export default function ContractsPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<span>Apple One HQ Tower</span> <span>Apple One HQ Tower</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">COMPLIANCE</span> <span className="text-slate-400">COMPLIANCE</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500"> Contracts</span> <span className="text-slate-400"> Contracts</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Contract management Contract management

View File

@@ -23,12 +23,12 @@ export default function FireSafetyPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">COMPLIANCE</span> <span className="text-slate-400">COMPLIANCE</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500"> FIRE & SAFETY</span> <span className="text-slate-400"> FIRE & SAFETY</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Fire & safety management Fire & safety management
@@ -102,7 +102,7 @@ export default function FireSafetyPortal() {
{/* --- MAIN CONTENT LAYOUT --- */} {/* --- MAIN CONTENT LAYOUT --- */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
{/* Left Column: Safety equipment inspection Table */} {/* Left Column: Safety equipment inspection Table */}
<div className="lg:col-span-2 rounded-xl border border-slate-800/80 bg-[#071321]/80 p-5"> <div className="lg:col-span-2 rounded-xl border border-slate-800/80 p-5">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h2 className="text-base font-bold text-slate-100"> <h2 className="text-base font-bold text-slate-100">
Safety equipment inspection Safety equipment inspection

View File

@@ -1,4 +1,4 @@
import { useState } from 'react';
import { import {
Layers, Layers,
ShieldCheck, ShieldCheck,
@@ -32,12 +32,12 @@ export default function StatutoryCompliancePortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>Compliance</span> <span className="text-gray-400">Compliance</span>
<span></span> <span className="text-gray-600"></span>
<span>Statutory</span> <span className="text-gray-400">Statutory</span>
</div> </div>
<h1 className="text-2xl font-extrabold text-white tracking-tight mt-1.5"> <h1 className="text-2xl font-extrabold text-white tracking-tight mt-1.5">
Statutory compliance tracker Statutory compliance tracker

View File

@@ -1,10 +1,8 @@
import { useState } from 'react'; import { useState } from 'react';
import { import {
ShieldCheck,
Clock,
AlertTriangle, AlertTriangle,
Calendar,
Layers,
Plus, Plus,
GraduationCap, GraduationCap,
Star, Star,
@@ -28,12 +26,12 @@ export default function TrainingPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">COMPLIANCE</span> <span className="text-slate-400">COMPLIANCE</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">TRAINING</span> <span className="text-slate-400">TRAINING</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Training & onboarding Training & onboarding

View File

@@ -20,12 +20,12 @@ export default function WasteESGPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">SUSTAINABILITY</span> <span className="text-slate-400">SUSTAINABILITY</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">WASTE</span> <span className="text-slate-400">WASTE</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Waste management Waste management
@@ -97,7 +97,7 @@ export default function WasteESGPortal() {
</div> </div>
{/* --- MAIN CONTENT SECTION BELOW STAT CARDS --- */} {/* --- MAIN CONTENT SECTION BELOW STAT CARDS --- */}
<div className="grid grid-cols-1 lg:grid-cols-5 gap-4 mb-6"> <div className="grid grid-cols-1 lg:grid-cols-5 gap-4 mb-4">
{/* Waste by Stream Progress Chart */} {/* Waste by Stream Progress Chart */}
<div className="lg:col-span-3 rounded-xl border border-slate-800/80 bg-[#071321]/80 p-5 flex flex-col justify-between"> <div className="lg:col-span-3 rounded-xl border border-slate-800/80 bg-[#071321]/80 p-5 flex flex-col justify-between">
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">

View File

@@ -1,25 +1,24 @@
"use client"; "use client";
import React, { useState } from "react"; import { useState } from "react";
import { Plus, QrCode, Sparkles } from "lucide-react"; import { Plus, } from "lucide-react";
import Button from "@/components/common/button";
import { blocks, floors, zones } from "@/constants/constant";
export default function MasterDataPortal() { export default function MasterDataPortal() {
const [activeTab, setActiveTab] = useState("Block / Floor / Zone"); const [activeTab, setActiveTab] = useState("Block / Floor / Zone");
// Sample data for the hierarchy cards // Sample data for the hierarchy cards
const blocks = ["Block 1", "Block 2", "Tower A"];
const floors = ["Ground", "Floor 1", "Floor 2"];
const zones = ["Zone N", "Zone Z1", "Zone Z2"];
return ( return (
<div className=" text-slate-100 font-sans my-15"> <div className=" text-slate-100 font-sans my-15">
{/* --- BREADCRUMB --- */} {/* --- BREADCRUMB --- */}
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<span>APPLE ONE HQ TOWER</span> <span>APPLE ONE HQ TOWER</span>
<span className="text-slate-600"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">CONFIGURE</span> <span className="text-slate-400">CONFIGURE</span>
<span className="text-slate-600"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">MASTER DATA</span> <span className="text-slate-400">MASTER DATA</span>
</div> </div>
{/* --- PAGE HEADER --- */} {/* --- PAGE HEADER --- */}
@@ -40,7 +39,7 @@ export default function MasterDataPortal() {
<span className="text-[10px] uppercase font-mono tracking-wider text-slate-500 font-bold"> <span className="text-[10px] uppercase font-mono tracking-wider text-slate-500 font-bold">
SITE & LOCATION SITE & LOCATION
</span> </span>
<button <Button
onClick={() => setActiveTab("Block / Floor / Zone")} onClick={() => setActiveTab("Block / Floor / Zone")}
className={`px-3 py-1.5 rounded-lg border text-xs font-semibold transition-all ${ className={`px-3 py-1.5 rounded-lg border text-xs font-semibold transition-all ${
activeTab === "Block / Floor / Zone" activeTab === "Block / Floor / Zone"
@@ -49,7 +48,7 @@ export default function MasterDataPortal() {
}`} }`}
> >
Block / Floor / Zone Block / Floor / Zone
</button> </Button>
</div> </div>
{/* ASSETS */} {/* ASSETS */}
@@ -59,7 +58,7 @@ export default function MasterDataPortal() {
</span> </span>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{["Manufacturer", "Service Provider", "Criticality"].map((item) => ( {["Manufacturer", "Service Provider", "Criticality"].map((item) => (
<button <Button
key={item} key={item}
onClick={() => setActiveTab(item)} onClick={() => setActiveTab(item)}
className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${ className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${
@@ -69,7 +68,7 @@ export default function MasterDataPortal() {
}`} }`}
> >
{item} {item}
</button> </Button>
))} ))}
</div> </div>
</div> </div>
@@ -81,7 +80,7 @@ export default function MasterDataPortal() {
</span> </span>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{["Service Type", "Unit", "Store", "Partners"].map((item) => ( {["Service Type", "Unit", "Store", "Partners"].map((item) => (
<button <Button
key={item} key={item}
onClick={() => setActiveTab(item)} onClick={() => setActiveTab(item)}
className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${ className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${
@@ -91,7 +90,7 @@ export default function MasterDataPortal() {
}`} }`}
> >
{item} {item}
</button> </Button>
))} ))}
</div> </div>
</div> </div>
@@ -103,7 +102,7 @@ export default function MasterDataPortal() {
</span> </span>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{["Budget Category", "Budget Type"].map((item) => ( {["Budget Category", "Budget Type"].map((item) => (
<button <Button
key={item} key={item}
onClick={() => setActiveTab(item)} onClick={() => setActiveTab(item)}
className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${ className={`px-3 py-1.5 rounded-lg border text-xs transition-all ${
@@ -113,7 +112,7 @@ export default function MasterDataPortal() {
}`} }`}
> >
{item} {item}
</button> </Button>
))} ))}
</div> </div>
</div> </div>
@@ -125,7 +124,7 @@ export default function MasterDataPortal() {
PEOPLE PEOPLE
</span> </span>
<div> <div>
<button <Button
onClick={() => setActiveTab("Course")} onClick={() => setActiveTab("Course")}
className={`px-3 py-1.5 rounded-lg border text-xs font-semibold transition-all ${ className={`px-3 py-1.5 rounded-lg border text-xs font-semibold transition-all ${
activeTab === "Course" activeTab === "Course"
@@ -134,7 +133,7 @@ export default function MasterDataPortal() {
}`} }`}
> >
Course Course
</button> </Button>
</div> </div>
</div> </div>
</div> </div>
@@ -200,18 +199,18 @@ export default function MasterDataPortal() {
<span className="flex items-center gap-1 text-[10px] font-mono font-bold text-emerald-400 uppercase tracking-wider"> <span className="flex items-center gap-1 text-[10px] font-mono font-bold text-emerald-400 uppercase tracking-wider">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> ACTIVE <span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> ACTIVE
</span> </span>
<button className="text-[11px] text-slate-400 border border-slate-800 bg-slate-900/60 hover:bg-slate-800 px-2.5 py-1 rounded-md transition-colors"> <Button className="text-[11px] text-slate-400 border border-slate-800 bg-slate-900/60 hover:bg-slate-800 px-2.5 py-1 rounded-md transition-colors">
Remove Remove
</button> </Button>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
<button className="mt-6 flex items-center gap-1.5 text-xs font-bold text-emerald-400 hover:text-emerald-300 transition-colors w-fit"> <Button className="mt-6 flex items-center gap-1.5 text-xs font-bold text-emerald-400 hover:text-emerald-300 transition-colors w-fit">
<Plus className="w-3.5 h-3.5 stroke-[3]" /> <Plus className="w-3.5 h-3.5 stroke-[3]" />
<span>Add floor</span> <span>Add floor</span>
</button> </Button>
</div> </div>
{/* Zone Column */} {/* Zone Column */}
@@ -229,22 +228,23 @@ export default function MasterDataPortal() {
<span className="flex items-center gap-1 text-[10px] font-mono font-bold text-emerald-400 uppercase tracking-wider"> <span className="flex items-center gap-1 text-[10px] font-mono font-bold text-emerald-400 uppercase tracking-wider">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> ACTIVE <span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span> ACTIVE
</span> </span>
<button className="text-[11px] text-slate-400 border border-slate-800 bg-slate-900/60 hover:bg-slate-800 px-2.5 py-1 rounded-md transition-colors"> <Button className="text-[11px] text-slate-400 border border-slate-800 bg-slate-900/60 hover:bg-slate-800 px-2.5 py-1 rounded-md transition-colors">
Remove Remove
</button> </Button>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
<button className="mt-6 flex items-center gap-1.5 text-xs font-bold text-emerald-400 hover:text-emerald-300 transition-colors w-fit"> <Button className="mt-6 flex items-center gap-1.5 text-xs font-bold text-emerald-400 hover:text-emerald-300 transition-colors w-fit">
<Plus className="w-3.5 h-3.5 stroke-[3]" /> <Plus className="w-3.5 h-3.5 stroke-[3]" />
<span>Add zone</span> <span>Add zone</span>
</button> </Button>
</div> </div>
</div> </div>
</div> </div>
); );
} }

View File

@@ -3,61 +3,9 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Check } from "lucide-react"; import { Check } from "lucide-react";
import Button from "@/components/common/button"; import Button from "@/components/common/button";
import { initialPermissions, rolesList } from "@/constants/constant";
// Initial roles state
const rolesList = [
{ id: "admin", label: "Admin", badge: "all" },
{ id: "helpdesk", label: "Helpdesk", badge: "scoped" },
{ id: "mne_supervisor", label: "M&E Supervisor", badge: "scoped" },
{ id: "technician", label: "Technician", badge: "scoped" },
{ id: "tenant", label: "Tenant", badge: "scoped" },
];
// Initial permissions table data
const initialPermissions = [
{
id: 1,
module: "Help Desk",
menu: "Daily Location Checklist",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 2,
module: "Equipment",
menu: "Site-Wise Equipment",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 3,
module: "Equipment",
menu: "AMC Schedule",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 4,
module: "Request",
menu: "TFM Request",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 5,
module: "Energy",
menu: "Meter Reading",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 6,
module: "Master",
menu: "Request Location",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
{
id: 7,
module: "Security",
menu: "Users",
permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
},
];
export default function RolesAccessPortal() { export default function RolesAccessPortal() {
const [activeTopTab, setActiveTopTab] = useState("Roles & Permissions"); const [activeTopTab, setActiveTopTab] = useState("Roles & Permissions");
@@ -68,16 +16,16 @@ export default function RolesAccessPortal() {
return ( return (
<div className="my-15 text-slate-100 font-sans"> <div className="my-15 text-slate-100 font-sans">
{/* --- BREADCRUMB --- */} {/* --- BREADCRUMB --- */}
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<span>APPLE ONE HQ TOWER</span> <span>APPLE ONE HQ TOWER</span>
<span className="text-slate-600"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">CONFIGURE</span> <span className="text-slate-400">CONFIGURE</span>
<span className="text-slate-600"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">ROLES & ACCESS</span> <span className="text-slate-400">ROLES & ACCESS</span>
</div> </div>
{/* --- PAGE HEADER --- */} {/* --- PAGE HEADER --- */}
<h1 className="text-3xl font-bold text-white tracking-tight mt-1"> <h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Roles & access Roles & access
</h1> </h1>
<p className="text-sm font-medium text-slate-400 mt-2 max-w-2xl leading-relaxed"> <p className="text-sm font-medium text-slate-400 mt-2 max-w-2xl leading-relaxed">
@@ -88,7 +36,7 @@ export default function RolesAccessPortal() {
{/* --- MAIN TABS --- */} {/* --- MAIN TABS --- */}
<div className="flex items-center gap-8 border-b border-slate-800/80 mt-8 text-sm font-semibold"> <div className="flex items-center gap-8 border-b border-slate-800/80 mt-8 text-sm font-semibold">
{["Roles & Permissions", "Tenant Access", "Escalation Matrix"].map((tab) => ( {["Roles & Permissions", "Tenant Access", "Escalation Matrix"].map((tab) => (
<button <Button
key={tab} key={tab}
onClick={() => setActiveTopTab(tab)} onClick={() => setActiveTopTab(tab)}
className={`pb-3 relative transition-colors ${ className={`pb-3 relative transition-colors ${
@@ -101,7 +49,7 @@ export default function RolesAccessPortal() {
{activeTopTab === tab && ( {activeTopTab === tab && (
<span className="absolute bottom-0 left-0 right-0 h-0.5 bg-emerald-400 rounded-full" /> <span className="absolute bottom-0 left-0 right-0 h-0.5 bg-emerald-400 rounded-full" />
)} )}
</button> </Button>
))} ))}
</div> </div>
@@ -112,7 +60,7 @@ export default function RolesAccessPortal() {
{rolesList.map((role) => { {rolesList.map((role) => {
const isSelected = selectedRole === role.id; const isSelected = selectedRole === role.id;
return ( return (
<button <Button
key={role.id} key={role.id}
onClick={() => setSelectedRole(role.id)} onClick={() => setSelectedRole(role.id)}
className={`w-full flex items-center justify-between px-5 py-4 text-left transition-all relative ${ className={`w-full flex items-center justify-between px-5 py-4 text-left transition-all relative ${
@@ -136,7 +84,7 @@ export default function RolesAccessPortal() {
> >
{role.badge} {role.badge}
</span> </span>
</button> </Button>
); );
})} })}
</div> </div>
@@ -176,8 +124,8 @@ export default function RolesAccessPortal() {
const isChecked = row.permissions[permKey]; const isChecked = row.permissions[permKey];
return ( return (
<td key={permKey} className="py-4 px-4 text-center"> <td key={permKey} className="py-4 px-4 text-center">
<button <Button
type="button"
className={`w-5 h-5 rounded flex items-center justify-center transition-all border mx-auto ${ className={`w-5 h-5 rounded flex items-center justify-center transition-all border mx-auto ${
isChecked isChecked
@@ -186,7 +134,7 @@ export default function RolesAccessPortal() {
}`} }`}
> >
{isChecked && <Check className="w-3.5 h-3.5 stroke-[3]" />} {isChecked && <Check className="w-3.5 h-3.5 stroke-[3]" />}
</button> </Button>
</td> </td>
); );
} }

View File

@@ -26,29 +26,23 @@ export default function SettingsPortal() {
return ( return (
<div className="my-15 text-slate-200 font-sans"> <div className="my-15 text-slate-200 font-sans">
{/* Top Header & Breadcrumb */} {/* Top Header & Breadcrumb */}
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<div> <span>APPLE ONE HQ TOWER</span>
<div className="text-xs uppercase tracking-wider text-slate-400 mb-2 font-medium"> <span className="text-slate-600"></span>
<span className="hover:text-slate-200 cursor-pointer"> <span className="text-slate-400">CONFIGURE</span>
APPLE ONE HQ TOWER <span className="text-slate-600"></span>
</span>{" "} <span className="text-slate-400">SETTINGS</span>
<span className="hover:text-slate-200 cursor-pointer">CONFIGURE</span>{" "}
<span className="text-slate-300">SETTINGS</span>
</div>
<h1 className="text-2xl font-bold text-white mb-1">Settings</h1>
<p className="text-slate-400 text-sm">
Personal and notification preferences for this tenant workspace.
</p>
</div>
{/* Save Changes Button */}
<div>
<button className="bg-[#2DD4BF] hover:bg-[#26b8a5] text-[#070D19] font-semibold text-sm px-5 py-2.5 rounded-lg transition-colors shadow-sm">
Save changes
</button>
</div>
</div> </div>
{/* --- PAGE HEADER --- */}
<h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Settings
</h1>
<p className="text-sm font-medium text-slate-400 mt-2 max-w-2xl leading-relaxed">
Personal and notification preferences for this tenant workspace.
</p>
{/* Main Grid Layout */} {/* Main Grid Layout */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
{/* Left Column: App Settings */} {/* Left Column: App Settings */}
@@ -66,7 +60,7 @@ export default function SettingsPortal() {
<p className="text-xs text-slate-400">Workspace loaded on sign-in</p> <p className="text-xs text-slate-400">Workspace loaded on sign-in</p>
</div> </div>
<select <select
value={appSettings.defaultTenant}
className="bg-[#080E21] border border-slate-700/80 text-slate-200 text-xs rounded-lg px-3 py-2 w-full sm:w-48 focus:outline-none focus:border-[#2DD4BF] cursor-pointer" className="bg-[#080E21] border border-slate-700/80 text-slate-200 text-xs rounded-lg px-3 py-2 w-full sm:w-48 focus:outline-none focus:border-[#2DD4BF] cursor-pointer"
> >

View File

@@ -1,71 +1,38 @@
"use client"; "use client";
import Button from "@/components/common/button";
import { userData } from "@/constants/constant";
import React, { useState } from "react"; import React, { useState } from "react";
// Mock user location data matching the screenshot
const userData = [
{
name: "Dhananjay T.",
email: "dhananjay@kafm.io",
mobile: "7489477369",
latitude: "18.5450",
longitude: "73.7935",
site: "Apple One",
// Relative coordinates for the map visual dots (X%, Y%)
x: "19%",
y: "38%",
},
{
name: "ME Local",
email: "me.local@kafm.io",
mobile: "9876543210",
latitude: "18.5469",
longitude: "73.7945",
site: "Apple One",
x: "44%",
y: "43%",
},
{
name: "TECH Local",
email: "tech.local@kafm.io",
mobile: "9123456780",
latitude: "18.5441",
longitude: "73.7951",
site: "Apple One",
x: "69%",
y: "48%",
},
];
export default function UserLocationPortal() { export default function UserLocationPortal() {
const [viewMode, setViewMode] = useState<"map" | "table">("table"); const [viewMode, setViewMode] = useState<"map" | "table">("table");
const [mapType, setMapType] = useState<"MAP" | "SATELLITE">("MAP"); const [mapType, setMapType] = useState<"MAP" | "SATELLITE">("MAP");
return ( return (
<div className="my-15 text-slate-200 font-sans"> <div className="my-15 min-h-screen h-full text-slate-200 font-sans">
{/* Top Breadcrumb & Header */} {/* Top Breadcrumb & Header */}
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
{/* Breadcrumb */} <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<div className="text-xs uppercase tracking-wider text-slate-400 mb-2 font-medium"> <span className="text-teal-400">APPLE ONE HQ TOWER</span>
<span className="hover:text-slate-200 cursor-pointer"> <span className="text-slate-600"></span>
APPLE ONE HQ TOWER <span className="text-slate-400">CONFIGURE</span>
</span>{" "} <span className="text-slate-600"></span>
<span className="hover:text-slate-200 cursor-pointer">CONFIGURE</span>{" "} <span className="text-slate-400">USER LOCATION</span>
<span className="text-slate-300">USER LOCATION</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2">
{/* Main Title */} User location
<h1 className="text-3xl font-bold text-white mb-2">User location</h1> </h1>
<p className="text-slate-400 text-sm max-w-2xl leading-relaxed"> <p className="text-sm font-medium text-slate-400 mt-2 max-w-xl leading-relaxed">
Live position of active technicians, captured from the mobile app. Map Live position of active technicians, captured from the mobile app. Map and table views.
and table views.
</p> </p>
</div> </div>
{/* View Switcher Buttons */} {/* View Switcher Buttons */}
<div className="flex bg-[#0F172A] p-1 rounded-lg border border-slate-800 self-start md:self-auto"> <div className="flex bg-[#0F172A] p-1 rounded-lg border border-slate-800 self-start md:self-auto">
<button <Button
onClick={() => setViewMode("map")} onClick={() => setViewMode("map")}
className={`px-4 py-2 rounded-md text-sm font-medium transition-all ${ className={`px-4 py-2 rounded-md text-sm font-medium transition-all ${
viewMode === "map" viewMode === "map"
@@ -74,8 +41,8 @@ export default function UserLocationPortal() {
}`} }`}
> >
Map view Map view
</button> </Button>
<button <Button
onClick={() => setViewMode("table")} onClick={() => setViewMode("table")}
className={`px-4 py-2 rounded-md text-sm font-medium transition-all ${ className={`px-4 py-2 rounded-md text-sm font-medium transition-all ${
viewMode === "table" viewMode === "table"
@@ -84,7 +51,7 @@ export default function UserLocationPortal() {
}`} }`}
> >
Table view Table view
</button> </Button>
</div> </div>
</div> </div>
@@ -139,23 +106,23 @@ export default function UserLocationPortal() {
{/* Map Type Toggle (Bottom Right of Map Area) */} {/* Map Type Toggle (Bottom Right of Map Area) */}
<div className="absolute bottom-2 right-4 flex items-center space-x-2 text-[10px] font-mono tracking-wider text-slate-500"> <div className="absolute bottom-2 right-4 flex items-center space-x-2 text-[10px] font-mono tracking-wider text-slate-500">
<button <Button
onClick={() => setMapType("MAP")} onClick={() => setMapType("MAP")}
className={`hover:text-slate-300 transition-colors ${ className={`hover:text-slate-300 transition-colors ${
mapType === "MAP" ? "text-slate-300 font-bold" : "" mapType === "MAP" ? "text-slate-300 font-bold" : ""
}`} }`}
> >
MAP MAP
</button> </Button>
<span></span> <span></span>
<button <Button
onClick={() => setMapType("SATELLITE")} onClick={() => setMapType("SATELLITE")}
className={`hover:text-slate-300 transition-colors ${ className={`hover:text-slate-300 transition-colors ${
mapType === "SATELLITE" ? "text-slate-300 font-bold" : "" mapType === "SATELLITE" ? "text-slate-300 font-bold" : ""
}`} }`}
> >
SATELLITE SATELLITE
</button> </Button>
</div> </div>
</div> </div>

View File

@@ -19,12 +19,12 @@ export default function WorkFlowAutomationPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest uppercase font-mono">
<span className="text-teal-400">APPLE ONE HQ TOWER</span> <span className="text-teal-400">APPLE ONE HQ TOWER</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">CONFIGURE</span> <span className="text-slate-400">CONFIGURE</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">AUTOMATION</span> <span className="text-slate-400">AUTOMATION</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Workflow automation Workflow automation
@@ -113,9 +113,9 @@ export default function WorkFlowAutomationPortal() {
<span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase"> <span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase">
WHEN WHEN
</span> </span>
<button className="px-3.5 py-1.5 rounded-lg border border-[#2DD4BF]/40 text-[#2DD4BF] text-xs font-mono font-medium transition-colors"> <Button className="px-3.5 py-1.5 rounded-lg border border-[#2DD4BF]/40 text-[#2DD4BF] text-xs font-mono font-medium transition-colors">
Trigger event Trigger event
</button> </Button>
</div> </div>
{/* IF Step */} {/* IF Step */}
@@ -123,9 +123,9 @@ export default function WorkFlowAutomationPortal() {
<span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase"> <span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase">
IF IF
</span> </span>
<button className="px-3.5 py-1.5 rounded-lg border border-slate-700 text-slate-300 text-xs font-mono font-medium transition-colors"> <Button className="px-3.5 py-1.5 rounded-lg border border-slate-700 text-slate-300 text-xs font-mono font-medium transition-colors">
Condition Condition
</button> </Button>
</div> </div>
{/* THEN Step */} {/* THEN Step */}
@@ -133,9 +133,9 @@ export default function WorkFlowAutomationPortal() {
<span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase"> <span className="text-[10px] font-mono tracking-widest text-slate-400 uppercase">
THEN THEN
</span> </span>
<button className="px-3.5 py-1.5 rounded-lg border border-[#2DD4BF]/30 text-[#2DD4BF] text-xs font-mono font-medium transition-colors"> <Button className="px-3.5 py-1.5 rounded-lg border border-[#2DD4BF]/30 text-[#2DD4BF] text-xs font-mono font-medium transition-colors">
Action Action
</button> </Button>
</div> </div>
</div> </div>

View File

@@ -12,6 +12,9 @@ import StatCard from "@/components/common/dashStatCard";
import { Card } from '@/components/common/cardWrapper'; import { Card } from '@/components/common/cardWrapper';
import { CardHeader } from '@/components/common/cardHeader'; import { CardHeader } from '@/components/common/cardHeader';
import { approvalQueueData, categoryData } from "@/constants/constant"; import { approvalQueueData, categoryData } from "@/constants/constant";
import Table from "@/components/common/dataTable";
import { budgetPerformanceRows } from "@/constants/tabledata";
import { budgetPerformanceHeaders } from "@/constants/tabledata";
@@ -21,12 +24,12 @@ export default function BudgetPortal() {
{/* --- HEADER SECTION WITH BUTTONS --- */} {/* --- HEADER SECTION WITH BUTTONS --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>FINANCE</span> <span className="text-gray-400">FINANCE</span>
<span></span> <span className="text-gray-600"></span>
<span>O&M BUDGET</span> <span className="text-gray-400">O&M BUDGET</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
@@ -99,63 +102,23 @@ export default function BudgetPortal() {
</div> </div>
{/* --- BUDGET DETAILS & APPROVAL QUEUE SECTION --- */} {/* --- BUDGET DETAILS & APPROVAL QUEUE SECTION --- */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8"> <div className="grid grid-cols-2 gap-3 mb-8">
{/* Planned vs Actual Table (Left 2 Columns) */} {/* Planned vs Actual Table (Left 2 Columns) */}
<Card className="lg:col-span-2 justify-start"> <div className=" border border-slate-800/80 rounded-lg ">
<CardHeader <div className="flex items-center justify-between
title="Planned vs actual · by category" px-4 py-4 border-b border-slate-800/80">
subtitle="CAPEX ₹35.0 L • OPEX ₹1.56 Cr" <h2 className="text-base font-semibold text-white">
/> Planned vs actual·by category</h2>
</div>
{/* Corrected column layout and removed horizontal scrollbar to align with the right UI. */}
<Table headers={budgetPerformanceHeaders} rows={budgetPerformanceRows} />
</div>
<div className="overflow-x-auto mt-2">
<table className="w-full text-left border-collapse">
<thead>
<tr className="border-b border-[#162942]/60 text-[11px] font-mono font-bold text-slate-500 uppercase tracking-wider">
<th className="py-2.5 px-2">Category</th>
<th className="py-2.5 px-2">Type</th>
<th className="py-2.5 px-2 font-mono">Planned</th>
<th className="py-2.5 px-2 font-mono">Actual</th>
<th className="py-2.5 px-2 font-mono">Variance</th>
<th className="py-2.5 px-2 font-mono min-w-[120px]">Utilization</th>
</tr>
</thead>
<tbody className="divide-y divide-[#162942]/40 text-xs">
{categoryData.map((row, idx) => (
<tr key={idx} className="hover:bg-slate-900/30 transition-colors">
<td className="py-3 px-2 font-semibold text-slate-100">
{row.category}
</td>
<td className="py-3 px-2">
<span className="bg-[#12233a] border border-[#1d3554] text-slate-300 font-mono text-[10px] px-2 py-0.5 rounded">
{row.type}
</span>
</td>
<td className="py-3 px-2 font-mono text-slate-300">
{row.planned}
</td>
<td className="py-3 px-2 font-mono text-slate-300">
{row.actual}
</td>
<td className={`py-3 px-2 font-mono font-semibold ${row.varianceColor}`}>
{row.variance}
</td>
<td className="py-3 px-2">
<div className="w-full bg-[#12233a] h-1.5 rounded-full overflow-hidden mb-1">
<div
className={`h-full ${row.barColor}`}
style={{ width: `${Math.min(row.utilization, 100)}%` }}
/>
</div>
<span className="text-[10px] font-mono text-slate-400">
{row.utilization}%
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
{/* Approval Queue Panel (Right 1 Column) */} {/* Approval Queue Panel (Right 1 Column) */}
<Card className="justify-start"> <Card className="justify-start">
@@ -174,9 +137,9 @@ export default function BudgetPortal() {
</div> </div>
{item.status === "pending" ? ( {item.status === "pending" ? (
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-200 text-xs font-semibold px-3 py-1 rounded transition-colors whitespace-nowrap"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-200 text-xs font-semibold px-3 py-1 rounded transition-colors whitespace-nowrap">
Approve Approve
</button> </Button>
) : ( ) : (
<span className="flex items-center gap-1.5 bg-emerald-950/40 border border-emerald-800/30 text-emerald-400 text-[10px] font-mono font-bold px-2.5 py-1 rounded-full whitespace-nowrap"> <span className="flex items-center gap-1.5 bg-emerald-950/40 border border-emerald-800/30 text-emerald-400 text-[10px] font-mono font-bold px-2.5 py-1 rounded-full whitespace-nowrap">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" /> <span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />

View File

@@ -22,12 +22,12 @@ export default function CostInvoicePortal() {
{/* --- HEADER SECTION WITH BUTTONS --- */} {/* --- HEADER SECTION WITH BUTTONS --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>FINANCE</span> <span className="text-gray-400">FINANCE</span>
<span></span> <span className="text-gray-400"></span>
<span>COSTING & INVOICING</span> <span className="text-gray-400">COSTING & INVOICING</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Plus, Download } from 'lucide-react';
import Button from "@/components/common/button"; import Button from "@/components/common/button";
import NavigationTabs from '@/components/common/tabs'; import NavigationTabs from '@/components/common/tabs';
import { reportFilters, reporttabs, Reqeusttabs, statusFilters } from '@/constants/constant'; import { reportFilters, reporttabs, Reqeusttabs, statusFilters } from '@/constants/constant';
@@ -22,12 +22,12 @@ export default function ReportPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>INSIGHT</span> <span className="text-gray-400">INSIGHT</span>
<span></span> <span className="text-gray-600"></span>
<span>REPORTS</span> <span className="text-gray-400">REPORTS</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Reports & MMR Reports & MMR
@@ -59,11 +59,11 @@ export default function ReportPortal() {
onChange={setActiveFilter} onChange={setActiveFilter}
/> />
<button <Button
className="inline-flex items-center gap-2 rounded-xl bg-teal-400 px-5 py-2.5 text-sm font-semibold text-slate-950 hover:bg-teal-300 transition-colors focus:outline-none focus:ring-2 focus:ring-teal-400/50 shrink-0" className="inline-flex items-center gap-2 rounded-xl bg-teal-400 px-5 py-2.5 text-sm font-semibold text-slate-950 hover:bg-teal-300 transition-colors focus:outline-none focus:ring-2 focus:ring-teal-400/50 shrink-0"
> >
Download Download
</button> </Button>
</div> </div>
<div className='mt-5'> <div className='mt-5'>

View File

@@ -22,12 +22,12 @@ export default function AlarmRulesPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<span>APPLE ONE HQ TOWER</span> <span>APPLE ONE HQ TOWER</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">IOT</span> <span className="text-slate-400">IOT</span>
<span className="text-slate-500"></span> <span className="text-slate-600"></span>
<span className="text-slate-500">ALARMS & RULES</span> <span className="text-slate-400">ALARMS & RULES</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-1"> <h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Alarms & automation rules Alarms & automation rules
@@ -237,8 +237,8 @@ export default function AlarmRulesPortal() {
Raises a Help Desk request with the asset and fault pre-filled Raises a Help Desk request with the asset and fault pre-filled
</p> </p>
</div> </div>
<button <Button
type="button"
onClick={() => setAutoWorkOrder(!autoWorkOrder)} onClick={() => setAutoWorkOrder(!autoWorkOrder)}
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${ className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
autoWorkOrder ? 'bg-[#2dd4bf]' : 'bg-slate-700' autoWorkOrder ? 'bg-[#2dd4bf]' : 'bg-slate-700'
@@ -249,7 +249,7 @@ export default function AlarmRulesPortal() {
autoWorkOrder ? 'translate-x-5' : 'translate-x-0' autoWorkOrder ? 'translate-x-5' : 'translate-x-0'
}`} }`}
/> />
</button> </Button>
</div> </div>
{/* Rule 2 */} {/* Rule 2 */}
@@ -262,8 +262,8 @@ export default function AlarmRulesPortal() {
Notifies the escalation matrix after 15 minutes Notifies the escalation matrix after 15 minutes
</p> </p>
</div> </div>
<button <Button
type="button"
onClick={() => setEscalateCriticals(!escalateCriticals)} onClick={() => setEscalateCriticals(!escalateCriticals)}
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${ className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
escalateCriticals ? 'bg-[#2dd4bf]' : 'bg-slate-700' escalateCriticals ? 'bg-[#2dd4bf]' : 'bg-slate-700'
@@ -274,7 +274,7 @@ export default function AlarmRulesPortal() {
escalateCriticals ? 'translate-x-5' : 'translate-x-0' escalateCriticals ? 'translate-x-5' : 'translate-x-0'
}`} }`}
/> />
</button> </Button>
</div> </div>
{/* Rule 3 */} {/* Rule 3 */}
@@ -287,8 +287,8 @@ export default function AlarmRulesPortal() {
Widens comfort bands 22:0006:00 to save energy Widens comfort bands 22:0006:00 to save energy
</p> </p>
</div> </div>
<button <Button
type="button"
onClick={() => setOffHoursSetpoint(!offHoursSetpoint)} onClick={() => setOffHoursSetpoint(!offHoursSetpoint)}
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${ className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
offHoursSetpoint ? 'bg-[#2dd4bf]' : 'bg-slate-700' offHoursSetpoint ? 'bg-[#2dd4bf]' : 'bg-slate-700'
@@ -299,7 +299,7 @@ export default function AlarmRulesPortal() {
offHoursSetpoint ? 'translate-x-5' : 'translate-x-0' offHoursSetpoint ? 'translate-x-5' : 'translate-x-0'
}`} }`}
/> />
</button> </Button>
</div> </div>
{/* Rule 4 */} {/* Rule 4 */}
@@ -312,8 +312,8 @@ export default function AlarmRulesPortal() {
Adds a filter change to the next PPM visit automatically Adds a filter change to the next PPM visit automatically
</p> </p>
</div> </div>
<button <Button
type="button"
onClick={() => setFilterPpmTask(!filterPpmTask)} onClick={() => setFilterPpmTask(!filterPpmTask)}
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${ className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none ${
filterPpmTask ? 'bg-[#2dd4bf]' : 'bg-slate-800' filterPpmTask ? 'bg-[#2dd4bf]' : 'bg-slate-800'
@@ -324,7 +324,7 @@ export default function AlarmRulesPortal() {
filterPpmTask ? 'translate-x-5 bg-slate-950' : 'translate-x-0' filterPpmTask ? 'translate-x-5 bg-slate-950' : 'translate-x-0'
}`} }`}
/> />
</button> </Button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -14,17 +14,17 @@ export default function CommandCenterPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
<span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span> <span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span>
<span></span> <span className='text-gray-600'></span>
<span>IOT</span> <span className='text-gray-400'>IOT</span>
<span></span> <span className='text-gray-600'></span>
<span>COMMAND CENTER</span> <span className='text-gray-400'>COMMAND CENTER</span>
</div> </div>
<h1 className="text-3xl font-bold text-white tracking-tight mt-1"> <h1 className="text-3xl font-bold text-white tracking-tight mt-1">
IoT command center IoT command center
</h1> </h1>
<p className="text-sm text-[#7f93ac] mt-2 max-w-xl leading-relaxed"> <p className="text-sm text-[#7f93ac] font-medium mt-2 max-w-xl leading-relaxed">
Every gateway, controller and sensor across the portfolio on one live board scoped to Apple One. Every gateway, controller and sensor across the portfolio on one live board scoped to Apple One.
</p> </p>
</div> </div>
@@ -192,9 +192,9 @@ export default function CommandCenterPortal() {
<div> <div>
<div className="flex justify-between items-center mb-1"> <div className="flex justify-between items-center mb-1">
<h3 className="font-semibold text-white text-base">Live alarm feed</h3> <h3 className="font-semibold text-white text-base">Live alarm feed</h3>
<button className="text-xs text-[#10b981] font-semibold hover:underline"> <Button className="text-xs text-[#10b981] font-semibold hover:underline">
All alarms All alarms
</button> </Button>
</div> </div>
<p className="text-[11px] text-[#4e6178] font-mono mb-4">streaming</p> <p className="text-[11px] text-[#4e6178] font-mono mb-4">streaming</p>

View File

@@ -1,17 +1,17 @@
import { useState } from 'react';
import { import {
Grid2X2, Grid2X2,
AlertTriangle, AlertTriangle,
Sun, Sun,
Disc, Disc,
Smartphone, Smartphone,
FileText
} from "lucide-react"; } from "lucide-react";
import Button from "@/components/common/button"; import Button from "@/components/common/button";
import StatCard from "@/components/common/dashStatCard"; import StatCard from "@/components/common/dashStatCard";
import InfoBanner from "@/components/common/infoBanner"; import InfoBanner from "@/components/common/infoBanner";
import Table from '@/components/common/dataTable'; import Table from '@/components/common/dataTable';
import { contractheaders, contractrows, devicefleetheaders, devicefleetrows } from '@/constants/tabledata'; import { devicefleetheaders, devicefleetrows } from '@/constants/tabledata';
export default function DeviceFleetPortal() { export default function DeviceFleetPortal() {
return ( return (
@@ -19,12 +19,12 @@ export default function DeviceFleetPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
<span>APPLE ONE HQ TOWER</span> <span>APPLE ONE HQ TOWER</span>
<span className="text-slate-500"></span> <span className="text-gray-600"></span>
<span className="text-slate-500">IOT</span> <span className="text-gray-400">IOT</span>
<span className="text-slate-500"></span> <span className="text-gray-600"></span>
<span className="text-slate-500">DEVICE FLEET</span> <span className="text-gray-400">DEVICE FLEET</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-1"> <h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Gateways, controllers & sensors Gateways, controllers & sensors

View File

@@ -13,17 +13,17 @@ export default function EnergyUtilityPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
<span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span> <span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span>
<span></span> <span className='text-gray-600'></span>
<span>IOT</span> <span className='text-gray-400'>IOT</span>
<span></span> <span className='text-gray-600'></span>
<span>ENERGY & UTILITIES</span> <span className='text-gray-400'>ENERGY & UTILITIES</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-1"> <h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Energy & utilities telemetry Energy & utilities telemetry
</h1> </h1>
<p className="text-sm text-[#7f93ac] mt-2 max-w-xl leading-relaxed"> <p className="text-sm text-[#7f93ac] font-medium mt-2 max-w-xl leading-relaxed">
Live smart-meter streams for power, water and gas the same spine that feeds the Energy module and ESG reporting. Live smart-meter streams for power, water and gas the same spine that feeds the Energy module and ESG reporting.
</p> </p>
</div> </div>

View File

@@ -4,21 +4,8 @@ import Button from "@/components/common/button";
import { Card } from '@/components/common/cardWrapper'; import { Card } from '@/components/common/cardWrapper';
import BarChart from "@/components/charts/barchart"; // Replace path with your actual BarChart component import path import BarChart from "@/components/charts/barchart"; // Replace path with your actual BarChart component import path
import { plantLoadData } from '@/constants/constant';
const plantLoadData = [
{ month: '08', height: 'h-[35%]' },
{ month: '09', height: 'h-[38%]' },
{ month: '10', height: 'h-[32%]' },
{ month: '11', height: 'h-[40%]' },
{ month: '12', height: 'h-[52%]' },
{ month: '13', height: 'h-[68%]' },
{ month: '14', height: 'h-[78%]' },
{ month: '15', height: 'h-[78%]' },
{ month: '16', height: 'h-[78%]' },
{ month: '17', height: 'h-[78%]' },
{ month: '18', height: 'h-[78%]' },
{ month: '19', height: 'h-[78%]' }
];
export default function HVACPlantPortal() { export default function HVACPlantPortal() {
return ( return (
@@ -27,17 +14,17 @@ export default function HVACPlantPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
<span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span> <span className="text-emerald-400 font-bold">APPLE ONE HQ TOWER</span>
<span></span> <span className="text-gray-600"></span>
<span>IOT</span> <span className="text-gray-400">IOT</span>
<span></span> <span className="text-gray-600"></span>
<span>HVAC PLANT</span> <span className="text-gray-400">HVAC PLANT</span>
</div> </div>
<h1 className="text-3xl font-bold text-white tracking-tight mt-1"> <h1 className="text-3xl font-bold text-white tracking-tight mt-1">
Chiller plant & air side Chiller plant & air side
</h1> </h1>
<p className="text-sm text-[#7f93ac] mt-2 max-w-xl leading-relaxed"> <p className="text-sm text-[#7f93ac] font-medium mt-2 max-w-xl leading-relaxed">
Live chiller, AHU and plant telemetry with start/stop control commands are audit-logged. Live chiller, AHU and plant telemetry with start/stop control commands are audit-logged.
</p> </p>
</div> </div>
@@ -221,9 +208,9 @@ export default function HVACPlantPortal() {
<td className="py-3.5 text-slate-500"> / </td> <td className="py-3.5 text-slate-500"> / </td>
<td className="py-3.5 text-slate-400">0</td> <td className="py-3.5 text-slate-400">0</td>
<td className="py-3.5 text-right"> <td className="py-3.5 text-right">
<button className="px-3 py-1 rounded border border-[#162942] text-slate-300 bg-[#0e1c2e] hover:bg-slate-800 text-[11px] font-semibold transition-colors"> <Button className="px-3 py-1 rounded border border-[#162942] text-slate-300 bg-[#0e1c2e] hover:bg-slate-800 text-[11px] font-semibold transition-colors">
Start Start
</button> </Button>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@@ -42,17 +42,35 @@ export default function EnergyPortal() {
</div> </div>
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6 items-start">
{/* --- TABLES GRID (SIDE-BY-SIDE) --- */} {/* LEFT TABLE: STOCK MASTER */}
<div className="grid grid-cols-1 xl:grid-cols-2 gap-2 items-start"> <div className=" border border-slate-800/80 rounded-lg ">
<div className="flex items-center justify-between px-4
py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Meter Master</h2>
</div>
{/* Corrected column layout and removed horizontal scrollbar to align with the right UI. */}
<Table headers={meterHeaders} rows={meterRows}/>
</div>
{/* RIGHT TABLE: CONSUMPTION LEDGER */}
<div className=" w-full border
border-slate-800/80 rounded-lg overflow-hidden">
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Latest Readings</h2>
</div>
<Table headers={readingHeaders} rows={readingRows}/>
</div>
{/* LEFT TABLE: METER MASTER */}
<Table headers={meterHeaders} rows={meterRows}/>
{/* Right table */}
<Table headers={readingHeaders} rows={readingRows}/>
</div> </div>
</div> </div>
); );
} }

View File

@@ -9,7 +9,8 @@ import {
import Button from "@/components/common/button"; import Button from "@/components/common/button";
import StatCard from "@/components/common/dashStatCard"; import StatCard from "@/components/common/dashStatCard";
import InfoBanner from "@/components/common/infoBanner"; import InfoBanner from "@/components/common/infoBanner";
import { consumptionLedger, stockItems } from "@/constants/constant"; import Table from "@/components/common/dataTable";
import { consumptionHeaders, consumptionRows, inventoryHeaders, inventoryRows, } from "@/constants/tabledata";
@@ -104,87 +105,19 @@ export default function InventoryPortal() {
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6 items-start"> <div className="grid grid-cols-1 xl:grid-cols-2 gap-6 items-start">
{/* LEFT TABLE: STOCK MASTER */} {/* LEFT TABLE: STOCK MASTER */}
<div className="bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-hidden"> <div className=" border border-slate-800/80 rounded-lg ">
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80"> <div className="flex items-center justify-between px-4
py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Stock master</h2> <h2 className="text-base font-semibold text-white">Stock master</h2>
<span className="text-xs font-mono text-slate-500">7 items</span> <span className="text-xs font-mono text-slate-500">7 items</span>
</div> </div>
{/* Corrected column layout and removed horizontal scrollbar to align with the right UI. */} {/* Corrected column layout and removed horizontal scrollbar to align with the right UI. */}
<div className=""> <Table headers={inventoryHeaders} rows={inventoryRows} />
<table className="w-full h-full text-left text-sm">
<thead>
<tr className="border-b border-slate-800/60 text-[11px] font-bold uppercase tracking-wider text-slate-400">
<th className="py-3 px-4">Item</th>
<th className="py-3 px-4">Group</th>
<th className="py-3 px-4">Store</th>
<th className="py-3 px-4">Min</th>
<th className="py-3 px-4">Present</th>
<th className="py-3 px-4">Status</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/40">
{stockItems.map((row, index) => {
const isOverdue = row.status === "OVERDUE";
return (
<tr
key={index}
className={`transition-colors relative ${
row.isHighlighted
? "bg-[#0e2238]"
: "hover:bg-slate-800/30"
}`}
>
<td className="py-3 px-4 font-semibold text-slate-100 relative">
{row.isHighlighted && (
<div className="absolute left-0 top-0 bottom-0 w-[3px] bg-teal-400" />
)}
{row.item}
</td>
<td className="py-3 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.group}
</td>
<td className="py-3 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.store}
</td>
<td className="py-3 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.min}
</td>
<td className="py-3 px-4 font-semibold whitespace-nowrap">
<span className={isOverdue ? "text-rose-400" : "text-white"}>
{row.presentValue}{" "}
</span>
<span
className={`font-mono text-xs ${
isOverdue ? "text-rose-400" : "text-slate-300"
}`}
>
{row.unit}
</span>
</td>
<td className="py-3 px-4">
{row.status === "COMPLETED" ? (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold tracking-wider bg-emerald-950/60 text-emerald-400 border border-emerald-800/30">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
COMPLETED
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold tracking-wider bg-rose-950/40 text-rose-400 border border-rose-900/30">
<span className="w-1.5 h-1.5 rounded-full bg-rose-400"></span>
OVERDUE
</span>
)}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div> </div>
{/* RIGHT TABLE: CONSUMPTION LEDGER */} {/* RIGHT TABLE: CONSUMPTION LEDGER */}
<div className="bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-hidden"> <div className="h-full w-full border border-slate-800/80 rounded-lg overflow-hidden">
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80"> <div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Consumption ledger</h2> <h2 className="text-base font-semibold text-white">Consumption ledger</h2>
<span className="text-xs font-mono text-slate-500 lowercase"> <span className="text-xs font-mono text-slate-500 lowercase">
@@ -192,54 +125,7 @@ export default function InventoryPortal() {
</span> </span>
</div> </div>
<div> <Table headers={consumptionHeaders} rows={consumptionRows} />
<table className="w-full h-full text-left text-sm">
<thead>
<tr className="border-b border-slate-800/60 text-[11px] font-bold uppercase tracking-wider text-slate-400">
<th className="py-3 px-4">Txn</th>
<th className="py-3 px-4">Item</th>
<th className="py-3 px-4">Type</th>
<th className="py-3 px-4">Qty</th>
<th className="py-3 px-4">Job Card</th>
<th className="py-3 px-4">Date</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/40">
{consumptionLedger.map((row, index) => (
<tr key={index} className="hover:bg-slate-800/30 transition-colors">
<td className="py-3 px-4 font-mono text-teal-400 font-medium text-xs whitespace-nowrap">
{row.txn}
</td>
<td className="py-3 px-4 font-semibold text-slate-100 max-w-[140px]">
{row.item}
</td>
<td className="py-3 px-4 whitespace-nowrap">
{row.type === "Consume" ? (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-amber-950/40 text-amber-300 border border-amber-800/30">
<span className="w-1.5 h-1.5 rounded-full bg-amber-400"></span>
Consume
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-950/40 text-blue-300 border border-blue-800/30">
<span className="w-1.5 h-1.5 rounded-full bg-blue-400"></span>
Receipt
</span>
)}
</td>
<td className="py-3 px-4 font-medium text-slate-200 whitespace-nowrap">
{row.qty}
</td>
<td className="py-3 px-4 font-mono text-teal-400 text-xs whitespace-nowrap">
{row.jobCard}
</td>
<td className="py-3 px-4 text-slate-300 text-xs font-medium whitespace-nowrap">
{row.date}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div> </div>
</div> </div>

View File

@@ -1,16 +1,18 @@
import { useState } from 'react';
import { import {
Star, Star,
ShieldCheck, ShieldCheck,
Activity, Activity,
Clock, Clock,
BarChart2, BarChart2,
Plus Plus,
} from "lucide-react"; } from "lucide-react";
import Button from "@/components/common/button"; import Button from "@/components/common/button";
import StatCard from "@/components/common/dashStatCard"; import StatCard from "@/components/common/dashStatCard";
import InfoBanner from "@/components/common/infoBanner"; import InfoBanner from "@/components/common/infoBanner";
import { fieldCrewData, vendorData } from '@/constants/constant'; import Table from "@/components/common/dataTable";
import { teamStatusRows, teamStatusHeaders, vendorPerformanceHeaders, vendorPerformanceRows } from "@/constants/tabledata";
export default function VendorServicePortal() { export default function VendorServicePortal() {
@@ -99,111 +101,23 @@ export default function VendorServicePortal() {
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6 items-start"> <div className="grid grid-cols-1 xl:grid-cols-3 gap-6 items-start">
{/* LEFT TABLE: VENDOR SCORECARD */} {/* LEFT TABLE: VENDOR SCORECARD */}
<div className="xl:col-span-2 bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-hidden"> <div className="xl:col-span-2 border border-slate-800/80 rounded-lg overflow-hidden">
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80"> <div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Vendor scorecard</h2> <h2 className="text-base font-semibold text-white">Vendor scorecard</h2>
<span className="text-xs font-mono text-slate-500 lowercase">
SLA rating jobs
</span>
</div> </div>
<div className="overflow-x-auto"> <Table headers={vendorPerformanceHeaders} rows={vendorPerformanceRows} />
<table className="w-full text-left text-sm">
<thead>
<tr className="border-b border-slate-800/60 text-[11px] font-bold uppercase tracking-wider text-slate-400">
<th className="py-3 px-6">Vendor</th>
<th className="py-3 px-4">Scope</th>
<th className="py-3 px-4">Rating</th>
<th className="py-3 px-4">SLA</th>
<th className="py-3 px-4">Response</th>
<th className="py-3 px-6">Open</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/40">
{vendorData.map((row, index) => (
<tr key={index} className="hover:bg-slate-800/30 transition-colors">
<td className="py-4 px-6">
<div className="font-semibold text-slate-100">{row.name}</div>
<div className="text-xs font-mono text-slate-500 mt-0.5">{row.id}</div>
</td>
<td className="py-4 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.scope}
</td>
<td className="py-4 px-4 font-medium text-slate-200 whitespace-nowrap">
<div className="flex items-center gap-1">
<span>{row.rating}</span>
<Star className="w-3.5 h-3.5 fill-amber-400 text-amber-400" />
</div>
</td>
<td className={`py-4 px-4 font-semibold whitespace-nowrap ${row.slaColor}`}>
{row.sla}
</td>
<td className="py-4 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.response}
</td>
<td className="py-4 px-6 font-semibold text-blue-400 whitespace-nowrap">
{row.openJobs}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div> </div>
{/* RIGHT TABLE: FIELD CREW • LIVE */} {/* RIGHT TABLE: FIELD CREW • LIVE */}
<div className="bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-hidden"> <div className=" border border-slate-800/80 rounded-lg overflow-hidden">
<div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80"> <div className="flex items-center justify-between px-6 py-4 border-b border-slate-800/80">
<h2 className="text-base font-semibold text-white">Field crew live</h2> <h2 className="text-base font-semibold text-white">Field crew live</h2>
<span className="text-xs font-mono text-slate-500 lowercase">
4 on site
</span>
</div> </div>
<div className="p-4 space-y-3"> <Table headers={teamStatusHeaders} rows={teamStatusRows} />
{fieldCrewData.map((crew, index) => {
return (
<div
key={index}
className="flex items-center justify-between p-3 rounded-lg bg-[#0d1835]/50 hover:bg-slate-800/30 transition-colors border border-slate-800/40"
>
<div className="flex items-center gap-3">
<div className="w-9 h-9 rounded-lg bg-teal-950/60 border border-teal-800/30 text-teal-400 text-xs font-bold flex items-center justify-center shrink-0">
{crew.initials}
</div>
<div>
<div className="font-semibold text-slate-100 text-sm">{crew.name}</div>
<div className="text-xs text-slate-400 mt-0.5">{crew.role}</div>
</div>
</div>
<div className="text-right shrink-0">
{crew.statusType === "onsite" && (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-emerald-950/60 text-emerald-400 border border-emerald-800/30">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
{crew.status}
</span>
)}
{crew.statusType === "enroute" && (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-amber-950/60 text-amber-400 border border-amber-800/30">
<span className="w-1.5 h-1.5 rounded-full bg-amber-400"></span>
{crew.status}
</span>
)}
{crew.statusType === "offsite" && (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-slate-800/80 text-slate-400 border border-slate-700/50">
<span className="w-1.5 h-1.5 rounded-full bg-slate-500"></span>
{crew.status}
</span>
)}
<div className="text-[11px] font-mono text-slate-500 mt-1">
{crew.time}
</div>
</div>
</div>
);
})}
</div>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,8 @@ import { permitsData, workPermitFilters } from '@/constants/constant';
import FilterTabs from '@/components/common/roundedFilters'; import FilterTabs from '@/components/common/roundedFilters';
import StatCard from '@/components/common/dashStatCard'; import StatCard from '@/components/common/dashStatCard';
import InfoBanner from '@/components/common/infoBanner'; import InfoBanner from '@/components/common/infoBanner';
import Table from '@/components/common/dataTable';
import { workPermitHeaders, workPermitRows } from '@/constants/tabledata';
export default function WorkPermitPortal() { export default function WorkPermitPortal() {
@@ -13,61 +15,7 @@ export default function WorkPermitPortal() {
// Permit Data matching the UI // Permit Data matching the UI
const renderStatusBadge = (status: string) => {
switch (status) {
case "ACTIVE":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-emerald-950/60 text-emerald-400 border border-emerald-800/40">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400"></span>
ACTIVE
</span>
);
case "SUBMITTED":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-amber-950/50 text-amber-300 border border-amber-800/40">
<span className="w-1.5 h-1.5 rounded-full bg-amber-400"></span>
SUBMITTED
</span>
);
case "APPROVED":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-blue-950/60 text-blue-400 border border-blue-800/40">
<span className="w-1.5 h-1.5 rounded-full bg-blue-400"></span>
APPROVED
</span>
);
case "EXPIRED":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-rose-950/40 text-rose-400 border border-rose-900/30">
<span className="w-1.5 h-1.5 rounded-full bg-rose-400"></span>
EXPIRED
</span>
);
case "CLOSED":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-slate-800/80 text-slate-400 border border-slate-700/50">
<span className="w-1.5 h-1.5 rounded-full bg-slate-400"></span>
CLOSED
</span>
);
case "REJECTED":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-rose-950/40 text-rose-400 border border-rose-900/30">
<span className="w-1.5 h-1.5 rounded-full bg-rose-400"></span>
REJECTED
</span>
);
case "DRAFT":
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-[10px] font-bold tracking-wider bg-slate-800/80 text-slate-400 border border-slate-700/50">
<span className="w-1.5 h-1.5 rounded-full bg-slate-400"></span>
DRAFT
</span>
);
default:
return null;
}
};
return ( return (
<div className="my-15 text-slate-100 font-sans"> <div className="my-15 text-slate-100 font-sans">
@@ -103,10 +51,7 @@ export default function WorkPermitPortal() {
</div> </div>
</div> </div>
{/* --- NAVIGATION TABS & TOP ACTION BUTTONS --- */}
<div className="flex flex-col md:flex-row md:items-center justify-between border-b border-slate-800/80 mb-6 gap-4">
{/* Navigation tabs component if needed */}
</div>
{/* --- STAT CARDS --- */} {/* --- STAT CARDS --- */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
@@ -166,94 +111,7 @@ export default function WorkPermitPortal() {
{/* --- PERMIT TABLE SECTION --- */} {/* --- PERMIT TABLE SECTION --- */}
<div className="bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-x-auto"> <div className="bg-[#0b1329] border border-slate-800/80 rounded-lg overflow-x-auto">
<table className="w-full text-left text-sm"> <Table headers={workPermitHeaders} rows={workPermitRows}/>
<thead>
<tr className="border-b border-slate-800/80 text-[11px] font-bold uppercase tracking-wider text-slate-400">
<th className="py-3 px-4">Permit</th>
<th className="py-3 px-4">Working Type</th>
<th className="py-3 px-4">Location</th>
<th className="py-3 px-4">Contractor</th>
<th className="py-3 px-4">Validity</th>
<th className="py-3 px-4">Crew</th>
<th className="py-3 px-4">Status</th>
<th className="py-3 px-4 text-right"></th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/40">
{permitsData.map((row, index) => (
<tr
key={index}
className={`transition-colors relative ${
row.isHighlighted ? "bg-[#0e2238]" : "hover:bg-slate-800/30"
}`}
>
{/* Permit ID */}
<td className="py-4 px-4 font-mono text-teal-400 font-medium text-xs whitespace-nowrap relative">
{row.isHighlighted && (
<div className="absolute left-0 top-0 bottom-0 w-[3px] bg-teal-400" />
)}
{row.permit}
</td>
{/* Working Type */}
<td className="py-4 px-4 font-semibold text-slate-100 whitespace-nowrap">
{row.workingType}
</td>
{/* Location */}
<td className="py-4 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.location}
</td>
{/* Contractor */}
<td className="py-4 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.contractor}
</td>
{/* Validity */}
<td className="py-4 px-4 whitespace-nowrap">
<div className="text-xs text-slate-300 font-medium">{row.validityDate}</div>
<div className="text-[11px] font-mono text-slate-500">{row.validityTime}</div>
</td>
{/* Crew */}
<td className="py-4 px-4 text-slate-300 font-medium whitespace-nowrap">
{row.crew}
</td>
{/* Status Badge */}
<td className="py-4 px-4 whitespace-nowrap">
{renderStatusBadge(row.status)}
</td>
{/* Actions */}
<td className="py-4 px-4 text-right whitespace-nowrap">
<div className="flex items-center justify-end gap-2">
{row.hasViewIconOnly ? (
<div className="flex flex-col gap-1">
<button className="p-1.5 text-slate-400 hover:text-white bg-slate-800/40 hover:bg-slate-800 rounded border border-slate-700/50 transition-colors">
<FileText size={14} />
</button>
<button className="p-1.5 text-slate-400 hover:text-white bg-slate-800/40 hover:bg-slate-800 rounded border border-slate-700/50 transition-colors">
<Eye size={14} />
</button>
</div>
) : (
<div className="flex flex-col items-center gap-1">
<button className="p-1.5 text-slate-400 hover:text-white bg-slate-800/40 hover:bg-slate-800 rounded border border-slate-700/50 transition-colors">
<FileText size={14} />
</button>
<button className="text-teal-400 hover:text-teal-300 text-xs font-semibold hover:underline">
{row.actionText}
</button>
</div>
)}
</div>
</td>
</tr>
))}
</tbody>
</table>
</div> </div>
<div className="mb-10 mt-10"> <div className="mb-10 mt-10">

View File

@@ -3,12 +3,13 @@ import { Check } from 'lucide-react';
import BarChart from "@/components/charts/barchart"; import BarChart from "@/components/charts/barchart";
import StatCard from "@/components/common/dashStatCard"; import StatCard from "@/components/common/dashStatCard";
import ActivityFeed from "@/components/dashboard/overview/activityFeed"; import ActivityFeed from "@/components/dashboard/overview/activityFeed";
import {activities, chartData, schedulePerformanceHeaders, schedulePerformanceRows} from "@/constants/constant" import {activities, chartData} from "@/constants/constant"
import { Card } from '@/components/common/cardWrapper'; import { Card } from '@/components/common/cardWrapper';
import {CardHeader} from '@/components/common/cardHeader'; import {CardHeader} from '@/components/common/cardHeader';
import {ProgressBarRow }from '@/components/charts/progressBarRow'; import {ProgressBarRow }from '@/components/charts/progressBarRow';
import {StatusProgressRow} from '@/components/charts/statusProgressRow'; import {StatusProgressRow} from '@/components/charts/statusProgressRow';
import Table from '@/components/common/dataTable'; import Table from '@/components/common/dataTable';
import { schedulePerformanceHeaders, schedulePerformanceRows } from '@/constants/tabledata';
export default function Dashboard() { export default function Dashboard() {

View File

@@ -22,12 +22,12 @@ export default function MeetingRoomPortal() {
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>WORKPLACE</span> <span className="text-gray-400">WORKPLACE</span>
<span></span> <span className="text-gray-600"></span>
<span>MEETING ROOMS</span> <span className="text-gray-400">MEETING ROOMS</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-1"> <h1 className="text-2xl font-bold text-white tracking-tight mt-1">
Meeting room booking Meeting room booking
@@ -136,15 +136,15 @@ export default function MeetingRoomPortal() {
<div className="flex items-center justify-between border-t border-[#162942]/60 pt-3 mt-2"> <div className="flex items-center justify-between border-t border-[#162942]/60 pt-3 mt-2">
<span className="text-xs text-slate-400">{room.subtitle}</span> <span className="text-xs text-slate-400">{room.subtitle}</span>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-200 text-xs font-semibold px-3 py-1.5 rounded transition-colors"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-200 text-xs font-semibold px-3 py-1.5 rounded transition-colors">
{room.actionType === "book" ? "Book" : "View"} {room.actionType === "book" ? "Book" : "View"}
</button> </Button>
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-slate-200 p-1.5 rounded transition-colors"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-slate-200 p-1.5 rounded transition-colors">
<Pencil className="w-3.5 h-3.5" /> <Pencil className="w-3.5 h-3.5" />
</button> </Button>
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-rose-400 p-1.5 rounded transition-colors"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-rose-400 p-1.5 rounded transition-colors">
<Trash2 className="w-3.5 h-3.5" /> <Trash2 className="w-3.5 h-3.5" />
</button> </Button>
</div> </div>
</div> </div>
</Card> </Card>

View File

@@ -23,12 +23,12 @@ const [activeFilter, setActiveFilter] = useState<string>('All');
{/* --- HEADER SECTION --- */} {/* --- HEADER SECTION --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>Workplace</span> <span className="text-gray-400">Workplace</span>
<span></span> <span className="text-gray-600"></span>
<span>Visitors</span> <span className="text-gray-400">Visitors</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
Visitor management Visitor management

View File

@@ -22,8 +22,7 @@ import { CardHeader } from '@/components/common/cardHeader';
export default function WorkSpacePortal() { export default function WorkSpacePortal() {
const [activeTab, setActiveTab] = useState<string>("Desk Booking"); const [activeTab, setActiveTab] = useState<string>("Desk Booking");
// Grid state matching the UI: 4 rows x 12 columns (48 seats)
// Types: 'occupied' (red/purple outline), 'free' (teal), 'reserved' (amber)
const deskGrid = Array.from({ length: 48 }).map((_, index) => { const deskGrid = Array.from({ length: 48 }).map((_, index) => {
if (index === 42) return "reserved"; // 1 Reserved desk if (index === 42) return "reserved"; // 1 Reserved desk
if (index >= 36) return "free"; // Free desks on the bottom row if (index >= 36) return "free"; // Free desks on the bottom row
@@ -35,12 +34,12 @@ export default function WorkSpacePortal() {
{/* --- HEADER SECTION WITH BUTTONS --- */} {/* --- HEADER SECTION WITH BUTTONS --- */}
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6"> <div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
<div> <div>
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-slate-500 uppercase font-mono"> <div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-slate-500 uppercase font-mono">
<span className="text-teal-400">Apple One HQ Tower</span> <span className="text-teal-400">Apple One HQ Tower</span>
<span></span> <span className="text-gray-600"></span>
<span>WORKPLACE</span> <span className="text-gray-400">WORKPLACE</span>
<span></span> <span className="text-gray-600"></span>
<span>WORKSPACE</span> <span className="text-gray-400">WORKSPACE</span>
</div> </div>
<h1 className="text-2xl font-bold text-white tracking-tight mt-2"> <h1 className="text-2xl font-bold text-white tracking-tight mt-2">
@@ -192,12 +191,12 @@ export default function WorkSpacePortal() {
{/* Value & Actions */} {/* Value & Actions */}
<div className="flex items-center gap-2 font-mono text-xs text-slate-200"> <div className="flex items-center gap-2 font-mono text-xs text-slate-200">
<span className="font-bold">{zone.current}/{zone.max}</span> <span className="font-bold">{zone.current}/{zone.max}</span>
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-slate-200 p-1 rounded transition-colors"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-slate-200 p-1 rounded transition-colors">
<Pencil className="w-3 h-3" /> <Pencil className="w-3 h-3" />
</button> </Button>
<button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-rose-400 p-1 rounded transition-colors"> <Button className="bg-[#12233a] hover:bg-[#1a3252] border border-[#1d3554] text-slate-400 hover:text-rose-400 p-1 rounded transition-colors">
<Trash2 className="w-3 h-3" /> <Trash2 className="w-3 h-3" />
</button> </Button>
</div> </div>
</div> </div>
); );

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { OPERATIONS_SIDEBAR_ITEMS, ADMIN_SIDEBAR_ITEMS } from "@/constants/constant"; import { OPERATIONS_SIDEBAR_ITEMS, ADMIN_SIDEBAR_ITEMS } from "@/constants/sidebarConstant";
import SidebarItem from "./sideBarItem"; 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 { useSession, signOut } from "next-auth/react";

View File

@@ -1,178 +1,6 @@
import {
LayoutGrid,
Smile,
Building2,
User,
Target,
CheckSquare,
FileText,
Box,
Zap,
ClipboardList,
Star,
Monitor,
UserCheck,
Calendar,
Layers,
Coins,
Receipt,
ShieldCheck,
Flame,
Recycle,
GraduationCap,
Brain,
Activity,
Bot,
Gauge,
Snowflake,
Leaf,
MapPin,
BarChart3,
Sun,
Shield,
Settings,
Wallet,
Radar,
Cog,
Smartphone,
Users,
Database,
Globe,
LayoutDashboard,
} from "lucide-react";
//Side bar Drop Down menu
export const OPERATIONS_SIDEBAR_ITEMS = [
{
title: "Overview",
icon: LayoutGrid,
children: [
{ title: "Dashboard", href: "/dashboard/overview/dashboard", icon: LayoutGrid },
{ 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: "/dashboard/overview/serviceEngineer", icon: Target },
],
},
{
title: "Operations",
icon: Settings,
children: [
{ title: "Help Desk", href: "/dashboard/operations/helpDesk", icon: CheckSquare, badge: 6, badgeColor: "bg-amber-500 text-black" },
{ title: "Equipment", href: "/dashboard/operations/equipment", icon: Target },
{ title: "Requests", href: "/dashboard/operations/request", icon: FileText, badge: 15, badgeColor: "bg-amber-400 text-black" },
{ title: "Inventory", href: "/dashboard/operations/inventory", icon: Box },
{ title: "Energy", href: "/dashboard/operations/energy", icon: Zap },
{ title: "Work Permit", href: "/dashboard/operations/workPermit", icon: ClipboardList, badge: 3, badgeColor: "bg-amber-500 text-black" },
{ title: "Vendor & Field Service", href: "/dashboard/operations/vendorFieldService", icon: Star, badge: 12, badgeColor: "bg-sky-400 text-black" },
],
},
{
title: "Workplace",
icon: Monitor,
children: [
{ title: "Visitor Management", href: "/dashboard/workplace/visitorManagement", icon: UserCheck },
{ title: "Meeting Rooms", href: "/dashboard/workplace/meetingRoom", icon: Calendar },
{ title: "Workspace", href: "/dashboard/workplace/workspace", icon: Layers },
],
},
{
title: "Finance",
icon: Wallet,
children: [
{ title: "O&M Budget", href: "/dashboard/finance/budget", icon: Coins },
{ title: "Costing & Invoicing", href: "/dashboard/finance/costinvoice", icon: Receipt },
],
},
{
title: "Compliance & Safety",
icon: ShieldCheck,
children: [
{ title: "Statutory Compliance", href: "/dashboard/compliance-safety/statutoryCompliance", icon: ShieldCheck },
{ title: "Contracts & SLA", href: "/dashboard/compliance-safety/contracts", icon: FileText },
{ title: "Fire & Safety", href: "/dashboard/compliance-safety/fireAndSafety", icon: Flame },
{ title: "Waste & ESG", href: "/dashboard/compliance-safety/wasteAndEsg", icon: Recycle },
{ title: "Training", href: "/dashboard/compliance-safety/training", icon: GraduationCap },
{ title: "Audit & Survey", href: "/dashboard/compliance-safety/auditAndSurvey", icon: GraduationCap },
],
},
{
title: "Intelligence",
icon: Brain,
children: [{ title: "AI & Predictive", href: "/dashboard/intelligence/aiPredictive", icon: Brain },
{ title: "Asset Health", href: "/dashboard/intelligence/assetHealth", icon: ShieldCheck },
{ title: "Energy Benchmarking", href: "/dashboard/intelligence/energyBenchmarking", icon: Activity },
{ title: "AI Helpdesk", href: "/dashboard/intelligence/aiHelpdesk", icon: Bot },
{ title: "Connected Ops", href: "/dashboard/intelligence/connectedOps", icon: Gauge },
{ title: "Connected Assets", href: "/dashboard/intelligence/connectedAsset", icon: Snowflake },
{ title: "Sustainability", href: "/dashboard/intelligence/sustainability", icon: Leaf },
{ title: "GPS Tracking", href: "/dashboard/intelligence/gpstracking", icon: MapPin },],
},
{
title: "IoT Application",
icon: Radar,
children: [{ title: "Command Center", href: "/dashboard/iot-app/commandCenter", icon: Gauge },
{ title: "HVAC Plant", href: "/dashboard/iot-app/hvacPlant", icon: Snowflake },
{ title: "Energy & Utilities", href: "/dashboard/iot-app/energyUtility", icon: Zap },
{ title: "Device Fleet", href: "/dashboard/iot-app/deviceFleet", icon: LayoutGrid },
{ title: "Alarms & Rules", href: "/dashboard/iot-app/alarmsRules", icon: Shield, badge: 7, badgeColor: "bg-rose-500 text-white" },],
},
{
title: "Insight",
icon: BarChart3,
children: [{ title: "Reports & MMR", href: "/dashboard/insight/report", icon: BarChart3 },],
},
{
title: "Configure",
icon: Cog,
children: [{ title: "Master Data", href: "/dashboard/configure/masterdata", icon: Layers },
{ title: "Roles & Access", href: "/dashboard/configure/rolesAndAccess", icon: Shield },
{ title: "Workflow Automation", href: "/dashboard/configure/workflowautomation", icon: Bot },
{ title: "User Location", href: "/dashboard/configure/userLocation", icon: MapPin },
{ title: "Settings", href: "/dashboard/configure/settings", icon: Sun },],
},
];
export const ADMIN_SIDEBAR_ITEMS = [
{
title: "Platform",
icon: Building2,
children: [
{ title: "Overview", href: "/dashboard/admin/overview", icon: LayoutGrid },
{ title: "Tenants", href: "/dashboard/admin/tenants", icon: Building2 },
{ title: "Users", href: "/dashboard/admin/users", icon: Users },
{ title: "Sites", href: "/dashboard/admin/site", icon: MapPin },
{ title: "Security", href: "/dashboard/admin/security", icon: Shield },
],
},
{
title: "Configuration",
icon: LayoutGrid,
children: [
{ title: "Modules", href: "/dashboard/admin/modules", icon: LayoutGrid },
{ title: "Language", href: "/dashboard/admin/language", icon: Globe },
{ title: "Dynamic Dashboard", href: "/dashboard/admin/dynamicDashboard", icon: LayoutDashboard },
{ title: "Mobile Flows", href: "/dashboard/admin/mobileFlow", icon: Smartphone },
],
},
];
export const schedulePerformanceHeaders = [
"Schedule",
"Total",
"Done",
"On Time",
"Delayed",
];
export const schedulePerformanceRows = [
["PPM", 24, 19, 17, 2],
["AMC", 8, 6, 6, 0],
];
//Overview dashboard data
export const chartData = [ export const chartData = [
{ month: 'J', height: 'h-24' }, { month: 'J', height: 'h-24' },
@@ -562,324 +390,116 @@ export const scheduleItems = [
{ frequency: "On call", stream: "Hazardous", vendor: "Ramky Enviro" }, { frequency: "On call", stream: "Hazardous", vendor: "Ramky Enviro" },
]; ];
export const stockItems = [
{
item: "Cooling tower fan belt",
group: "HVAC",
store: "Block Store",
min: 5,
presentValue: 8,
unit: "Gallon",
status: "COMPLETED",
isHighlighted: false,
},
{
item: "Air filter 24×24",
group: "HVAC",
store: "Block Store",
min: 5,
presentValue: 2,
unit: "Nos",
status: "OVERDUE",
isHighlighted: true,
},
{
item: "MCB 32A",
group: "Electrical",
store: "Block Store",
min: 5,
presentValue: 8,
unit: "Nos",
status: "COMPLETED",
isHighlighted: false,
},
{
item: "Contactor 40A",
group: "Electrical",
store: "Block Store",
min: 2,
presentValue: 2,
unit: "Nos",
status: "OVERDUE",
isHighlighted: false,
},
{
item: "PVC pipe 1\"",
group: "Plumbing",
store: "Main Store",
min: 3,
presentValue: 0,
unit: "Mtr",
status: "OVERDUE",
isHighlighted: false,
},
{
item: "Submersible pump seal",
group: "Plumbing",
store: "Main Store",
min: 3,
presentValue: 2,
unit: "Nos",
status: "OVERDUE",
isHighlighted: false,
},
{
item: "Refrigerant R410a",
group: "HVAC",
store: "Block Store",
min: 5,
presentValue: 0,
unit: "Kg",
status: "OVERDUE",
isHighlighted: false,
},
];
export const consumptionLedger = [ export const plantLoadData = [
{ { month: '08', height: 'h-[35%]' },
txn: "TXN-5200", { month: '09', height: 'h-[38%]' },
item: "Cooling tower fan belt", { month: '10', height: 'h-[32%]' },
type: "Consume", { month: '11', height: 'h-[40%]' },
qty: "2 Gallon", { month: '12', height: 'h-[52%]' },
jobCard: "026/1009", { month: '13', height: 'h-[68%]' },
date: "Jun 20, 2026", { month: '14', height: 'h-[78%]' },
}, { month: '15', height: 'h-[78%]' },
{ { month: '16', height: 'h-[78%]' },
txn: "TXN-5201", { month: '17', height: 'h-[78%]' },
item: "MCB 32A", { month: '18', height: 'h-[78%]' },
type: "Consume", { month: '19', height: 'h-[78%]' }
qty: "1 Nos", ];
jobCard: "026/1016",
date: "Jun 21, 2026", // Initial roles state
}, export const rolesList = [
{ { id: "admin", label: "Admin", badge: "all" },
txn: "TXN-5202", { id: "helpdesk", label: "Helpdesk", badge: "scoped" },
item: "Air filter 24×24", { id: "mne_supervisor", label: "M&E Supervisor", badge: "scoped" },
type: "Receipt", { id: "technician", label: "Technician", badge: "scoped" },
qty: "10 Nos", { id: "tenant", label: "Tenant", badge: "scoped" },
jobCard: "—", ];
date: "Jun 22, 2026",
}, // Initial permissions table data
{ export const initialPermissions = [
txn: "TXN-5203", {
item: "Submersible pump seal", id: 1,
type: "Consume", module: "Help Desk",
qty: "1 Nos", menu: "Daily Location Checklist",
jobCard: "026/1023", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
date: "Jun 23, 2026", },
}, {
{ id: 2,
txn: "TXN-5204", module: "Equipment",
item: "Air filter 24×24", menu: "Site-Wise Equipment",
type: "Consume", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
qty: "3 Nos", },
jobCard: "026/1030", {
date: "Jun 24, 2026", id: 3,
}, module: "Equipment",
{ menu: "AMC Schedule",
txn: "TXN-5205", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
item: "PVC pipe 1\"", },
type: "Receipt", {
qty: "20 Mtr", id: 4,
jobCard: "—", module: "Request",
date: "Jun 25, 2026", menu: "TFM Request",
}, permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
{ },
txn: "TXN-5406", {
item: "Cooling tower fan belt", id: 5,
type: "Consume", module: "Energy",
qty: "2 Gallon", menu: "Meter Reading",
jobCard: "026/1009", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
date: "Jun 7, 2026", },
}, {
{ id: 6,
txn: "TXN-5407", module: "Master",
item: "MCB 32A", menu: "Request Location",
type: "Consume", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
qty: "1 Nos", },
jobCard: "026/1016", {
date: "Jun 7, 2026", id: 7,
}, module: "Security",
{ menu: "Users",
txn: "TXN-5200", permissions: { all: false, view: true, add: true, edit: true, delete: false, cancel: true, print: true },
item: "Cooling tower fan belt", },
type: "Consume", ];
qty: "2 Gallon",
jobCard: "026/1009",
date: "Jun 20, 2026",
},
{
txn: "TXN-5201",
item: "MCB 32A",
type: "Consume",
qty: "1 Nos",
jobCard: "026/1016",
date: "Jun 21, 2026",
},
{
txn: "TXN-5202",
item: "Air filter 24×24",
type: "Receipt",
qty: "10 Nos",
jobCard: "—",
date: "Jun 22, 2026",
},
{
txn: "TXN-5203",
item: "Submersible pump seal",
type: "Consume",
qty: "1 Nos",
jobCard: "026/1023",
date: "Jun 23, 2026",
},
{
txn: "TXN-5204",
item: "Air filter 24×24",
type: "Consume",
qty: "3 Nos",
jobCard: "026/1030",
date: "Jun 24, 2026",
},
{
txn: "TXN-5205",
item: "PVC pipe 1\"",
type: "Receipt",
qty: "20 Mtr",
jobCard: "—",
date: "Jun 25, 2026",
},
{
txn: "TXN-5406",
item: "Cooling tower fan belt",
type: "Consume",
qty: "2 Gallon",
jobCard: "026/1009",
date: "Jun 7, 2026",
},
{
txn: "TXN-5407",
item: "MCB 32A",
type: "Consume",
qty: "1 Nos",
jobCard: "026/1016",
date: "Jun 7, 2026",
},
];
export const vendorData = [
{
name: "Voltas Ltd",
id: "CTR-700",
scope: "HVAC AMC & breakdown",
rating: "4.6",
sla: "95%",
slaColor: "text-emerald-400",
response: "4.0h",
openJobs: "2",
},
{
name: "Blue Star",
id: "CTR-701",
scope: "Chiller & VRV service",
rating: "4.1",
sla: "88%",
slaColor: "text-amber-400",
response: "1.2h",
openJobs: "2",
},
{
name: "Sterling FM",
id: "CTR-702",
scope: "Integrated FM / soft services",
rating: "3.4",
sla: "94%",
slaColor: "text-emerald-400",
response: "2.4h",
openJobs: "4",
},
{
name: "OTIS Elevators",
id: "CTR-704",
scope: "Elevator AMC",
rating: "4.8",
sla: "95%",
slaColor: "text-emerald-400",
response: "2.8h",
openJobs: "—",
},
{
name: "Sodexo",
id: "CTR-705",
scope: "Soft services & cafeteria",
rating: "4.3",
sla: "90%",
slaColor: "text-amber-400",
response: "2.8h",
openJobs: "1",
},
{
name: "In-house team",
id: "—",
scope: "Day-to-day maintenance",
rating: "4.0",
sla: "93%",
slaColor: "text-amber-400",
response: "3.2h",
openJobs: "3",
},
];
export const fieldCrewData = [ export const blocks = ["Block 1", "Block 2", "Tower A"];
{ export const floors = ["Ground", "Floor 1", "Floor 2"];
initials: "RK", export const zones = ["Zone N", "Zone Z1", "Zone Z2"];
name: "Ravi Kumar", // Mock user location data matching the screenshot
role: "M&E Technician • Chiller plant", export const userData = [
status: "ON-SITE", {
statusType: "onsite", name: "Dhananjay T.",
time: "6.4h today", email: "dhananjay@kafm.io",
}, mobile: "7489477369",
{ latitude: "18.5450",
initials: "SI", longitude: "73.7935",
name: "Sana Iqbal", site: "Apple One",
role: "HVAC Engineer • AHU room L7", // Relative coordinates for the map visual dots (X%, Y%)
status: "ON-SITE", x: "19%",
statusType: "onsite", y: "38%",
time: "6.1h today", },
}, {
{ name: "ME Local",
initials: "MD", email: "me.local@kafm.io",
name: "Mohan D.", mobile: "9876543210",
role: "Electrician • En route", latitude: "18.5469",
status: "EN-ROUTE", longitude: "73.7945",
statusType: "enroute", site: "Apple One",
time: "", x: "44%",
}, y: "43%",
{ },
initials: "LN", {
name: "Lakshmi N.", name: "TECH Local",
role: "Housekeeping Lead • Lobby + L2", email: "tech.local@kafm.io",
status: "ON-SITE", mobile: "9123456780",
statusType: "onsite", latitude: "18.5441",
time: "6.7h today", longitude: "73.7951",
}, site: "Apple One",
{ x: "69%",
initials: "AP", y: "48%",
name: "Arjun P.", },
role: "Plumber • Off-site", ];
status: "OFF-SITE",
statusType: "offsite",
time: "—",
},
{
initials: "FR",
name: "Fatima R.",
role: "BMS Operator • Control room",
status: "ON-SITE",
statusType: "onsite",
time: "7.6h today",
},
];
export const permitsData = [ export const permitsData = [
{ {

View File

@@ -0,0 +1,160 @@
import {
LayoutGrid,
Smile,
Building2,
User,
Target,
CheckSquare,
FileText,
Box,
Zap,
ClipboardList,
Star,
Monitor,
UserCheck,
Calendar,
Layers,
Coins,
Receipt,
ShieldCheck,
Flame,
Recycle,
GraduationCap,
Brain,
Activity,
Bot,
Gauge,
Snowflake,
Leaf,
MapPin,
BarChart3,
Sun,
Shield,
Settings,
Wallet,
Radar,
Cog,
Smartphone,
Users,
Globe,
LayoutDashboard,
} from "lucide-react";
export const OPERATIONS_SIDEBAR_ITEMS = [
{
title: "Overview",
icon: LayoutGrid,
children: [
{ title: "Dashboard", href: "/dashboard/overview/dashboard", icon: LayoutGrid },
{ 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: "/dashboard/overview/serviceEngineer", icon: Target },
],
},
{
title: "Operations",
icon: Settings,
children: [
{ title: "Help Desk", href: "/dashboard/operations/helpDesk", icon: CheckSquare, badge: 6, badgeColor: "bg-amber-500 text-black" },
{ title: "Equipment", href: "/dashboard/operations/equipment", icon: Target },
{ title: "Requests", href: "/dashboard/operations/request", icon: FileText, badge: 15, badgeColor: "bg-amber-400 text-black" },
{ title: "Inventory", href: "/dashboard/operations/inventory", icon: Box },
{ title: "Energy", href: "/dashboard/operations/energy", icon: Zap },
{ title: "Work Permit", href: "/dashboard/operations/workPermit", icon: ClipboardList, badge: 3, badgeColor: "bg-amber-500 text-black" },
{ title: "Vendor & Field Service", href: "/dashboard/operations/vendorFieldService", icon: Star, badge: 12, badgeColor: "bg-sky-400 text-black" },
],
},
{
title: "Workplace",
icon: Monitor,
children: [
{ title: "Visitor Management", href: "/dashboard/workplace/visitorManagement", icon: UserCheck },
{ title: "Meeting Rooms", href: "/dashboard/workplace/meetingRoom", icon: Calendar },
{ title: "Workspace", href: "/dashboard/workplace/workspace", icon: Layers },
],
},
{
title: "Finance",
icon: Wallet,
children: [
{ title: "O&M Budget", href: "/dashboard/finance/budget", icon: Coins },
{ title: "Costing & Invoicing", href: "/dashboard/finance/costinvoice", icon: Receipt },
],
},
{
title: "Compliance & Safety",
icon: ShieldCheck,
children: [
{ title: "Statutory Compliance", href: "/dashboard/compliance-safety/statutoryCompliance", icon: ShieldCheck },
{ title: "Contracts & SLA", href: "/dashboard/compliance-safety/contracts", icon: FileText },
{ title: "Fire & Safety", href: "/dashboard/compliance-safety/fireAndSafety", icon: Flame },
{ title: "Waste & ESG", href: "/dashboard/compliance-safety/wasteAndEsg", icon: Recycle },
{ title: "Training", href: "/dashboard/compliance-safety/training", icon: GraduationCap },
{ title: "Audit & Survey", href: "/dashboard/compliance-safety/auditAndSurvey", icon: GraduationCap },
],
},
{
title: "Intelligence",
icon: Brain,
children: [{ title: "AI & Predictive", href: "/dashboard/intelligence/aiPredictive", icon: Brain },
{ title: "Asset Health", href: "/dashboard/intelligence/assetHealth", icon: ShieldCheck },
{ title: "Energy Benchmarking", href: "/dashboard/intelligence/energyBenchmarking", icon: Activity },
{ title: "AI Helpdesk", href: "/dashboard/intelligence/aiHelpdesk", icon: Bot },
{ title: "Connected Ops", href: "/dashboard/intelligence/connectedOps", icon: Gauge },
{ title: "Connected Assets", href: "/dashboard/intelligence/connectedAsset", icon: Snowflake },
{ title: "Sustainability", href: "/dashboard/intelligence/sustainability", icon: Leaf },
{ title: "GPS Tracking", href: "/dashboard/intelligence/gpstracking", icon: MapPin },],
},
{
title: "IoT Application",
icon: Radar,
children: [{ title: "Command Center", href: "/dashboard/iot-app/commandCenter", icon: Gauge },
{ title: "HVAC Plant", href: "/dashboard/iot-app/hvacPlant", icon: Snowflake },
{ title: "Energy & Utilities", href: "/dashboard/iot-app/energyUtility", icon: Zap },
{ title: "Device Fleet", href: "/dashboard/iot-app/deviceFleet", icon: LayoutGrid },
{ title: "Alarms & Rules", href: "/dashboard/iot-app/alarmRule", icon: Shield, badge: 7, badgeColor: "bg-rose-500 text-white" },],
},
{
title: "Insight",
icon: BarChart3,
children: [{ title: "Reports & MMR", href: "/dashboard/insight/report", icon: BarChart3 },],
},
{
title: "Configure",
icon: Cog,
children: [{ title: "Master Data", href: "/dashboard/configure/masterdata", icon: Layers },
{ title: "Roles & Access", href: "/dashboard/configure/rolesAndAccess", icon: Shield },
{ title: "Workflow Automation", href: "/dashboard/configure/workflowautomation", icon: Bot },
{ title: "User Location", href: "/dashboard/configure/userLocation", icon: MapPin },
{ title: "Settings", href: "/dashboard/configure/settings", icon: Sun },],
},
];
export const ADMIN_SIDEBAR_ITEMS = [
{
title: "Platform",
icon: Building2,
children: [
{ title: "Overview", href: "/dashboard/admin/overview", icon: LayoutGrid },
{ title: "Tenants", href: "/dashboard/admin/tenants", icon: Building2 },
{ title: "Users", href: "/dashboard/admin/users", icon: Users },
{ title: "Sites", href: "/dashboard/admin/site", icon: MapPin },
{ title: "Security", href: "/dashboard/admin/security", icon: Shield },
],
},
{
title: "Configuration",
icon: LayoutGrid,
children: [
{ title: "Modules", href: "/dashboard/admin/modules", icon: LayoutGrid },
{ title: "Language", href: "/dashboard/admin/language", icon: Globe },
{ title: "Dynamic Dashboard", href: "/dashboard/admin/dynamicDashboard", icon: LayoutDashboard },
{ title: "Mobile Flows", href: "/dashboard/admin/mobileFlow", icon: Smartphone },
],
},
];

File diff suppressed because it is too large Load Diff