119 lines
5.7 KiB
TypeScript
119 lines
5.7 KiB
TypeScript
export const metadata = {
|
|||
|
|
title: "System Status — Property Management Network",
|
||
|
|
description: "Real-time status of all Property Management Network services.",
|
||
|
|
}
|
||
|
|
|
||
|
|
const SERVICES = [
|
||
|
|
{ name: "Web Application", status: "operational", uptime: "99.98%" },
|
||
|
|
{ name: "API Gateway", status: "operational", uptime: "99.97%" },
|
||
|
|
{ name: "Database (Supabase)", status: "operational", uptime: "99.99%" },
|
||
|
|
{ name: "Payment Processing (Stripe)", status: "operational", uptime: "99.95%" },
|
||
|
|
{ name: "Email Delivery (Resend)", status: "operational", uptime: "99.96%" },
|
||
|
|
{ name: "File Storage", status: "operational", uptime: "99.99%" },
|
||
|
|
{ name: "Tenant Portal", status: "operational", uptime: "99.97%" },
|
||
|
|
{ name: "Webhook Delivery", status: "operational", uptime: "99.90%" },
|
||
|
|
]
|
||
|
|
|
||
|
|
const INCIDENTS = [
|
||
|
|
{
|
||
|
|
date: "2026-03-28",
|
||
|
|
title: "Resolved: Delayed email notifications",
|
||
|
|
detail: "Email notifications were delayed by up to 12 minutes due to a Resend upstream issue. Fully resolved at 14:32 UTC.",
|
||
|
|
severity: "minor",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
date: "2026-02-14",
|
||
|
|
title: "Resolved: Slow dashboard load times",
|
||
|
|
detail: "Database query optimisations were deployed to fix a slow index scan affecting dashboards with 50+ units. Resolved in 45 minutes.",
|
||
|
|
severity: "minor",
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
export default function StatusPage() {
|
||
|
|
const allOperational = SERVICES.every((s) => s.status === "operational")
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="bg-[#09090b] text-white min-h-screen">
|
||
|
|
<div className="mx-auto max-w-3xl px-6 pt-32 pb-24">
|
||
|
|
{/* Header */}
|
||
|
|
<div className="mb-10">
|
||
|
|
<h1 className="text-3xl font-bold text-white mb-2">System Status</h1>
|
||
|
|
<p className="text-white/40 text-sm">Real-time health of all Property Management Network services.</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Overall status */}
|
||
|
|
<div className={`flex items-center gap-3 rounded-2xl border p-5 mb-8 ${allOperational ? "border-emerald-500/20 bg-emerald-500/5" : "border-red-500/20 bg-red-500/5"}`}>
|
||
|
|
<div className={`relative flex h-3 w-3`}>
|
||
|
|
<span className={`animate-ping absolute inline-flex h-full w-full rounded-full opacity-75 ${allOperational ? "bg-emerald-400" : "bg-red-400"}`} />
|
||
|
|
<span className={`relative inline-flex rounded-full h-3 w-3 ${allOperational ? "bg-emerald-400" : "bg-red-400"}`} />
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<p className={`font-semibold text-sm ${allOperational ? "text-emerald-300" : "text-red-300"}`}>
|
||
|
|
{allOperational ? "All systems operational" : "Partial outage detected"}
|
||
|
|
</p>
|
||
|
|
<p className="text-xs text-white/30 mt-0.5">Last checked: just now</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Services */}
|
||
|
|
<div className="rounded-2xl border border-white/[0.06] bg-[#111118] overflow-hidden mb-10">
|
||
|
|
<div className="px-5 py-3.5 border-b border-white/[0.04]">
|
||
|
|
<p className="text-xs font-semibold uppercase tracking-wider text-white/30">Services</p>
|
||
|
|
</div>
|
||
|
|
{SERVICES.map((svc, i) => (
|
||
|
|
<div key={svc.name} className={`flex items-center justify-between px-4 sm:px-5 py-3.5 sm:py-4 gap-3 ${i !== SERVICES.length - 1 ? "border-b border-white/[0.04]" : ""}`}>
|
||
|
|
<div className="flex items-center gap-2 min-w-0">
|
||
|
|
<div className={`shrink-0 h-2 w-2 rounded-full ${svc.status === "operational" ? "bg-emerald-400" : svc.status === "degraded" ? "bg-amber-400" : "bg-red-400"}`} />
|
||
|
|
<span className="text-sm text-white/80 truncate">{svc.name}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-3 sm:gap-6 shrink-0">
|
||
|
|
<span className="hidden sm:block text-xs text-white/30 tabular-nums">{svc.uptime} uptime</span>
|
||
|
|
<span className={`text-xs font-medium capitalize ${svc.status === "operational" ? "text-emerald-400" : svc.status === "degraded" ? "text-amber-400" : "text-red-400"}`}>
|
||
|
|
{svc.status}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Uptime graph placeholder */}
|
||
|
|
<div className="rounded-2xl border border-white/[0.06] bg-[#111118] p-5 mb-10">
|
||
|
|
<p className="text-xs font-semibold uppercase tracking-wider text-white/30 mb-4">90-day uptime</p>
|
||
|
|
<div className="flex gap-px sm:gap-0.5 h-6 sm:h-8 items-end">
|
||
|
|
{Array.from({ length: 90 }).map((_, i) => (
|
||
|
|
<div
|
||
|
|
key={i}
|
||
|
|
className="flex-1 rounded-sm bg-emerald-500/70"
|
||
|
|
style={{ height: `${Math.random() > 0.03 ? 100 : Math.floor(Math.random() * 60 + 20)}%` }}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
<div className="flex justify-between mt-2 text-[10px] text-white/20">
|
||
|
|
<span>90 days ago</span>
|
||
|
|
<span>Today</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Incidents */}
|
||
|
|
<div>
|
||
|
|
<h2 className="text-lg font-bold text-white mb-4">Past Incidents</h2>
|
||
|
|
<div className="space-y-3">
|
||
|
|
{INCIDENTS.map((inc) => (
|
||
|
|
<div key={inc.date} className="rounded-2xl border border-white/[0.06] bg-[#111118] p-5">
|
||
|
|
<div className="flex items-center gap-2 mb-2">
|
||
|
|
<span className="text-[10px] font-medium px-2 py-0.5 rounded-full bg-amber-500/10 text-amber-400 uppercase">
|
||
|
|
{inc.severity}
|
||
|
|
</span>
|
||
|
|
<span className="text-xs text-white/30">{inc.date}</span>
|
||
|
|
</div>
|
||
|
|
<p className="text-sm font-semibold text-white mb-1">{inc.title}</p>
|
||
|
|
<p className="text-xs text-white/50 leading-relaxed">{inc.detail}</p>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|