Dashboard Componeets files are added some

This commit is contained in:
2026-07-14 13:20:26 +01:00
parent ca40bd4095
commit 4c8c537f9c
13 changed files with 499 additions and 20 deletions

View File

@@ -2,6 +2,7 @@
import Sidebar from "@/components/dashboard/sidebar"; import Sidebar from "@/components/dashboard/sidebar";
import OperationsDashboard from "@/components/dashboard/dashboard";
export default function DashboardPage() { export default function DashboardPage() {
return ( return (
@@ -10,8 +11,8 @@ export default function DashboardPage() {
<main className="flex bg-[#091522]"> <main className="flex bg-[#091522]">
<Sidebar /> <Sidebar />
<div className="flex-1 p-10 text-white"> <div className="flex-1 p-6 text-white">
Main Content <OperationsDashboard/>
</div> </div>
</main> </main>

View File

@@ -0,0 +1,28 @@
import { ActivityFeedProps } from "@/constants/types"
export default function ActivityFeed({ activities }: ActivityFeedProps) {
return (
<div className="rounded-xl border border-[#14253d] bg-[#0c1a2c] p-6 flex flex-col">
<h3 className="text-base font-semibold text-white mb-4">Recent activity</h3>
<hr className="border-[#14253d] mb-6" />
<div className="divide-y divide-[#14253d] flex-1 flex flex-col justify-between">
{activities.map((activity, index) => {
const parts = activity.text.split(activity.boldText);
return (
<div key={index} className="py-3.5 flex items-start text-sm gap-4 first:pt-0 last:pb-0">
<span className="text-gray-500 font-medium tabular-nums shrink-0">{activity.time}</span>
<p className="text-gray-300">
{parts[0]}
<span className="font-semibold text-white">{activity.boldText}</span>
{parts[1]}
</p>
</div>
);
})}
</div>
</div>
);
}

View File

@@ -0,0 +1,34 @@
import {BarChartProps} from "@/constants/types";
export default function BarChart({ data }: BarChartProps) {
return (
<div className="rounded-xl border border-[#14253d] bg-[#0c1a2c]
p-4 flex flex-col justify-between">
<div className="flex items-center justify-between mb-4 ">
<h3 className="text-base font-semibold text-white">TFM requests · monthly</h3>
<span className="text-xs text-gray-500">2026 · auto-refresh 60s</span>
</div>
<hr className="border-[#14253d] mb-6" />
<div>
{/* Bars */}
<div className="flex items-end justify-between h-40 px-2 border-b border-[#1b3454] pb-2">
{data.map((item, idx) => (
<div key={idx} className="flex flex-col items-center flex-1 group">
<div className={`w-5 ${item.height} bg-teal-400 rounded-t transition-all duration-300 group-hover:bg-teal-300`} />
</div>
))}
</div>
{/* X-Axis */}
<div className="flex justify-between pt-3 px-2 text-xs font-medium text-gray-500">
{data.map((item, idx) => (
<span key={idx} className="w-5 text-center">{item.month}</span>
))}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,14 @@
export function CardHeader({ title, subtitle }: { title: string; subtitle?: string }) {
return (
<div className="flex justify-between items-baseline mb-2 border-b border-[#162942]/50 pb-3">
<h3 className="text-white text-base font-semibold tracking-wide">{title}</h3>
{subtitle && (
<span className="text-[#4e6178] text-xs font-medium uppercase tracking-wider">
{subtitle}
</span>
)}
</div>
);
}

View File

@@ -0,0 +1,8 @@
export function Card({ children, className = "" }: { children: React.ReactNode; className?: string }) {
return (
<div className={`bg-[#0a1526] border border-[#162942] rounded-xl p-3
shadow-xl flex flex-col justify-between ${className}`}>
{children}
</div>
);
}

View File

@@ -0,0 +1,189 @@
import { Check } from 'lucide-react';
import Navbar from "@/components/dashboard/navbar";
import BarChart from "@/components/dashboard/barchart";
import StatCard from "@/components/dashboard/statCard";
import ActivityFeed from "@/components/dashboard/activityFeed";
import {activities, chartData} from "@/constants/constant"
import { Card } from '@/components/dashboard/cardWrapper';
import {CardHeader} from '@/components/dashboard/cardHeader';
import {ProgressBarRow }from '@/components/dashboard/progressBarRow';
import {StatusProgressRow} from '@/components/dashboard/statusProgressRow';
export default function Dashboard() {
return (
<div className=" bg-[#071321] text-[#93a3b8] font-sans antialiased">
<Navbar />
<main >
{/* Title Section */}
<div className="flex items-start justify-between">
<div>
<div className="flex items-center gap-2
text-xs font-bold uppercase tracking-widest text-teal-500 mt-8">
<span>Apple One HQ Tower</span>
<span className="text-gray-600">·</span>
<span className="text-gray-400">Tenant</span>
<span className="text-gray-600">·</span>
<span className="text-gray-400">Apple One</span>
</div>
<h1 className="text-2xl font-bold text-white tracking-tight">Operations dashboard</h1>
<p className="mt-2 text-sm text-gray-400 max-w-xl leading-relaxed">
Live snapshot scoped to Apple One. The layout below is the dashboard published for this tenant in Administration.
</p>
</div>
<div className="mt-20 flex items-center gap-1 rounded-full border border-teal-500/30 bg-teal-500/10 px-2 py-1 text-xs font-medium text-teal-400">
<Check className="h-3.5 w-3.5 " />
<span>Published layout</span>
</div>
</div>
{/* 4 Cards Grid */}
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
<StatCard title="Open Requests" value={14} subtitle="+4 overdue" progress={70} color="teal" />
<StatCard title="Checklists Due" value={6} subtitle="of 10 scheduled" progress={60} color="amber" />
<StatCard title="PPM Attention" value={4} subtitle="assets off-plan" progress={40} color="rose" />
<StatCard title="Assets Tracked" value={8} subtitle="across blocks" progress={65} color="emerald" />
</div>
{/* Lower Row Grid */}
<div className=" mt-4 grid grid-cols-1 lg:grid-cols-12 gap-4">
<div className="lg:col-span-7">
<BarChart data={chartData} />
</div>
<div className="lg:col-span-5">
<ActivityFeed activities={activities} />
</div>
</div>
<div className="mt-4 grid grid-cols-1 lg:grid-cols-12 gap-6">
{/* Schedule Performance MMR */}
<div className="lg:col-span-7">
<Card>
<CardHeader title="Schedule performance • MMR" subtitle="ppm & amc" />
<div className="overflow-x-auto mt-2">
<table className=" text-left border-collapse">
<thead>
<tr className="text-[#4b5f7a] text-xs font-bold uppercase tracking-wider border-b border-[#1b2b41]/40 pb-3">
<th className="pb-3">Schedule</th>
<th className="pb-3 text-right">Total</th>
<th className="pb-3 text-right">Done</th>
<th className="pb-3 text-right">On Time</th>
<th className="pb-3 text-right">Delayed</th>
</tr>
</thead>
<tbody className="divide-y divide-[#1b2b41]/30 text-sm font-semibold">
<tr className="hover:bg-[#11233a]/25 transition-colors">
<td className="py-4 text-white">PPM</td>
<td className="py-4 text-right text-slate-300">24</td>
<td className="py-4 text-right text-slate-300">19</td>
<td className="py-4 text-right text-slate-300">17</td>
<td className="py-4 text-right text-red-500">2</td>
</tr>
<tr className="hover:bg-[#11233a]/25 transition-colors">
<td className="py-4 text-white">AMC</td>
<td className="py-4 text-right text-slate-300">8</td>
<td className="py-4 text-right text-slate-300">6</td>
<td className="py-4 text-right text-slate-300">6</td>
<td className="py-4 text-right text-slate-400">0</td>
</tr>
</tbody>
</table>
</div>
</Card>
</div>
{/* Energy Today */}
<div className="lg:col-span-5 ">
<Card>
<CardHeader title="Energy • today"
subtitle="day-wise" />
<div className="space-y-2
text-sm mt-2 font-mono">
<div className="flex justify-between items-baseline">
<span className="text-[#4b5f7a] font-semibold text-xs tracking-wider uppercase">Electricity</span>
<span className="text-white text-base font-bold">1,284 <span className="text-xs font-normal text-slate-400 font-sans">kwh</span></span>
</div>
<div className="flex justify-between items-baseline">
<span className="text-[#4b5f7a] font-semibold text-xs tracking-wider uppercase">Water</span>
<span className="text-white text-base font-bold">312 <span className="text-xs font-normal text-slate-400 font-sans">kL</span></span>
</div>
<div className="flex justify-between items-baseline">
<span className="text-[#4b5f7a] font-semibold text-xs tracking-wider uppercase">Diesel</span>
<span className="text-white text-base font-bold">48 <span className="text-xs font-normal text-slate-400 font-sans">L</span></span>
</div>
<div className="flex justify-between items-center pt-4 border-t border-[#1b2b41]/40">
<span className="text-[#4b5f7a] font-semibold text-xs tracking-wider uppercase">Vs Avg</span>
<div className="flex items-center space-x-3">
<span className="bg-[#0b2723] text-[#17cbb5] border border-[#17cbb5]/20 text-[10px] font-bold px-3 py-1 rounded-full flex items-center gap-1.5 uppercase">
<span className="w-1.5 h-1.5 rounded-full bg-[#17cbb5] inline-block animate-pulse"></span>
Completed
</span>
<span className="text-[#17cbb5] font-bold text-sm">-6%</span>
</div>
</div>
</div>
</Card>
</div>
</div>
{/* ROW 2: Sub-metrics and Tracking widgets */}
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{/* Top 5 Requester */}
<Card>
<CardHeader title="Top 5 requester" subtitle="this month" />
<div className="space-y-3 mt-1">
<ProgressBarRow label="Academic Block" value={18} maxValue={18} />
<ProgressBarRow label="Hostel Block" value={13} maxValue={18} />
<ProgressBarRow label="HVAC Plant" value={9} maxValue={18} />
<ProgressBarRow label="Pump Room" value={6} maxValue={18} />
<ProgressBarRow label="Lobby" value={4} maxValue={18} />
</div>
</Card>
{/* Asset Register */}
<Card>
<CardHeader title="Asset register" subtitle="live" />
<div className="flex items-baseline space-x-3 my-4">
<span className="text-5xl font-light text-[#17cbb5]">8</span>
<span className="text-[#5b7391] text-xs font-semibold uppercase tracking-wider">assets tracked</span>
</div>
<div className="space-y-3 text-sm font-semibold border-t border-[#1b2b41]/40 pt-4">
<div className="flex justify-between py-1">
<span className="text-[#4b5f7a] text-xs uppercase tracking-wider">On Plan</span>
<span className="text-white">3</span>
</div>
<div className="flex justify-between py-1">
<span className="text-[#4b5f7a] text-xs uppercase tracking-wider">Attention</span>
<span className="text-red-500">5</span>
</div>
<div className="flex justify-between py-1">
<span className="text-[#4b5f7a] text-xs uppercase tracking-wider">Groups</span>
<span className="text-white">4</span>
</div>
</div>
</Card>
{/* PM Plan vs Started */}
<Card>
<CardHeader title="PM plan vs started" subtitle="this month" />
<div className="space-y-4 mt-1">
<StatusProgressRow label="Planned" value={24} total={24} barColor="bg-[#52647c]" />
<StatusProgressRow label="Started" value={19} total={24} barColor="bg-[#17cbb5]" />
<StatusProgressRow label="Completed" value={17} total={24} barColor="bg-[#10b981]" />
</div>
</Card>
</div>
</main>
</div>
);
}

View File

@@ -0,0 +1,80 @@
import { Search, HelpCircle, Globe, Sun, Bell, ChevronDown, MapPin } from 'lucide-react';
export default function Navbar() {
return (
<header className="flex items-center justify-between
bg-[#071321] ">
{/* Left Group */}
<div className="flex items-center gap-2">
{/* Company Selector */}
<div className="flex items-center gap-2 rounded-full bg-[#0a1826]
px-3 py-1.5 text-sm font-semibold text-[#10b981]
border border-[#132338] cursor-pointer hover:bg-[#0f2338] transition whitespace-nowrap">
<span className="h-2 w-2 rounded-full bg-[#10b981] shrink-0"></span>
<span className="font-semibold">Apple One</span>
<ChevronDown className="h-3.5 w-3.5 text-[#10b981]" />
</div>
{/* Location Selector */}
<div className="flex items-center gap-2 rounded-full bg-[#0a1826] px-4 py-2 text-sm font-medium text-[#cbd5e1] border border-[#132338] cursor-pointer hover:bg-[#0f2338] transition whitespace-nowrap">
<MapPin className="h-4 w-4 text-gray-500 shrink-0" />
<span className="whitespace-nowrap">
Apple One <span className="text-[#cbd5e1] font-semibold">HQ Tower</span>
</span>
<ChevronDown className="h-4 w-4 text-gray-500 shrink-0" />
</div>
{/* Search Bar */}
<div className="relative w-60">
<Search className="absolute left-4 top-3 h-4 w-4 text-gray-500" />
<input
type="text"
placeholder="Search requests, equipment, met"
className="w-full rounded-xl bg-[#0a1826] pl-10 pr-4 py-2 text-sm text-white placeholder-gray-500 border border-[#132338] focus:outline-none focus:border-teal-500"
/>
</div>
</div>
{/* Right Utilities */}
<div className="flex items-center gap-3">
{/* Tour */}
<button className="flex items-center gap-2 rounded-xl border border-[#132338] bg-[#0a1826] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#14253d]">
<HelpCircle className="h-4 w-4 text-gray-400" />
<span>Tour</span>
</button>
{/* Language */}
<div className="flex items-center gap-1.5 rounded-xl border border-[#132338] bg-[#0a1826] px-4 py-2 text-sm font-semibold text-[#cbd5e1] cursor-pointer hover:bg-[#14253d]">
<Globe className="h-4 w-4 text-gray-400" />
<span>English</span>
<ChevronDown className="h-4 w-4 text-gray-500" />
</div>
{/* Live Indicator */}
<div className="flex items-center gap-2 px-1 text-sm font-bold text-[#10b981] tracking-wider">
<span className="h-1.5 w-1.5 rounded-full bg-[#10b981]"></span>
<span className="text-xs font-bold text-gray-400">LIVE</span>
</div>
{/* Theme Toggle */}
<button className="flex h-9 w-9 items-center justify-center rounded-xl border border-[#132338] bg-[#0a1826] text-gray-400 hover:text-white transition">
<Sun className="h-4 w-4" />
</button>
{/* Notifications */}
<div className="relative flex h-9 w-9 items-center justify-center rounded-xl border border-[#132338] bg-[#0a1826] cursor-pointer hover:bg-[#14253d] transition">
<Bell className="h-4 w-4 text-gray-400" />
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-[#ef4444] text-[9px] font-bold text-white">
8
</span>
</div>
{/* Profile Avatar */}
<div className="flex h-9 w-9 items-center justify-center rounded-full bg-[#1b3454] text-xs font-bold text-white cursor-pointer hover:opacity-90 transition">
DH
</div>
</div>
</header>
);
}

View File

@@ -0,0 +1,18 @@
import { ProgressBarProps } from "@/constants/types";
export function ProgressBarRow({ label, value, maxValue }: ProgressBarProps) {
const percentage = (value / maxValue) * 100;
return (
<div className="flex items-center justify-between py-1.5 text-sm">
<span className="text-[#899db7] w-32 truncate">{label}</span>
<div className="flex-1 mx-4 bg-[#122238] h-2.5 rounded-full overflow-hidden">
<div
className="bg-[#17cbb5] h-full rounded-full transition-all duration-500"
style={{ width: `${percentage}%` }}
/>
</div>
<span className="text-white font-bold w-6 text-right">{value}</span>
</div>
);
}

View File

@@ -1,42 +1,44 @@
import { SIDEBAR_ITEMS } from "@/constants/constant"; import { SIDEBAR_ITEMS } from "@/constants/constant";
import SidebarItem from "./sideBarItem"; import SidebarItem from "./sideBarItem";
import { import {
ShieldCheck,
ShieldCheck,
Activity, Activity,
ChevronDown, ChevronDown,
ChevronsLeft, ChevronsLeft,
} from "lucide-react"; } from "lucide-react";
export default function Sidebar() { export default function Sidebar() {
return ( return (
<aside className="w-80 bg-[#071321] text-white h-screen overflow-y-auto"> <aside className=" bg-[#071321] text-white h-screen overflow-y-auto">
<div className="flex items-center gap-2.5 px-4 pt-4 pb-3"> <div className="flex items-center gap-2 px-2 pt-2 pb-3">
<div className="flex h-9 w-9 items-center justify-center rounded-lg bg-[#3de0c4] font-bold text-[#05111d] text-lg"> <div className="flex h-9 w-9 items-center justify-center rounded-lg
bg-[#3de0c4] font-bold text-[#05111d] text-sm">
K K
</div> </div>
<span className="text-xl font-bold tracking-tight text-white"> <span className="text-sm font-bold tracking-tight text-white">
KA<span className="text-[#3de0c4]">FM</span> KA<span className="text-[#3de0c4]">FM</span>
</span> </span>
</div> </div>
<div className="mx-3 my-2 flex rounded-xl bg-[#091624] p-1 border border-[#142538]"> <div className="mx-4 my-2 flex rounded-xl
<button className="flex flex-1 items-center justify-center gap-1.5 rounded-lg bg-[#3de0c4] py-1.5 text-xs text-black font-semibold shadow-sm"> bg-[#091624] p-2 border border-[#142538]">
<button className="flex flex-1
items-center justify-center gap-1 rounded-lg bg-[#3de0c4] py-1.5 text-xs
text-black font-bold shadow-sm">
<Activity size={14} /> <Activity size={14} />
Operations Operations
</button> </button>
<button className="flex flex-1 items-center justify-center gap-1.5 rounded-lg py-1.5 text-xs text-slate-400 font-medium hover:text-white transition-colors"> <button className="flex flex-1 items-center justify-center gap-1
rounded-lg py-1 text-xs text-slate-400 font-medium hover:text-white transition-colors">
<ShieldCheck size={14} /> <ShieldCheck size={14} />
Admin Admin
</button> </button>
</div> </div>
<p className="px-4 pt-2 pb-1 text-xs font-semibold uppercase tracking-wider text-slate-500"> <p className="px-4 pt-2 pb-1 text-xs font-semibold uppercase
tracking-wider text-slate-500">
Tenant runtime Tenant runtime
</p> </p>
<div className="py-4"> <div className="py-3">
{SIDEBAR_ITEMS.map((item) => ( {SIDEBAR_ITEMS.map((item) => (
<SidebarItem <SidebarItem
key={item.title} key={item.title}

View File

@@ -0,0 +1,24 @@
import { StatCardProps } from "@/constants/types";
import { colorMap } from "@/constants/constant";
export default function StatCard({ title, value, subtitle, progress, color }: StatCardProps) {
return (
<div className="rounded-xl border border-[#14253d] bg-[#0c1a2c] p-4 flex flex-col justify-between ">
<div>
<span className="text-xs font-bold uppercase tracking-wider text-gray-400">{title}</span>
<div className="text-4xl font-bold text-white mt-1">{value}</div>
</div>
<div >
<span className="text-xs text-gray-400">{subtitle}</span>
<div className="w-full bg-[#162a45] h-1.5 rounded-full mt-2 overflow-hidden">
<div
className={`h-1.5 rounded-full ${colorMap[color]} transition-all duration-500`}
style={{ width: `${progress}%` }}
/>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,21 @@
import { StatusProgressProps } from "@/constants/types";
export function StatusProgressRow({ label, value, total, barColor = "bg-[#17cbb5]" }: StatusProgressProps) {
const percentage = (value / total) * 100;
return (
<div className="space-y-2 py-1.5">
<div className="flex justify-between text-xs font-semibold">
<span className="text-white">{label}</span>
<span className="text-[#5b7391]">{value}/{total}</span>
</div>
<div className="bg-[#122238] h-3 rounded-full overflow-hidden">
<div
className={`${barColor} h-full rounded-full transition-all duration-500`}
style={{ width: `${percentage}%` }}
/>
</div>
</div>
);
}

View File

@@ -31,12 +31,9 @@ import {
BarChart3, BarChart3,
Sun, Sun,
Shield, Shield,
Settings, Settings,
Wallet, Wallet,
Radar, Radar,
Cog, Cog,
} from "lucide-react"; } from "lucide-react";
@@ -128,4 +125,32 @@ export const SIDEBAR_ITEMS = [
{ title: "User Location", href: "/configure/user-location", icon: MapPin }, { title: "User Location", href: "/configure/user-location", icon: MapPin },
{ title: "Settings", href: "/configure/settings", icon: Sun },], { title: "Settings", href: "/configure/settings", icon: Sun },],
}, },
]; ];
export const chartData = [
{ month: 'J', height: 'h-24' },
{ month: 'F', height: 'h-16' },
{ month: 'M', height: 'h-32' },
{ month: 'A', height: 'h-20' },
{ month: 'M', height: 'h-28' },
{ month: 'J', height: 'h-12' },
{ month: 'J', height: 'h-32' },
{ month: 'A', height: 'h-24' },
{ month: 'S', height: 'h-30' },
{ month: 'O', height: 'h-20' },
{ month: 'N', height: 'h-26' },
{ month: 'D', height: 'h-24' },
];
export const activities = [
{ time: '09:42', text: '6/1009 assigned to ME Local', boldText: '6/1009' },
{ time: '09:18', text: 'Location checklist Block 1/2 completed', boldText: 'Block 1/2' },
{ time: '08:55', text: 'Meter MTR-1 reading logged · 58.45 kWh', boldText: 'Meter MTR-1' },
{ time: '08:30', text: 'PPM job card printed for APP-1100', boldText: 'APP-1100' },
];
export const colorMap = {
teal: 'bg-teal-400',
amber: 'bg-amber-500',
rose: 'bg-rose-500',
emerald: 'bg-emerald-500',
};

View File

@@ -6,4 +6,39 @@ export type Step = "login" | "verify" | "forgot";
onSuccess?: () => void; onSuccess?: () => void;
onForgotPassword?:()=>void; onForgotPassword?:()=>void;
item?: any; item?: any;
}
interface Activity {
time: string;
text: string;
boldText: string;
}
export interface ActivityFeedProps {
activities: Activity[];
}
interface ChartItem {
month: string;
height: string; // Tailwind h-class like 'h-24'
}
export interface BarChartProps {
data: ChartItem[];
}
export interface StatCardProps {
title: string;
value: number | string;
subtitle: string;
progress: number;
color: 'teal' | 'amber' | 'rose' | 'emerald';
}
export interface ProgressBarProps {
label: string;
value: number;
maxValue: number;
}
export interface StatusProgressProps {
label: string;
value: number;
total: number;
barColor?: string;
} }