258 lines
12 KiB
TypeScript
258 lines
12 KiB
TypeScript
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-[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-gray-600'>•</span>
|
|
<span className='text-gray-400'>IOT</span>
|
|
<span className='text-gray-600'>•</span>
|
|
<span className='text-gray-400'>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] 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.
|
|
</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>
|
|
);
|
|
} |