Configure Completed is added
This commit is contained in:
334
components/dashboard/iotapplication/alarmsRules.tsx
Normal file
334
components/dashboard/iotapplication/alarmsRules.tsx
Normal file
@@ -0,0 +1,334 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
BarChart2,
|
||||
Check,
|
||||
AlertTriangle,
|
||||
Clock,
|
||||
CheckCircle2,
|
||||
Cpu
|
||||
} from "lucide-react";
|
||||
import Button from "@/components/common/button";
|
||||
import StatCard from "@/components/common/dashStatCard";
|
||||
|
||||
export default function AlarmRulesPortal() {
|
||||
// State for automation rules toggles
|
||||
const [autoWorkOrder, setAutoWorkOrder] = useState(true);
|
||||
const [escalateCriticals, setEscalateCriticals] = useState(true);
|
||||
const [offHoursSetpoint, setOffHoursSetpoint] = useState(true);
|
||||
const [filterPpmTask, setFilterPpmTask] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="my-15 text-slate-100 font-sans">
|
||||
{/* --- HEADER SECTION --- */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
|
||||
<span>APPLE ONE — HQ TOWER</span>
|
||||
<span className="text-slate-500">•</span>
|
||||
<span className="text-slate-500">IOT</span>
|
||||
<span className="text-slate-500">•</span>
|
||||
<span className="text-slate-500">ALARMS & RULES</span>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white tracking-tight mt-1">
|
||||
Alarms & automation rules
|
||||
</h1>
|
||||
<p className="text-sm font-medium text-slate-400 mt-2 max-w-xl leading-relaxed">
|
||||
Acknowledge live alarms, raise work orders in one click, and manage the automation rules that act on telemetry.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* --- HEADER BUTTONS --- */}
|
||||
<div className="flex items-center gap-3 self-start md:mt-4">
|
||||
<Button className="bg-[#0e1c2e] hover:bg-slate-800 text-slate-200 border border-[#162942] text-xs px-4 py-2 rounded-lg flex items-center gap-2 font-semibold transition-colors">
|
||||
<BarChart2 className="w-4 h-4 text-slate-400" />
|
||||
<span>History</span>
|
||||
</Button>
|
||||
|
||||
<Button className="bg-[#10b981] hover:bg-emerald-400 text-slate-950 font-bold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-lg">
|
||||
<Check className="w-4 h-4 text-slate-950 stroke-[3]" />
|
||||
<span>Acknowledge all (3)</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- STAT CARDS --- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
{/* Card 1: Critical open */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Critical open"
|
||||
value="2"
|
||||
icon={AlertTriangle}
|
||||
badgeText="act now"
|
||||
badgeClassName="text-rose-400 lowercase font-mono font-medium"
|
||||
iconContainerClassName="bg-rose-950/50 border-rose-800/30 text-rose-400"
|
||||
/>
|
||||
|
||||
{/* Card 2: Warnings open */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Warnings open"
|
||||
value="1"
|
||||
icon={Clock}
|
||||
badgeText="review"
|
||||
badgeClassName="text-amber-400 lowercase font-mono font-medium"
|
||||
iconContainerClassName="bg-amber-950/50 border-amber-800/30 text-amber-400"
|
||||
/>
|
||||
|
||||
{/* Card 3: Acknowledged */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Acknowledged"
|
||||
value="2"
|
||||
icon={CheckCircle2}
|
||||
badgeText="today"
|
||||
badgeClassName="text-emerald-400 lowercase font-mono font-medium"
|
||||
iconContainerClassName="bg-emerald-950/60 border-emerald-800/40 text-emerald-400"
|
||||
/>
|
||||
|
||||
{/* Card 4: Rules active */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Rules active"
|
||||
value="3 / 4"
|
||||
icon={Cpu}
|
||||
badgeText="automation"
|
||||
badgeClassName="text-slate-400 lowercase font-mono font-medium"
|
||||
iconContainerClassName="bg-blue-950/60 border-blue-800/40 text-blue-400"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* --- MAIN CONTENT GRID --- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
{/* --- LEFT SECTION: ALARMS LIST --- */}
|
||||
<div className="lg:col-span-7 bg-[#091322]/80 border border-slate-800/80 rounded-xl p-5 shadow-sm">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-base font-bold text-white">Alarms</h2>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">live · newest first</p>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-slate-800/60">
|
||||
{/* Alarm Item 1 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-3">
|
||||
<div className="flex items-start gap-2.5 min-w-0">
|
||||
<span className="w-2 h-2 rounded-full bg-rose-500 shrink-0 mt-1.5" />
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-slate-100 truncate">
|
||||
<span className="text-teal-400 font-mono">CH-02</span>
|
||||
{" · "}
|
||||
<span>Condenser approach high — 4.2 K above design</span>
|
||||
</p>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">08:41 · open</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Ack
|
||||
</Button>
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Work order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alarm Item 2 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-3">
|
||||
<div className="flex items-start gap-2.5 min-w-0">
|
||||
<span className="w-2 h-2 rounded-full bg-amber-500 shrink-0 mt-1.5" />
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-slate-100 truncate">
|
||||
<span className="text-teal-400 font-mono">AHU-07</span>
|
||||
{" · "}
|
||||
<span>Filter ΔP beyond limit — replacement due</span>
|
||||
</p>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">08:12 · open</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Ack
|
||||
</Button>
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Work order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alarm Item 3 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-3">
|
||||
<div className="flex items-start gap-2.5 min-w-0">
|
||||
<span className="w-2 h-2 rounded-full bg-rose-500 shrink-0 mt-1.5" />
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-slate-100 truncate">
|
||||
<span className="text-teal-400 font-mono">CTL-14</span>
|
||||
{" · "}
|
||||
<span>Controller offline — no heartbeat for 30 min</span>
|
||||
</p>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">07:56 · open</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Ack
|
||||
</Button>
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Work order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alarm Item 4 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-3">
|
||||
<div className="flex items-start gap-2.5 min-w-0">
|
||||
<span className="w-2 h-2 rounded-full bg-amber-500 shrink-0 mt-1.5" />
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-slate-100 truncate">
|
||||
<span className="text-teal-400 font-mono">SNS-208</span>
|
||||
{" · "}
|
||||
<span>CO₂ trending up in open office L3 — 1,080 ppm</span>
|
||||
</p>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">07:30 · acknowledged</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Work order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Alarm Item 5 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-3">
|
||||
<div className="flex items-start gap-2.5 min-w-0">
|
||||
<span className="w-2 h-2 rounded-full bg-blue-500 shrink-0 mt-1.5" />
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-slate-100 truncate">
|
||||
<span className="text-teal-400 font-mono">GW-01</span>
|
||||
{" · "}
|
||||
<span>Gateway reconnected after 90 s network drop</span>
|
||||
</p>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">06:58 · acknowledged</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Button className="rounded-md border border-slate-700/60 bg-slate-900/40 px-3 py-1 text-xs font-medium text-slate-300 hover:bg-slate-800 hover:text-white transition">
|
||||
Work order
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- RIGHT SECTION: AUTOMATION RULES --- */}
|
||||
<div className="lg:col-span-5 bg-[#091322]/80 border border-slate-800/80 rounded-xl p-5 shadow-sm h-fit">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-base font-bold text-white">Automation rules</h2>
|
||||
<p className="text-xs font-mono text-slate-400 mt-0.5">telemetry → action</p>
|
||||
</div>
|
||||
|
||||
<div className="divide-y divide-slate-800/60">
|
||||
{/* Rule 1 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-slate-100">
|
||||
Auto work order on critical alarm
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
Raises a Help Desk request with the asset and fault pre-filled
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
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 ${
|
||||
autoWorkOrder ? 'bg-[#2dd4bf]' : 'bg-slate-700'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`pointer-events-none inline-block h-5 w-5 transform rounded-full bg-slate-950 shadow ring-0 transition duration-200 ease-in-out ${
|
||||
autoWorkOrder ? 'translate-x-5' : 'translate-x-0'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Rule 2 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-slate-100">
|
||||
Escalate unacknowledged criticals
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
Notifies the escalation matrix after 15 minutes
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
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 ${
|
||||
escalateCriticals ? 'bg-[#2dd4bf]' : 'bg-slate-700'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`pointer-events-none inline-block h-5 w-5 transform rounded-full bg-slate-950 shadow ring-0 transition duration-200 ease-in-out ${
|
||||
escalateCriticals ? 'translate-x-5' : 'translate-x-0'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Rule 3 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-slate-100">
|
||||
Off-hours setpoint relaxation
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
Widens comfort bands 22:00–06:00 to save energy
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
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 ${
|
||||
offHoursSetpoint ? 'bg-[#2dd4bf]' : 'bg-slate-700'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`pointer-events-none inline-block h-5 w-5 transform rounded-full bg-slate-950 shadow ring-0 transition duration-200 ease-in-out ${
|
||||
offHoursSetpoint ? 'translate-x-5' : 'translate-x-0'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Rule 4 */}
|
||||
<div className="py-3.5 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-slate-100">
|
||||
Filter ΔP → PPM task
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
Adds a filter change to the next PPM visit automatically
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
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 ${
|
||||
filterPpmTask ? 'bg-[#2dd4bf]' : 'bg-slate-800'
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`pointer-events-none inline-block h-5 w-5 transform rounded-full bg-slate-300 shadow ring-0 transition duration-200 ease-in-out ${
|
||||
filterPpmTask ? 'translate-x-5 bg-slate-950' : 'translate-x-0'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
258
components/dashboard/iotapplication/commandCenter.tsx
Normal file
258
components/dashboard/iotapplication/commandCenter.tsx
Normal file
@@ -0,0 +1,258 @@
|
||||
import React from 'react';
|
||||
import { BarChart2, AlertTriangle, Sparkles } from "lucide-react";
|
||||
import Button from "@/components/common/button";
|
||||
import { Card } from '@/components/common/cardWrapper';
|
||||
import { CardHeader } from '@/components/common/cardHeader';
|
||||
|
||||
|
||||
|
||||
// --- MAIN COMMAND CENTER PORTAL ---
|
||||
export default function CommandCenterPortal() {
|
||||
return (
|
||||
<div className="my-15 text-slate-100 font-sans">
|
||||
|
||||
{/* --- HEADER SECTION --- */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
|
||||
<span className="text-emerald-400 font-bold">APPLE ONE — HQ TOWER</span>
|
||||
<span>•</span>
|
||||
<span>IOT</span>
|
||||
<span>•</span>
|
||||
<span>COMMAND CENTER</span>
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight mt-1">
|
||||
IoT command center
|
||||
</h1>
|
||||
<p className="text-sm text-[#7f93ac] mt-2 max-w-xl leading-relaxed">
|
||||
Every gateway, controller and sensor across the portfolio on one live board — scoped to Apple One.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* --- HEADER BUTTONS --- */}
|
||||
<div className="flex items-center gap-3 self-start md:mt-2">
|
||||
<Button className="bg-[#0e1c2e] hover:bg-slate-800 text-slate-200 border border-[#162942] text-xs px-4 py-2 rounded-lg flex items-center gap-2 font-semibold transition-colors">
|
||||
<BarChart2 className="w-4 h-4 text-slate-400" />
|
||||
<span>Snapshot</span>
|
||||
</Button>
|
||||
|
||||
<Button className="bg-[#10b981] hover:bg-emerald-400 text-slate-950 font-bold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-lg">
|
||||
<AlertTriangle className="w-4 h-4 fill-slate-950 stroke-[#10b981]" />
|
||||
<span>3 open alarms</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- STAT CARDS (WITH PROGRESS LINES) --- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
{/* Card 1: SITES ONLINE */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
SITES ONLINE
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">2 / 2</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">all streaming</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-[#10b981] h-full rounded-full" style={{ width: '100%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 2: DEVICES */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
DEVICES
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">93</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">5 gateways</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-emerald-400 h-full rounded-full" style={{ width: '80%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 3: LIVE LOAD */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
LIVE LOAD
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">0.46 MW</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">portfolio now</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-sky-500 h-full rounded-full" style={{ width: '60%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 4: OPEN ALARMS */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
OPEN ALARMS
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">3</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">needs attention</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-rose-500 h-full rounded-full" style={{ width: '35%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* --- LOWER SECTION --- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
|
||||
{/* Left Column (2 Cards) */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
|
||||
{/* Site Cards Container */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* Site 1 */}
|
||||
<Card className="p-4">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-[#10b981]"></span>
|
||||
<h3 className="font-bold text-white text-sm">Apple One — HQ Tower</h3>
|
||||
</div>
|
||||
<span className="text-xs text-[#4e6178] font-mono">2 GW</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-xs text-[#8297b0] mt-2">
|
||||
<span><strong className="text-white">38</strong> devices</span>
|
||||
<span><strong className="text-white">200</strong> kW</span>
|
||||
<span className="bg-[#381a24] text-rose-400 font-bold px-2 py-0.5 rounded-full text-[11px] border border-rose-900/50">
|
||||
• 2
|
||||
</span>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Site 2 */}
|
||||
<Card className="p-4">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-[#10b981]"></span>
|
||||
<h3 className="font-bold text-white text-sm">Apple One — Annexe</h3>
|
||||
</div>
|
||||
<span className="text-xs text-[#4e6178] font-mono">3 GW</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-xs text-[#8297b0] mt-2">
|
||||
<span><strong className="text-white">55</strong> devices</span>
|
||||
<span><strong className="text-white">263</strong> kW</span>
|
||||
<span className="bg-[#381a24] text-rose-400 font-bold px-2 py-0.5 rounded-full text-[11px] border border-rose-900/50">
|
||||
• 1
|
||||
</span>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Protocol Mix Card */}
|
||||
<Card className="p-5">
|
||||
<CardHeader title="Protocol mix" subtitle="by device count" />
|
||||
<div className="space-y-4 text-xs font-medium mt-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="w-24 text-[#8297b0]">BACnet</span>
|
||||
<div className="flex-1 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-[#10b981] h-full rounded-full" style={{ width: '46%' }}></div>
|
||||
</div>
|
||||
<span className="w-8 text-right font-bold text-white">46%</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="w-24 text-[#8297b0]">Modbus</span>
|
||||
<div className="flex-1 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-[#10b981] h-full rounded-full" style={{ width: '31%' }}></div>
|
||||
</div>
|
||||
<span className="w-8 text-right font-bold text-white">31%</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="w-24 text-[#8297b0]">MQTT / LoRa</span>
|
||||
<div className="flex-1 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-[#10b981] h-full rounded-full" style={{ width: '18%' }}></div>
|
||||
</div>
|
||||
<span className="w-8 text-right font-bold text-white">18%</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="w-24 text-[#8297b0]">NB-IoT</span>
|
||||
<div className="flex-1 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-[#10b981] h-full rounded-full" style={{ width: '5%' }}></div>
|
||||
</div>
|
||||
<span className="w-8 text-right font-bold text-white">5%</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Right Column (Live Alarm Feed) */}
|
||||
<Card className="p-5 flex flex-col justify-between relative">
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<h3 className="font-semibold text-white text-base">Live alarm feed</h3>
|
||||
<button className="text-xs text-[#10b981] font-semibold hover:underline">
|
||||
All alarms
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-[11px] text-[#4e6178] font-mono mb-4">streaming</p>
|
||||
|
||||
<div className="space-y-4 divide-y divide-[#162942]/60">
|
||||
<div className="pt-2">
|
||||
<div className="flex items-start gap-2.5">
|
||||
<span className="w-2 h-2 rounded-full bg-rose-500 mt-1.5 shrink-0"></span>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-200 leading-snug">
|
||||
CH-02 • Condenser approach high — 4.2 K above design
|
||||
</p>
|
||||
<p className="text-[10px] text-[#4e6178] font-mono mt-0.5">08:41 • open</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-3">
|
||||
<div className="flex items-start gap-2.5">
|
||||
<span className="w-2 h-2 rounded-full bg-amber-400 mt-1.5 shrink-0"></span>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-200 leading-snug">
|
||||
AHU-07 • Filter ΔP beyond limit — replacement due
|
||||
</p>
|
||||
<p className="text-[10px] text-[#4e6178] font-mono mt-0.5">08:12 • open</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-3">
|
||||
<div className="flex items-start gap-2.5">
|
||||
<span className="w-2 h-2 rounded-full bg-rose-500 mt-1.5 shrink-0"></span>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-200 leading-snug">
|
||||
CTL-14 • Controller offline — no heartbeat for 30 min
|
||||
</p>
|
||||
<p className="text-[10px] text-[#4e6178] font-mono mt-0.5">07:56 • open</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-3">
|
||||
<div className="flex items-start gap-2.5">
|
||||
<span className="w-2 h-2 rounded-full bg-amber-400 mt-1.5 shrink-0"></span>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-200 leading-snug">
|
||||
SNS-208 • CO₂ trending up in open office L3 — 1,080 ppm
|
||||
</p>
|
||||
<p className="text-[10px] text-[#4e6178] font-mono mt-0.5">07:30 • acknowledged</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
108
components/dashboard/iotapplication/deviceFleet.tsx
Normal file
108
components/dashboard/iotapplication/deviceFleet.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
Grid2X2,
|
||||
AlertTriangle,
|
||||
Sun,
|
||||
Disc,
|
||||
Smartphone,
|
||||
FileText
|
||||
} from "lucide-react";
|
||||
import Button from "@/components/common/button";
|
||||
import StatCard from "@/components/common/dashStatCard";
|
||||
import InfoBanner from "@/components/common/infoBanner";
|
||||
import Table from '@/components/common/dataTable';
|
||||
import { contractheaders, contractrows, devicefleetheaders, devicefleetrows } from '@/constants/tabledata';
|
||||
|
||||
export default function DeviceFleetPortal() {
|
||||
return (
|
||||
<div className="my-15 text-slate-100 font-sans">
|
||||
{/* --- HEADER SECTION --- */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-[10px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
|
||||
<span>APPLE ONE — HQ TOWER</span>
|
||||
<span className="text-slate-500">•</span>
|
||||
<span className="text-slate-500">IOT</span>
|
||||
<span className="text-slate-500">•</span>
|
||||
<span className="text-slate-500">DEVICE FLEET</span>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white tracking-tight mt-1">
|
||||
Gateways, controllers & sensors
|
||||
</h1>
|
||||
<p className="text-sm font-medium text-slate-400 mt-2 max-w-xl leading-relaxed">
|
||||
The connected-device registry for Apple One — protocol, firmware and heartbeat for every device.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* --- HEADER BUTTONS --- */}
|
||||
<div className="flex items-center gap-3 self-start md:mt-4">
|
||||
<Button className="bg-[#0e1c2e] hover:bg-slate-800 text-slate-200 border border-[#162942] text-xs px-4 py-2 rounded-lg flex items-center gap-2 font-semibold transition-colors">
|
||||
<Smartphone className="w-4 h-4 text-slate-400" />
|
||||
<span>Pair device</span>
|
||||
</Button>
|
||||
|
||||
<Button className="bg-[#10b981] hover:bg-emerald-400 text-slate-950 font-bold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-lg">
|
||||
<Sun className="w-4 h-4 text-slate-950 stroke-[2.5]" />
|
||||
<span>Update firmware (1)</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- STAT CARDS --- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
{/* Card 1: Online */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Online"
|
||||
value="5"
|
||||
icon={Grid2X2}
|
||||
badgeText="heartbeat < 60 s"
|
||||
badgeClassName="text-emerald-400 lowercase font-mono"
|
||||
iconContainerClassName="bg-emerald-950/60 border-emerald-800/40 text-emerald-400"
|
||||
/>
|
||||
|
||||
{/* Card 2: Offline */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Offline"
|
||||
value="1"
|
||||
icon={AlertTriangle}
|
||||
badgeText="investigate"
|
||||
badgeClassName="text-rose-400 lowercase font-mono"
|
||||
iconContainerClassName="bg-rose-950/50 border-rose-800/30 text-rose-400"
|
||||
/>
|
||||
|
||||
{/* Card 3: Firmware pending */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Firmware pending"
|
||||
value="1"
|
||||
icon={Sun}
|
||||
badgeText="staged rollout"
|
||||
badgeClassName="text-amber-400 lowercase font-mono"
|
||||
iconContainerClassName="bg-amber-950/50 border-amber-800/30 text-amber-400"
|
||||
/>
|
||||
|
||||
{/* Card 4: Protocols */}
|
||||
<StatCard
|
||||
variant="icon"
|
||||
title="Protocols"
|
||||
value="4"
|
||||
icon={Disc}
|
||||
badgeText="BACnet • Modbus • MQTT • NB-IoT"
|
||||
badgeClassName="text-slate-400 lowercase font-mono"
|
||||
iconContainerClassName="bg-blue-950/60 border-blue-800/40 text-blue-400"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table headers={devicefleetheaders} rows={devicefleetrows}/>
|
||||
|
||||
<div className="mb-10 mt-10">
|
||||
<InfoBanner
|
||||
boldText="Device security is centrally managed: "
|
||||
normalText="registration, trust and firmware policy live in Administration → Security — end users cannot change them."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
198
components/dashboard/iotapplication/energyUtility.tsx
Normal file
198
components/dashboard/iotapplication/energyUtility.tsx
Normal file
@@ -0,0 +1,198 @@
|
||||
import React from 'react';
|
||||
import { BarChart2, Zap } from "lucide-react";
|
||||
import Button from "@/components/common/button";
|
||||
import { Card } from '@/components/common/cardWrapper';
|
||||
import Table from '@/components/common/dataTable';
|
||||
import { energyUtilityHeaders, energyUtilityRows } from '@/constants/tabledata';
|
||||
import InfoBanner from '@/components/common/infoBanner';
|
||||
|
||||
export default function EnergyUtilityPortal() {
|
||||
return (
|
||||
<div className="my-15 text-slate-100 font-sans">
|
||||
|
||||
{/* --- HEADER SECTION --- */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
|
||||
<span className="text-emerald-400 font-bold">APPLE ONE — HQ TOWER</span>
|
||||
<span>•</span>
|
||||
<span>IOT</span>
|
||||
<span>•</span>
|
||||
<span>ENERGY & UTILITIES</span>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white tracking-tight mt-1">
|
||||
Energy & utilities telemetry
|
||||
</h1>
|
||||
<p className="text-sm text-[#7f93ac] 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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* --- HEADER BUTTONS --- */}
|
||||
<div className="flex items-center gap-3 self-start md:mt-2">
|
||||
<Button className="bg-[#0e1c2e] hover:bg-slate-800 text-slate-200 border border-[#162942] text-xs px-4 py-2 rounded-lg flex items-center gap-2 font-semibold transition-colors">
|
||||
<BarChart2 className="w-4 h-4 text-slate-400" />
|
||||
<span>Export readings</span>
|
||||
</Button>
|
||||
|
||||
<Button className="bg-[#10b981] hover:bg-emerald-400 text-slate-950 font-bold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-lg">
|
||||
<Zap className="w-4 h-4 fill-slate-950 text-slate-950" />
|
||||
<span>Open Energy module</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- STAT CARDS (WITH PROGRESS LINES) --- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
|
||||
{/* Card 1: LIVE BUILDING LOAD */}
|
||||
<Card className="p-4 min-h-[120px] flex flex-col justify-between">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
LIVE BUILDING LOAD
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">386 kW</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">peak today 512 kW</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-emerald-400 rounded-full" style={{ width: '70%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 2: ENERGY TODAY (Active highlighted border) */}
|
||||
<Card className="p-4 min-h-[120px] flex flex-col justify-between border-2 border-emerald-500/80 bg-emerald-950/10">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
ENERGY TODAY
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">3,120 kWh</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">-4% vs yesterday</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-emerald-400 rounded-full" style={{ width: '65%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 3: WATER TODAY */}
|
||||
<Card className="p-4 min-h-[120px] flex flex-col justify-between">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
WATER TODAY
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">38.4 kL</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">municipal + borewell</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-blue-500 h-full rounded-full" style={{ width: '50%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 4: METERS ONLINE */}
|
||||
<Card className="p-4 min-h-[120px] flex flex-col justify-between">
|
||||
<div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
METERS ONLINE
|
||||
</span>
|
||||
<div className="text-3xl font-extrabold text-white mt-1">4 / 6</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">1 gas meter offline</p>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-1 rounded-full mt-4 overflow-hidden">
|
||||
<div className="bg-amber-400 h-full rounded-full" style={{ width: '67%' }}></div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
{/* --- TELEMETRY & BREAKDOWN SECTION --- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
|
||||
{/* Left Side: Smart Meters Table */}
|
||||
<Card className="lg:col-span-7 p-6 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-lg font-bold text-white">Smart meters</h2>
|
||||
<p className="text-xs text-[#5c738e] font-mono mt-0.5">auto-polled</p>
|
||||
</div>
|
||||
|
||||
<Table headers={energyUtilityHeaders} rows={energyUtilityRows} />
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Right Side: Load by end use — live */}
|
||||
<Card className="lg:col-span-5 p-4 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-lg font-bold text-white">Load by end use — live</h2>
|
||||
<p className="text-xs text-[#5c738e] font-mono mt-0.5">% of 386 kW</p>
|
||||
</div>
|
||||
|
||||
{/* Load Breakdown Bars */}
|
||||
<div className="space-y-5">
|
||||
|
||||
{/* HVAC Plant */}
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1.5">
|
||||
<span className="text-slate-100">HVAC plant</span>
|
||||
<span className="text-[#5c738e] font-mono">44%</span>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-blue-500 h-full rounded-full" style={{ width: '44%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lighting & small power */}
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1.5">
|
||||
<span className="text-slate-100">Lighting & small power</span>
|
||||
<span className="text-[#5c738e] font-mono">23%</span>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-emerald-400 rounded-full" style={{ width: '23%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lifts & pumps */}
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1.5">
|
||||
<span className="text-slate-100">Lifts & pumps</span>
|
||||
<span className="text-[#5c738e] font-mono">12%</span>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-amber-400 h-full rounded-full" style={{ width: '12%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Data / UPS */}
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1.5">
|
||||
<span className="text-slate-100">Data / UPS</span>
|
||||
<span className="text-[#5c738e] font-mono">11%</span>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-emerald-400 rounded-full" style={{ width: '11%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Others */}
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1.5">
|
||||
<span className="text-slate-100">Others</span>
|
||||
<span className="text-[#5c738e] font-mono">10%</span>
|
||||
</div>
|
||||
<div className="w-full bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-slate-500 rounded-full" style={{ width: '10%' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<InfoBanner boldText='Anomaly watch:' normalText='lighting load after 22:00 is 9% above baseline on Block 1 · L3 — an automation rule can raise a Help Desk ticket automatically (see Alarms & Rules).
|
||||
'/>
|
||||
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
355
components/dashboard/iotapplication/hvacPlant.tsx
Normal file
355
components/dashboard/iotapplication/hvacPlant.tsx
Normal file
@@ -0,0 +1,355 @@
|
||||
import React from 'react';
|
||||
import { BarChart2, Zap, Snowflake, Activity, Target } from "lucide-react";
|
||||
import Button from "@/components/common/button";
|
||||
import { Card } from '@/components/common/cardWrapper';
|
||||
|
||||
import BarChart from "@/components/charts/barchart"; // Replace path with your actual BarChart component import path
|
||||
|
||||
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() {
|
||||
return (
|
||||
<div className="my-15 text-slate-100 font-sans">
|
||||
|
||||
{/* --- HEADER SECTION --- */}
|
||||
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-4 mb-6">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 text-[11px] font-semibold tracking-widest text-[#4e6178] uppercase font-mono">
|
||||
<span className="text-emerald-400 font-bold">APPLE ONE — HQ TOWER</span>
|
||||
<span>•</span>
|
||||
<span>IOT</span>
|
||||
<span>•</span>
|
||||
<span>HVAC PLANT</span>
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold text-white tracking-tight mt-1">
|
||||
Chiller plant & air side
|
||||
</h1>
|
||||
<p className="text-sm text-[#7f93ac] mt-2 max-w-xl leading-relaxed">
|
||||
Live chiller, AHU and plant telemetry with start/stop control — commands are audit-logged.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* --- HEADER BUTTONS --- */}
|
||||
<div className="flex items-center gap-3 self-start md:mt-2">
|
||||
<Button className="bg-[#0e1c2e] hover:bg-slate-800 text-slate-200 border border-[#162942] text-xs px-4 py-2 rounded-lg flex items-center gap-2 font-semibold transition-colors">
|
||||
<BarChart2 className="w-4 h-4 text-slate-400" />
|
||||
<span>Plant report</span>
|
||||
</Button>
|
||||
|
||||
<Button className="bg-[#10b981] hover:bg-emerald-400 text-slate-950 font-bold text-xs px-4 py-2 rounded-lg flex items-center gap-2 transition-colors shadow-lg">
|
||||
<Activity className="w-4 h-4 text-slate-950" />
|
||||
<span>Optimise staging</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- STAT CARDS (WITH ICON BADGES) --- */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
|
||||
{/* Card 1: Chillers running */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="p-2.5 rounded-lg bg-blue-950/60 border border-blue-800/40 text-blue-400">
|
||||
<Snowflake className="w-5 h-5" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
staged
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="text-3xl font-extrabold text-white">2 / 3</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">Chillers running</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 2: Avg COP */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800/40 text-emerald-400">
|
||||
<Activity className="w-5 h-5" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-emerald-400 tracking-wider uppercase font-mono">
|
||||
plant efficiency
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="text-3xl font-extrabold text-white">5.60</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">Avg COP</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 3: Plant load */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="p-2.5 rounded-lg bg-amber-950/50 border border-amber-800/40 text-amber-400">
|
||||
<Zap className="w-5 h-5" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
now
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="text-3xl font-extrabold text-white">401 kW</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">Plant load</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Card 4: AHUs running */}
|
||||
<Card className="p-4 min-h-[120px]">
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="p-2.5 rounded-lg bg-teal-950/60 border border-teal-800/40 text-teal-400">
|
||||
<Target className="w-5 h-5" />
|
||||
</div>
|
||||
<span className="text-[10px] font-bold text-[#5c738e] tracking-wider uppercase font-mono">
|
||||
air side
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="text-3xl font-extrabold text-white">3 / 4</div>
|
||||
<p className="text-xs text-[#5c738e] mt-1">AHUs running</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* --- TELEMETRY SECTION --- */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
|
||||
{/* Left Card: Chillers & Plant Load Chart */}
|
||||
<Card className="lg:col-span-7 p-6">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-lg font-bold text-white">Chillers</h2>
|
||||
<p className="text-xs text-[#5c738e] font-mono mt-0.5">live • 5 s refresh</p>
|
||||
</div>
|
||||
|
||||
{/* Chillers Table */}
|
||||
<div className="overflow-x-auto mb-8">
|
||||
<table className="w-full text-left text-xs">
|
||||
<thead>
|
||||
<tr className="text-[#5c738e] font-mono uppercase text-[10px] border-b border-[#162942]/60">
|
||||
<th className="pb-3 font-normal">UNIT</th>
|
||||
<th className="pb-3 font-normal">STATUS</th>
|
||||
<th className="pb-3 font-normal">LOAD</th>
|
||||
<th className="pb-3 font-normal">COP</th>
|
||||
<th className="pb-3 font-normal">CHW SUPPLY / RETURN</th>
|
||||
<th className="pb-3 font-normal">KW</th>
|
||||
<th className="pb-3 font-normal text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-[#162942]/40 font-mono">
|
||||
{/* CH-01 */}
|
||||
<tr>
|
||||
<td className="py-3.5 font-bold text-teal-400">CH-01</td>
|
||||
<td className="py-3.5">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• RUNNING
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-emerald-400 h-full rounded-full" style={{ width: '72%' }}></div>
|
||||
</div>
|
||||
<span className="text-slate-300">72%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3.5 font-bold text-emerald-400">5.8</td>
|
||||
<td className="py-3.5 text-slate-300">6.2 °C / 11.8 °C</td>
|
||||
<td className="py-3.5 text-slate-300">212</td>
|
||||
<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">
|
||||
Stop
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* CH-02 */}
|
||||
<tr>
|
||||
<td className="py-3.5 font-bold text-teal-400">CH-02</td>
|
||||
<td className="py-3.5">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• RUNNING
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-emerald-400 h-full rounded-full" style={{ width: '64%' }}></div>
|
||||
</div>
|
||||
<span className="text-slate-300">64%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3.5 font-bold text-amber-400">5.4</td>
|
||||
<td className="py-3.5 text-slate-300">6.5 °C / 12.1 °C</td>
|
||||
<td className="py-3.5 text-slate-300">189</td>
|
||||
<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">
|
||||
Stop
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* CH-03 */}
|
||||
<tr>
|
||||
<td className="py-3.5 font-bold text-teal-400">CH-03</td>
|
||||
<td className="py-3.5">
|
||||
<span className="px-2 py-0.5 rounded-full bg-slate-800/60 border border-slate-700/50 text-slate-400 text-[10px] font-bold">
|
||||
• STANDBY
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 bg-[#122339] h-2 rounded-full overflow-hidden">
|
||||
<div className="bg-slate-700 h-full rounded-full" style={{ width: '0%' }}></div>
|
||||
</div>
|
||||
<span className="text-slate-400">0%</span>
|
||||
</div>
|
||||
</td>
|
||||
<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-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">
|
||||
Start
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Plant Load Reusable Bar Chart Component */}
|
||||
<div>
|
||||
<h3 className="text-[10px] font-bold
|
||||
tracking-wider uppercase font-mono mb-4">
|
||||
PLANT LOAD • TODAY
|
||||
</h3>
|
||||
<div className="flex-grow flex flex-col justify-end">
|
||||
<BarChart data={plantLoadData} />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Right Card: Air Handling Units */}
|
||||
<Card className="lg:col-span-5 p-6 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-lg font-bold text-white">Air handling units</h2>
|
||||
<p className="text-xs text-[#5c738e] font-mono mt-0.5">supply air • fan speed</p>
|
||||
</div>
|
||||
|
||||
{/* AHUs Table */}
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left text-xs">
|
||||
<thead>
|
||||
<tr className="text-[#5c738e] font-mono uppercase text-[10px] border-b border-[#162942]/60">
|
||||
<th className="pb-3 font-normal">UNIT</th>
|
||||
<th className="pb-3 font-normal">ZONE</th>
|
||||
<th className="pb-3 font-normal">STATUS</th>
|
||||
<th className="pb-3 font-normal">SAT</th>
|
||||
<th className="pb-3 font-normal">FAN</th>
|
||||
<th className="pb-3 font-normal">FILTER</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-[#162942]/40 font-mono">
|
||||
{/* AHU-01 */}
|
||||
<tr>
|
||||
<td className="py-4 font-bold text-teal-400 leading-tight">AHU-01</td>
|
||||
<td className="py-4 text-slate-200 font-sans font-medium leading-tight">Lobby & atrium</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• ON
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-4 text-slate-200">14.2 °C</td>
|
||||
<td className="py-4 text-slate-200">62%</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• OK
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* AHU-04 */}
|
||||
<tr>
|
||||
<td className="py-4 font-bold text-teal-400 leading-tight">AHU-04</td>
|
||||
<td className="py-4 text-slate-200 font-sans font-medium leading-tight">Floors 2–4</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• ON
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-4 text-slate-200">13.8 °C</td>
|
||||
<td className="py-4 text-slate-200">71%</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• OK
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* AHU-07 */}
|
||||
<tr>
|
||||
<td className="py-4 font-bold text-teal-400 leading-tight">AHU-07</td>
|
||||
<td className="py-4 text-slate-200 font-sans font-medium leading-tight">Floors 5–7</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• ON
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-4 text-slate-200">15.1 °C</td>
|
||||
<td className="py-4 text-slate-200">84%</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-amber-950/80 border border-amber-800/50 text-amber-400 text-[10px] font-bold">
|
||||
• REPLACE
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* AHU-09 */}
|
||||
<tr>
|
||||
<td className="py-4 font-bold text-teal-400 leading-tight">AHU-09</td>
|
||||
<td className="py-4 text-slate-200 font-sans font-medium leading-tight">
|
||||
Basement · parking
|
||||
</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-slate-800/60 border border-slate-700/50 text-slate-400 text-[10px] font-bold">
|
||||
• OFF
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-4 text-slate-500">—</td>
|
||||
<td className="py-4 text-slate-400">0%</td>
|
||||
<td className="py-4">
|
||||
<span className="px-2 py-0.5 rounded-full bg-emerald-950/80 border border-emerald-800/50 text-emerald-400 text-[10px] font-bold">
|
||||
• OK
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer Warning Notice */}
|
||||
<div className="pt-6 border-t border-[#162942]/60 mt-6 text-xs text-[#7f93ac] leading-relaxed">
|
||||
AHU-07 filter ΔP is beyond limit — a PPM task can be raised automatically from{' '}
|
||||
<strong className="text-slate-200 hover:underline cursor-pointer">Alarms & Rules</strong>.
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user