Files
KAFM-Project/utils/table.tsx

226 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import {
Pencil,
Menu,
ShieldCheck,
QrCode,
Power,
Check,
Sparkles,
} from 'lucide-react';
// Data model interface
interface TableRowData {
id: string;
block: string;
floor: string;
zone: string;
department: string;
location: string;
window: string;
tat: string;
sched: number;
approval: boolean;
status: 'ACTIVE' | 'INACTIVE';
}
// Sample data extracted from your screenshot
const mockData: TableRowData[] = [
{ id: '1', block: 'Block 1', floor: 'G', zone: 'Z2', department: 'Electrical', location: 'Main lobby', window: '06:0017:30', tat: '60m', sched: 8, approval: true, status: 'INACTIVE' },
{ id: '2', block: 'Block 2', floor: '3', zone: 'Z2', department: 'Electrical', location: 'Main lobby', window: '08:0023:59', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
{ id: '3', block: 'Block 2', floor: '3', zone: 'Z1', department: 'Inspection work', location: 'Cafeteria', window: '06:0017:30', tat: '20m', sched: 8, approval: true, status: 'ACTIVE' },
{ id: '4', block: 'Block 1', floor: 'G', zone: 'Z1', department: 'HVAC', location: 'Server room', window: '08:0018:00', tat: '30m', sched: 4, approval: false, status: 'INACTIVE' },
{ id: '5', block: 'Block 2', floor: '3', zone: 'N', department: 'Inspection work', location: 'Server room', window: '08:0018:00', tat: '60m', sched: 8, approval: true, status: 'ACTIVE' },
{ id: '6', block: 'Block 2', floor: 'G', zone: 'Z1', department: 'Electrical', location: 'Reception', window: '06:0018:00', tat: '60m', sched: 6, approval: false, status: 'ACTIVE' },
{ id: '7', block: 'Block 1', floor: 'G', zone: 'Z2', department: 'Electrical', location: 'Food court', window: '06:0017:30', tat: '60m', sched: 8, approval: true, status: 'ACTIVE' },
{ id: '8', block: 'Block 2', floor: '3', zone: 'Z2', department: 'Electrical', location: 'Cafeteria', window: '08:0023:59', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
{ id: '9', block: 'Block 2', floor: '3', zone: 'Z1', department: 'Inspection work', location: 'Gym', window: '06:0017:30', tat: '20m', sched: 8, approval: true, status: 'INACTIVE' },
{ id: '10', block: 'Block 1', floor: 'G', zone: 'Z1', department: 'HVAC', location: 'Lobby', window: '08:0018:00', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
];
export default function LocationTable(){
const [selectedIds, setSelectedIds] = useState<string[]>(['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]
);
};
return (
<div className="w-full bg-[#071321] text-slate-300 rounded-xl overflow-hidden border border-slate-800/80 shadow-2xl relative font-sans">
<div className="overflow-x-auto">
<table className="w-full text-left text-xs border-collapse">
{/* TABLE HEADER */}
<thead>
<tr className="border-b border-slate-800/90 text-[11px] font-bold tracking-wider text-slate-500 uppercase font-mono">
<th className="py-4 px-4 w-12 text-center">
<input
type="checkbox"
checked={selectedIds.length === mockData.length}
onChange={toggleSelectAll}
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"
/>
</th>
<th className="py-4 px-3 font-mono">BLOCK</th>
<th className="py-4 px-3 font-mono">FLOOR</th>
<th className="py-4 px-3 font-mono">ZONE</th>
<th className="py-4 px-3 font-mono">DEPARTMENT</th>
<th className="py-4 px-3 font-mono">LOCATION</th>
<th className="py-4 px-3 font-mono">WINDOW</th>
<th className="py-4 px-3 font-mono">TAT</th>
<th className="py-4 px-3 font-mono">SCHED.</th>
<th className="py-4 px-3 font-mono">APPROVAL</th>
<th className="py-4 px-3 font-mono">STATUS</th>
<th className="py-4 px-4 font-mono text-right pr-6">ACTIONS</th>
</tr>
</thead>
{/* TABLE BODY */}
<tbody className="divide-y divide-slate-800/50">
{mockData.map((row) => {
const isSelected = selectedIds.includes(row.id);
return (
<tr
key={row.id}
className={`group relative transition-colors ${
isSelected
? 'bg-[#0e2238]/60 hover:bg-[#122942]/80'
: 'hover:bg-slate-800/30'
}`}
>
{/* Left Selection Indicator Bar (for Row 1 / Selected Rows) */}
<td className="py-3 px-4 text-center relative">
{isSelected && (
<span className="absolute left-0 top-0 bottom-0 w-[3px] bg-teal-400 rounded-r" />
)}
<input
type="checkbox"
checked={isSelected}
onChange={() => 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"
/>
</td>
{/* Block */}
<td className="py-3 px-3 font-semibold text-slate-100 whitespace-nowrap">
{row.block}
</td>
{/* Floor */}
<td className="py-3 px-3 font-medium text-slate-200">
{row.floor}
</td>
{/* Zone */}
<td className="py-3 px-3 font-medium text-slate-300">
{row.zone}
</td>
{/* Department */}
<td className="py-3 px-3 font-semibold text-slate-200 whitespace-nowrap">
{row.department}
</td>
{/* Location */}
<td className="py-3 px-3 font-extrabold text-white whitespace-nowrap">
{row.location}
</td>
{/* Window */}
<td className="py-3 px-3 font-mono text-slate-400 text-[11px] whitespace-nowrap">
{row.window}
</td>
{/* TAT */}
<td className="py-3 px-3 font-mono text-slate-200 font-medium">
{row.tat}
</td>
{/* Sched */}
<td className="py-3 px-3 font-mono text-slate-200 font-medium">
{row.sched}
</td>
{/* Approval */}
<td className="py-3 px-3 whitespace-nowrap">
{row.approval ? (
<span className="inline-flex items-center gap-1.5 text-emerald-400 font-semibold">
<Check size={14} className="stroke-[3]" />
<span>Yes</span>
</span>
) : (
<span className="text-slate-500 font-mono"></span>
)}
</td>
{/* Status Badge */}
<td className="py-3 px-3 whitespace-nowrap">
{row.status === 'ACTIVE' ? (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold font-mono tracking-wider bg-emerald-950/80 border border-emerald-800/40 text-emerald-400">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400"></span>
ACTIVE
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold font-mono tracking-wider bg-slate-800/80 border border-slate-700/50 text-slate-400">
<span className="h-1.5 w-1.5 rounded-full bg-slate-400"></span>
INACTIVE
</span>
)}
</td>
{/* Action Icon Buttons */}
<td className="py-3 px-4 text-right whitespace-nowrap pr-6">
<div className="inline-flex items-center gap-1.5">
<button
title="Edit"
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
>
<Pencil size={13} />
</button>
<button
title="Options"
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
>
<Menu size={13} />
</button>
<button
title="Security"
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
>
<ShieldCheck size={13} />
</button>
<button
title="QR Code"
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
>
<QrCode size={13} />
</button>
<button
title="Toggle Power"
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
>
<Power size={13} />
</button>
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}