diff --git a/app/dashboard/workplace/visitorManagement/page.tsx b/app/dashboard/workplace/visitorManagement/page.tsx index e69de29..f530919 100644 --- a/app/dashboard/workplace/visitorManagement/page.tsx +++ b/app/dashboard/workplace/visitorManagement/page.tsx @@ -0,0 +1,16 @@ +"use client" + +import VistiorManagementPortal from "@/components/dashboard/visitorManagement"; + + +export default function InventoryPage() { + return ( + + +
+ + +
+ + ); +} \ No newline at end of file diff --git a/components/dashboard/equipment.tsx b/components/dashboard/equipment.tsx index 36b2d52..8ed2d71 100644 --- a/components/dashboard/equipment.tsx +++ b/components/dashboard/equipment.tsx @@ -1,397 +1,317 @@ -import { useState } from 'react'; - import { - Pencil, - - Menu, - - ShieldCheck, - + FileText, QrCode, + Search, + Plus, + AlertTriangle, + Clock, + ShieldCheck, + Target, + Download, + LayoutGrid, +} from "lucide-react"; - Power, +import Table from "@/utils/dataTable"; +import InfoBanner from "@/utils/infoBanner"; +import Button from "@/utils/button"; +import NavigationTabs from "@/utils/tabs"; +import { equipmentTabs } from "@/constants/constant"; +import { useState } from "react"; - Check, +const headers = [ + "Code", + "Equipment", + "Group", + "Block · Floor", + "Service Provider", + "Criticality", + "PPM Status", + "Actions", +]; - Sparkles, +const Badge = ({ + text, + color, +}: { + text: string; + color: string; +}) => ( + + + {text} + +); -} from 'lucide-react'; +const ActionButtons = () => ( +
+ -import { mockData } from '@/constants/constant'; + + +
+); +export default function EquipmentPortal() { + const [activeTab, setActiveTab] = useState("Site-Wise Equipment"); - - -export default function LocationTable(){ - - const [selectedIds, setSelectedIds] = useState(['1']); // Row 1 selected by default (teal indicator bar) - - - - const toggleSelectAll = () => { - - if (selectedIds.length === mockData.length) { - - setSelectedIds([]); - - } else { - - setSelectedIds(mockData.map((row) => row.id)); - - } - - }; - - - - const toggleSelectRow = (id: string) => { - - setSelectedIds((prev) => - - prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] - - ); - - }; - - + const rows = [ + [ + APP-1100, + Cooling Tower, + "Electrical", + "Block 1 · 2", + "Blue Star", + "Important", + , + , + ], + [ + APP-1103, + Air Handling Unit, + "Plumbing", + "Tower A · 1", + "Blue Star", + , + , + , + ], + [ + APP-1106, + VRV Outdoor, + "Electrical", + "Tower A · G", + "Voltas", + , + , + , + ], + [ + APP-1109, + VRV Outdoor, + "HVAC", + "Tower A · 1", + "Voltas", + "Normal", + , + , + ], + [ + APP-1112, + Air Handling Unit, + "HVAC", + "Tower A · G", + "In-house", + , + , + , + ], + [ + APP-1115, + Air Handling Unit, + "Electrical", + "Tower A · 2", + "Voltas", + , + , + , + ], + [ + APP-1118, + Chiller, + "Electrical", + "Block 1 · 1", + "In-house", + "Important", + , + , + ], + [ + APP-1121, + Cooling Tower, + "Plumbing", + "Tower A · 1", + "Blue Star", + "Normal", + , + , + ], + ]; return ( - -
- -
- - - - {/* TABLE HEADER */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* TABLE BODY */} - - - - {mockData.map((row) => { - - const isSelected = selectedIds.includes(row.id); - - - - return ( - - - - {/* Left Selection Indicator Bar (for Row 1 / Selected Rows) */} - - - - - - {/* Block */} - - - - - - {/* Floor */} - - - - - - {/* Zone */} - - - - - - {/* Department */} - - - - - - {/* Location */} - - - - - - {/* Window */} - - - - - - {/* TAT */} - - - - - - {/* Sched */} - - - - - - {/* Approval */} - - - - - - {/* Status Badge */} - - - - - - {/* Action Icon Buttons */} - - - - - - ); - - })} - - - -
- - - - BLOCKFLOORZONEDEPARTMENTLOCATIONWINDOWTATSCHED.APPROVALSTATUSACTIONS
- - {isSelected && ( - - - - )} - - toggleSelectRow(row.id)} - - className="rounded border-slate-700 bg-slate-900/80 text-teal-400 focus:ring-0 focus:ring-offset-0 cursor-pointer accent-teal-400 h-3.5 w-3.5" - - /> - - - - {row.block} - - - - {row.floor} - - - - {row.zone} - - - - {row.department} - - - - {row.location} - - - - {row.window} - - - - {row.tat} - - - - {row.sched} - - - - {row.approval ? ( - - - - - - Yes - - - - ) : ( - - —— - - )} - - - - {row.status === 'ACTIVE' ? ( - - - - - - ACTIVE - - - - ) : ( - - - - - - INACTIVE - - - - )} - - - -
- - - - - - - - - - - -
- -
- +
+
+ + Apple One — HQ Tower + + + + Operations + + + + Equipment + +
+ +

+ + Equipment & maintenance + +

+ +

+ + Asset register, preventive (PPM) and + + contract (AMC) maintenance, scoped to the active tenant. + +

+ + + + + {/* Navigation Tabs */} + + + {/* --- STAT CARDS (4 CARDS MATCHING SCREENSHOT) --- */} +
+ {/* Total equipment */} +
+
+
+ +
+ 4 groups +
+
+
8
+
Total equipment
+
+
+ + {/* Critical assets */} +
+
+
+ +
+ priority +
+
+
4
+
Critical assets
+
+
+ + {/* PPM attention */} +
+
+
+ +
+ due / overdue +
+
+
3
+
PPM attention
+
+
+ + {/* On plan */} +
+
+
+ +
+ healthy +
+
+
5
+
On plan
+
+
+ {/* --- ROW 2: SEARCH, FILTERS & ACTION BUTTONS --- */} +
+ {/* Search & Group Dropdown */} +
+ {/* Search Bar */} +
+ + +
+ {/* All groups dropdown */} + +
- + {/* Action Buttons Right Side */} +
+ {/* All QR */} + + {/* Download */} + + + {/* Bulk upload */} + + + {/* Add equipment */} + +
+
+ + {/* Data Table */} +
+ + + + {/* Info Banner */} +
+ +
- ); - -} \ No newline at end of file +} \ No newline at end of file diff --git a/components/dashboard/helpDesk.tsx b/components/dashboard/helpDesk.tsx index e4ebb9e..e5dc16d 100644 --- a/components/dashboard/helpDesk.tsx +++ b/components/dashboard/helpDesk.tsx @@ -1,31 +1,312 @@ - - -import { useState } from 'react'; +import { useState } from 'react'; import { Layers, ShieldCheck, CheckSquare, Clock, Search, - QrCode, + QrCode, + Power, + List, + Pencil, Plus, } from 'lucide-react'; import Button from "@/utils/button"; import StatCard from "@/utils/dashStatCard"; -import LocationTable from '@/utils/dataTable'; +import Table from "@/utils/dataTable"; import NavigationTabs from '@/utils/tabs'; import { helpdeskTtabs } from '@/constants/constant'; +const StatusBadge = ({ + text, + color, +}: { + text: string; + color: string; +}) => ( + + + {text} + +); + +const ActionButtons = ({ active }: { active: boolean }) => ( +
+ + + + + + + + + +
+); + +const headers = [ + "", + "Block", + "Floor", + "Zone", + "Department", + "Location", + "Window", + "TAT", + "Sched.", + "Approval", + "Status", + "Actions", +]; + +const checkbox = ( + +); + +const rows = [ + [ + checkbox, + "Block 2", + "1", + "Z2", + "HVAC", + Parking P1, + 01:56–18:00, + "60m", + "4", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "2", + "Z1", + "Inspection work", + Cafeteria, + 01:56–23:59, + "360m", + "6", + , + , + , + ], + + [ + checkbox, + "Block 2", + "G", + "N", + "Inspection work", + Main lobby, + 08:00–23:59, + "360m", + "4", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "2", + "Z2", + "Electrical", + Reception, + 08:00–18:00, + "360m", + "4", + , + , + , + ], + + [ + checkbox, + "Block 2", + "3", + "Z1", + "Housekeeping", + Cafeteria, + 08:00–18:00, + "20m", + "8", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "3", + "Z1", + "Electrical", + Food court, + 08:00–17:30, + "20m", + "8", + , + , + , + ], + + [ + checkbox, + "Block 2", + "1", + "Z2", + "HVAC", + Parking P1, + 01:56–18:00, + "60m", + "4", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "2", + "Z1", + "Inspection work", + Cafeteria, + 01:56–23:59, + "360m", + "6", + , + , + , + ], + + [ + checkbox, + "Block 2", + "G", + "N", + "Inspection work", + Main lobby, + 08:00–23:59, + "360m", + "4", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "2", + "Z2", + "Electrical", + Reception, + 08:00–18:00, + "360m", + "4", + , + , + , + ], + + [ + checkbox, + "Block 2", + "3", + "Z1", + "Housekeeping", + Cafeteria, + 08:00–18:00, + "20m", + "8", + ✓ Yes, + , + , + ], + + [ + checkbox, + "Block 1", + "3", + "Z1", + "Electrical", + Food court, + 08:00–17:30, + "20m", + "8", + , + , + , + ], +]; export default function HelpDeskPortal() { const [activeTab, setActiveTab] = useState('Location'); - - return ( -
+
{/* --- HEADER SECTION --- */} -
+
Apple One — HQ Tower @@ -34,123 +315,118 @@ export default function HelpDeskPortal() { Help Desk
-

+

Help Desk & checklists

-

+

Scheduled location and equipment inspections, missed-checklist recovery, and HSQE incident management.

-
- {/* Reusable Navigation Tabs */} - - - {/* Rest of your page content */} -
-
- {/* Total Checklists */} - - - {/* Active */} - +
+ {/* Reusable Navigation Tabs */} + +
- {/* Approval Set */} - - - {/* Avg TAT */} - -
+
+ {/* Total Checklists */} + + + {/* Active */} + - + {/* Approval Set */} + + + {/* Avg TAT */} + +
{/* --- ROW 2: SEARCH, FILTERS & ACTION BUTTONS --- */} -
+
{/* Search & Select Filters */} -
+
{/* Search Bar */} -
- +
+
{/* Block Dropdown */} - + -{/* Status Dropdown (Active State matching the screenshot) */} - + {/* Status Dropdown */} +
{/* Action Buttons */} -
- -
- - - - - + {/* --- TABLE CONTAINER --- */} +
+
+ ); -} - +} \ No newline at end of file diff --git a/components/dashboard/request.tsx b/components/dashboard/request.tsx index 26e426d..24230fb 100644 --- a/components/dashboard/request.tsx +++ b/components/dashboard/request.tsx @@ -5,6 +5,190 @@ import LocationTable from '@/utils/dataTable'; import NavigationTabs from '@/utils/tabs'; import { Reqeusttabs,statusFilters } from '@/constants/constant'; import FilterTabs from '@/utils/roundedFilters'; +import Table from '@/utils/dataTable'; + + +const StatusBadge = ({ + text, + color, +}: { + text: string; + color: string; +}) => ( + + + {text} + +); + +const headers = [ + "Request No.", + "Department", + "Issue", + "Location", + "Assignee", + "Source", + "Status", +]; +const rows = [ + [ + TFM/AP/2026/1009, + "Electrical", + "Lighting out", + "Block 1 · G", + "ME Local", + Line, + , + ], + + [ + TFM/AP/2026/1016, + "HVAC", + "AHU not cooling", + "Lobby · 1", + "Dhananjay T.", + Walk-in, + , + ], + + [ + TFM/AP/2026/1023, + "HVAC", + "Thermostat fault", + "Block 1 · 1", + "ME Local", + Mobile app, + , + ], + + [ + TFM/AP/2026/1030, + "HVAC", + "Thermostat fault", + "Block 1 · 1", + "Dhananjay T.", + Mobile app, + , + ], + + [ + TFM/AP/2026/1037, + "Civil", + "Glass break", + "Block 1 · 1", + "Local Helpdesk", + Walk-in, + , + ], + + [ + TFM/AP/2026/1044, + "HVAC", + "Chiller alarm", + "Block 1 · 1", + "Dhananjay T.", + Mobile app, + , + ], + + [ + TFM/AP/2026/1051, + "Plumbing", + "Water leakage", + "Lobby · 1", + "Local Helpdesk", + Walk-in, + , + ], + + [ + TFM/AP/2026/1058, + "Civil", + "Glass break", + "Block 2 · 2", + "Dhananjay T.", + Walk-in, + , + ], + + [ + TFM/AP/2026/1065, + "Civil", + "Ceiling crack", + "Lobby · G", + "ME Local", + Line, + , + ], + + [ + TFM/AP/2026/1072, + "Plumbing", + "Water leakage", + "Block 2 · G", + "TECH Local", + Line, + , + ], + + [ + TFM/AP/2026/1079, + "Electrical", + "DB switch fault", + "Tower A · 1", + "TECH Local", + Mobile app, + , + ], + + [ + TFM/AP/2026/1086, + "HVAC", + "AHU not cooling", + "Lobby · 3", + "TECH Local", + Walk-in, + , + ], +]; export default function ServiceRequestsPortal() { const [activeTab, setActiveTab] = useState('TFM Requests'); @@ -36,7 +220,9 @@ export default function ServiceRequestsPortal() { {/* --- NAVIGATION TABS & TOP ACTION BUTTONS --- */} -
+
{/* Navigation Tabs */} - +
+
+ + ); } \ No newline at end of file diff --git a/components/dashboard/visitorManagement.tsx b/components/dashboard/visitorManagement.tsx new file mode 100644 index 0000000..93f97c8 --- /dev/null +++ b/components/dashboard/visitorManagement.tsx @@ -0,0 +1,279 @@ +import { useState } from 'react'; +import { + Star, + ShieldCheck, + Activity, + Clock, + BarChart2, + Plus +} from "lucide-react"; +import Button from "@/utils/button"; +import StatCard from "@/utils/dashStatCard"; +import InfoBanner from "@/utils/infoBanner"; +import FilterTabs from '@/utils/roundedFilters'; +import { visitorFilters } from '@/constants/constant'; +import Table from '@/utils/dataTable'; + +export default function VistiorManagementPortal() { + const headers = [ + "Pass", + "Visitor", + "Company", + "Host", + "Purpose", + "Type", + "In", + "Out", + "Status", + "", +]; +const Badge = ({ + text, + color, +}: { + text: string; + color: string; +}) => ( + + + {text} + +); + +const rows = [ + [ + VIS-4145, + Rahul Mehta, + "Voltas Ltd", + "Dhananjay T.", + "Maintenance visit", + Contractor, + "09:12", + "—", + , + , + ], + + [ + VIS-4146, + Anita Desai, + "Siemens", + "ME Local", + "Interview", + Interview, + "—", + "—", + , + , + ], + + [ + VIS-4147, + Karthik R., + "Schindler", + "Site FM Lead", + "Client meeting", + Guest, + "08:05", + "10:40", + , + , + ], + + [ + VIS-4148, + Priya Nair, + "Amazon Logistics", + "Estates Office", + "Material delivery", + Delivery, + "—", + "—", + , + , + ], + + [ + VIS-4149, + Imran Q., + "FreshMenu", + "TECH Local", + "AMC service", + Contractor, + "10:30", + "—", + , + , + ], + [ + VIS-4145, + Rahul Mehta, + "Voltas Ltd", + "Dhananjay T.", + "Maintenance visit", + Contractor, + "09:12", + "—", + , + , + ], + + [ + VIS-4146, + Anita Desai, + "Siemens", + "ME Local", + "Interview", + Interview, + "—", + "—", + , + , + ], + + [ + VIS-4147, + Karthik R., + "Schindler", + "Site FM Lead", + "Client meeting", + Guest, + "08:05", + "10:40", + , + , + ], + + [ + VIS-4148, + Priya Nair, + "Amazon Logistics", + "Estates Office", + "Material delivery", + Delivery, + "—", + "—", + , + , + ], + + [ + VIS-4149, + Imran Q., + "FreshMenu", + "TECH Local", + "AMC service", + Contractor, + "10:30", + "—", + , + , + ], +]; + +const [activeFilter, setActiveFilter] = useState('All'); + return ( +
+ {/* --- HEADER SECTION --- */} +
+
+
+ Apple One — HQ Tower + + Workplace + + Visitors +
+

+ Visitor management +

+

+ Pre-registration, QR / OTP check-in, host notifications and on-site visitor tracking with a full audit trail. +

+
+ + {/* --- HEADER BUTTONS --- */} +
+ + + +
+
+ + {/* --- STAT CARDS --- */} +
+ {/* Active vendors */} + + + {/* Avg SLA adherence */} + + + {/* Open field jobs */} + + + {/* Avg response time */} + +
+ + {/* --- STATUS PILL FILTERS --- */} +
+ +
+
+ +
+ +
+ + + + + ); +} \ No newline at end of file diff --git a/constants/constant.ts b/constants/constant.ts index 1effc72..0840e80 100644 --- a/constants/constant.ts +++ b/constants/constant.ts @@ -226,6 +226,15 @@ export const Reqeusttabs: string[] = [ { label: 'Rejected', count: 1 }, ]; + export const visitorFilters = [ + { label: 'All', count: 12 }, + { label: 'Expected', count: 2 }, + { label: 'Pre-Reg', count: 2}, + { label: 'Onsite', count: 4 }, + { label: 'Left', count: 3 }, + { label: 'Denied', count: 1 }, + + ]; // Data model interface diff --git a/utils/dataTable.tsx b/utils/dataTable.tsx index 36b2d52..d2812ea 100644 --- a/utils/dataTable.tsx +++ b/utils/dataTable.tsx @@ -1,397 +1,55 @@ -import { useState } from 'react'; - -import { - - Pencil, - - Menu, - - ShieldCheck, - - QrCode, - - Power, - - Check, - - Sparkles, - -} from 'lucide-react'; - -import { mockData } from '@/constants/constant'; - - - - - -export default function LocationTable(){ - - const [selectedIds, setSelectedIds] = useState(['1']); // Row 1 selected by default (teal indicator bar) - - - - const toggleSelectAll = () => { - - if (selectedIds.length === mockData.length) { - - setSelectedIds([]); - - } else { - - setSelectedIds(mockData.map((row) => row.id)); - - } - - }; - - - - const toggleSelectRow = (id: string) => { - - setSelectedIds((prev) => - - prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id] - - ); - - }; - +import React from "react"; +type TableProps = { + headers: string[]; + rows: React.ReactNode[][]; +}; +export default function Table({ headers, rows }: TableProps) { return ( - -
- +
- -
- - {/* TABLE HEADER */} - +
- - - - - - - - - - - - - - - - - - - - - - - - - - - + + {headers.map((header, index) => ( + + ))} - - - - {/* TABLE BODY */} - - - - {mockData.map((row) => { - - const isSelected = selectedIds.includes(row.id); - - - - return ( - - - - {/* Left Selection Indicator Bar (for Row 1 / Selected Rows) */} - - + {rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + - - - - {/* Block */} - - - - - - {/* Floor */} - - - - - - {/* Zone */} - - - - - - {/* Department */} - - - - - - {/* Location */} - - - - - - {/* Window */} - - - - - - {/* TAT */} - - - - - - {/* Sched */} - - - - - - {/* Approval */} - - - - - - {/* Status Badge */} - - - - - - {/* Action Icon Buttons */} - - - - - - ); - - })} - + ))} + + ))} -
- - - - BLOCKFLOORZONEDEPARTMENTLOCATIONWINDOWTATSCHED.APPROVALSTATUSACTIONS
+ {header} +
- - {isSelected && ( - - - - )} - - toggleSelectRow(row.id)} - - className="rounded border-slate-700 bg-slate-900/80 text-teal-400 focus:ring-0 focus:ring-offset-0 cursor-pointer accent-teal-400 h-3.5 w-3.5" - - /> - +
+ {cell} - - {row.block} - - - - {row.floor} - - - - {row.zone} - - - - {row.department} - - - - {row.location} - - - - {row.window} - - - - {row.tat} - - - - {row.sched} - - - - {row.approval ? ( - - - - - - Yes - - - - ) : ( - - —— - - )} - - - - {row.status === 'ACTIVE' ? ( - - - - - - ACTIVE - - - - ) : ( - - - - - - INACTIVE - - - - )} - - - -
- - - - - - - - - - - -
- -
-
- - - - -
- ); - -} \ No newline at end of file +} \ No newline at end of file