Files

120 lines
5.0 KiB
TypeScript
Raw Permalink Normal View History

"use client"
import { useState, useMemo } from "react"
import Link from "next/link"
import { MaintenanceStatusBadge, PriorityBadge } from "@/components/dashboard/maintenance-status-badge"
import { EmptyState } from "@/components/shared/empty-state"
import { formatDate } from "@/lib/utils"
import { Wrench, SlidersHorizontal } from "lucide-react"
import { Select } from "@/components/ui/select"
export function MaintenanceList({ requests, properties }: { requests: any[]; properties: any[] }) {
const [propertyId, setPropertyId] = useState("")
const [status, setStatus] = useState("")
const filtered = useMemo(() =>
requests.filter((r) => {
if (propertyId && r.property_id !== propertyId) return false
if (status && r.status !== status) return false
return true
}), [requests, propertyId, status])
const open = requests.filter((r) => r.status === "open").length
const inProgress = requests.filter((r) => r.status === "in_progress").length
const resolved = requests.filter((r) => r.status === "resolved").length
return (
<div className="space-y-5">
{/* Stats */}
<div className="grid grid-cols-3 gap-3">
{[
{ label: "Open", value: open, color: "text-amber-400", dot: "bg-amber-500" },
{ label: "In Progress", value: inProgress, color: "text-blue-400", dot: "bg-blue-500" },
{ label: "Resolved", value: resolved, color: "text-emerald-400", dot: "bg-emerald-500" },
].map((s) => (
<div key={s.label} className="rounded-xl border border-white/[0.06] bg-[#16161f] p-4">
<div className="flex items-center gap-2">
<span className={`h-1.5 w-1.5 rounded-full ${s.dot}`} />
<p className="text-xs text-white/35">{s.label}</p>
</div>
<p className={`mt-1.5 text-2xl font-bold tabular-nums ${s.color}`}>{s.value}</p>
</div>
))}
</div>
{/* Filters */}
<div className="flex items-center gap-2 flex-wrap">
<SlidersHorizontal className="h-3.5 w-3.5 text-white/25 shrink-0" />
<Select
value={propertyId}
onChange={setPropertyId}
options={[
{ value: "", label: "All properties" },
...properties.map((p) => ({ value: p.id, label: p.name })),
]}
className="w-40"
/>
<Select
value={status}
onChange={setStatus}
options={[
{ value: "", label: "All statuses" },
{ value: "open", label: "Open" },
{ value: "in_progress", label: "In Progress" },
{ value: "resolved", label: "Resolved" },
{ value: "closed", label: "Closed" },
]}
className="w-36"
/>
{(propertyId || status) && (
<button
onClick={() => { setPropertyId(""); setStatus("") }}
className="text-xs text-white/35 hover:text-white/70 transition"
>
Clear
</button>
)}
<span className="ml-auto text-xs text-white/25">{filtered.length} result{filtered.length !== 1 ? "s" : ""}</span>
</div>
{!filtered.length ? (
<EmptyState
icon={Wrench}
title="No maintenance requests"
description="Create requests to track and manage property maintenance issues."
action={{ label: "New request", href: "/maintenance/new" }}
/>
) : (
<div className="space-y-2">
{filtered.map((req: any) => (
<Link
key={req.id}
href={`/maintenance/${req.id}`}
className="group flex items-start gap-4 rounded-xl border border-white/[0.06] bg-[#16161f] p-4 transition-all duration-150 hover:border-indigo-500/25 hover:bg-[#1a1a2e] hover:shadow-lg hover:shadow-indigo-500/5"
>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<p className="text-sm font-semibold text-white group-hover:text-indigo-100 transition-colors">{req.title}</p>
<PriorityBadge priority={req.priority} />
</div>
{req.description && (
<p className="mt-1 text-xs text-white/40 line-clamp-1">{req.description}</p>
)}
<div className="mt-2 flex items-center gap-2 flex-wrap text-xs text-white/30">
{req.property?.name && <span>{req.property.name}</span>}
{req.unit && <span>· Unit {req.unit.unit_number}</span>}
{req.tenant && <span>· {req.tenant.first_name} {req.tenant.last_name}</span>}
<span>· {formatDate(req.created_at)}</span>
</div>
</div>
<div className="shrink-0 mt-0.5">
<MaintenanceStatusBadge status={req.status} />
</div>
</Link>
))}
</div>
)}
</div>
)
}