mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
decent homes mvp
This commit is contained in:
parent
66a43a19b8
commit
fa7636b340
2 changed files with 86 additions and 55 deletions
|
|
@ -140,8 +140,6 @@ export default async function DecentHomesPage({
|
|||
})
|
||||
);
|
||||
|
||||
console.log("summaryResults", summaryResults);
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4">
|
||||
<DecentHomesDashboard data={summaryResults} portfolioId={portfolioId} />
|
||||
|
|
|
|||
|
|
@ -17,7 +17,14 @@ import {
|
|||
TabsTrigger,
|
||||
TabsContent,
|
||||
} from "@/app/shadcn_components/ui/tabs";
|
||||
import { Wrench } from "lucide-react";
|
||||
|
||||
import {
|
||||
Wrench,
|
||||
AlertTriangle,
|
||||
Clock,
|
||||
Hourglass,
|
||||
CheckCircle,
|
||||
} from "lucide-react";
|
||||
|
||||
const DISPLAY_NAMES: Record<string, string> = {
|
||||
// Criterion A - HHSRS hazards
|
||||
|
|
@ -175,7 +182,7 @@ function StatusBadge({ status }: { status: string }) {
|
|||
// urgency badge
|
||||
function UrgencyBadge({ label }: { label: string }) {
|
||||
const colorMap: Record<string, string> = {
|
||||
Overdue: "bg-red-600",
|
||||
Overdue: "bg-red-700",
|
||||
"0–6 months": "bg-orange-500",
|
||||
"6–12 months": "bg-yellow-500",
|
||||
">12 months": "bg-green-600",
|
||||
|
|
@ -205,7 +212,7 @@ function CriterionContent({
|
|||
return (
|
||||
<Card className="h-96 flex flex-col relative overflow-hidden">
|
||||
<CardHeader>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<CardTitle className="text-brandbrown">{title}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 overflow-y-scroll pr-2 scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-gray-100">
|
||||
<ul className="space-y-2 pb-6">
|
||||
|
|
@ -235,7 +242,12 @@ function ReplacementsContent({
|
|||
const today = new Date();
|
||||
const groups: Record<
|
||||
string,
|
||||
{ sub_variable: string; expiry: Date; remaining: string }[]
|
||||
{
|
||||
sub_variable: string;
|
||||
expiry: Date;
|
||||
remaining: string;
|
||||
overdue: boolean;
|
||||
}[]
|
||||
> = {
|
||||
Overdue: [],
|
||||
"0–6 months": [],
|
||||
|
|
@ -248,46 +260,37 @@ function ReplacementsContent({
|
|||
const expiry = new Date(item.expiry_date);
|
||||
const diffMs = expiry.getTime() - today.getTime();
|
||||
const diffMonths = diffMs / (1000 * 60 * 60 * 24 * 30);
|
||||
const years = Math.floor(diffMonths / 12);
|
||||
const months = Math.floor(diffMonths % 12);
|
||||
const remaining =
|
||||
diffMs < 0
|
||||
? "Expired"
|
||||
: `${years > 0 ? `${years}y ` : ""}${months}m remaining`;
|
||||
|
||||
const years = Math.floor(Math.abs(diffMonths) / 12);
|
||||
const months = Math.floor(Math.abs(diffMonths) % 12);
|
||||
|
||||
let remaining = "";
|
||||
let overdue = false;
|
||||
if (diffMs < 0) {
|
||||
groups.Overdue.push({
|
||||
sub_variable: SUB_ITEMS_TEXT[item.sub_variable],
|
||||
expiry,
|
||||
remaining,
|
||||
});
|
||||
} else if (diffMonths <= 6) {
|
||||
groups["0–6 months"].push({
|
||||
sub_variable: SUB_ITEMS_TEXT[item.sub_variable],
|
||||
expiry,
|
||||
remaining,
|
||||
});
|
||||
} else if (diffMonths <= 12) {
|
||||
groups["6–12 months"].push({
|
||||
sub_variable: SUB_ITEMS_TEXT[item.sub_variable],
|
||||
expiry,
|
||||
remaining,
|
||||
});
|
||||
overdue = true;
|
||||
remaining = `Expired ${years > 0 ? `${years}y ` : ""}${months}m ago`;
|
||||
} else {
|
||||
groups[">12 months"].push({
|
||||
sub_variable: SUB_ITEMS_TEXT[item.sub_variable],
|
||||
expiry,
|
||||
remaining,
|
||||
});
|
||||
remaining = `${years > 0 ? `${years}y ` : ""}${months}m remaining`;
|
||||
}
|
||||
|
||||
const entry = {
|
||||
sub_variable: SUB_ITEMS_TEXT[item.sub_variable] ?? item.sub_variable,
|
||||
expiry,
|
||||
remaining,
|
||||
overdue,
|
||||
};
|
||||
|
||||
if (diffMs < 0) groups.Overdue.push(entry);
|
||||
else if (diffMonths <= 6) groups["0–6 months"].push(entry);
|
||||
else if (diffMonths <= 12) groups["6–12 months"].push(entry);
|
||||
else groups[">12 months"].push(entry);
|
||||
});
|
||||
|
||||
// sort each group by expiry date ascending (soonest first)
|
||||
Object.values(groups).forEach((comps) => {
|
||||
comps.sort((a, b) => a.expiry.getTime() - b.expiry.getTime());
|
||||
});
|
||||
// sort within each group
|
||||
Object.values(groups).forEach((comps) =>
|
||||
comps.sort((a, b) => a.expiry.getTime() - b.expiry.getTime())
|
||||
);
|
||||
|
||||
// order of groups
|
||||
const groupOrder: (keyof typeof groups)[] = [
|
||||
"Overdue",
|
||||
"0–6 months",
|
||||
|
|
@ -295,36 +298,66 @@ function ReplacementsContent({
|
|||
">12 months",
|
||||
];
|
||||
|
||||
// urgency → card highlight color + icon
|
||||
const cardStyles: Record<string, { border: string; icon: JSX.Element }> = {
|
||||
Overdue: {
|
||||
border: "border-l-4 border-red-600",
|
||||
icon: <AlertTriangle className="w-4 h-4 text-red-600" />,
|
||||
},
|
||||
"0–6 months": {
|
||||
border: "border-l-4 border-orange-500",
|
||||
icon: <Clock className="w-4 h-4 text-orange-500" />,
|
||||
},
|
||||
"6–12 months": {
|
||||
border: "border-l-4 border-yellow-500",
|
||||
icon: <Hourglass className="w-4 h-4 text-yellow-500" />,
|
||||
},
|
||||
">12 months": {
|
||||
border: "border-l-4 border-green-600",
|
||||
icon: <CheckCircle className="w-4 h-4 text-green-600" />,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="h-96 flex flex-col relative overflow-hidden">
|
||||
<Card className="h-[32rem] flex flex-col relative overflow-hidden">
|
||||
<CardHeader>
|
||||
<CardTitle>Upcoming Replacements</CardTitle>
|
||||
<CardTitle className="text-lg font-medium text-brandbrown">
|
||||
Upcoming Replacements
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 overflow-y-scroll pr-2 scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-gray-100">
|
||||
{groupOrder.map((urgency) =>
|
||||
groups[urgency].length > 0 ? (
|
||||
<div key={urgency} className="mb-4">
|
||||
<div className="flex items-center space-x-2 mb-2">
|
||||
<div key={urgency} className="mb-6">
|
||||
{/* group header */}
|
||||
<div className="flex items-center space-x-2 mb-3">
|
||||
<UrgencyBadge label={urgency} />
|
||||
<span className="text-gray-700 font-medium">
|
||||
{groups[urgency].length} items
|
||||
{groups[urgency].length}{" "}
|
||||
{groups[urgency].length > 1 ? "items" : "item"}
|
||||
</span>
|
||||
</div>
|
||||
<ul className="space-y-1 ml-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{groups[urgency].map((comp, idx) => (
|
||||
<li
|
||||
<div
|
||||
key={idx}
|
||||
className="flex justify-between border-b pb-1 last:border-0"
|
||||
className={`px-4 py-2 bg-gray-50 rounded-md border hover:bg-gray-100 transition ${cardStyles[urgency].border}`}
|
||||
>
|
||||
<span>
|
||||
{DISPLAY_NAMES[comp.sub_variable] ?? comp.sub_variable}
|
||||
</span>
|
||||
<span className="text-sm text-gray-600">
|
||||
{comp.remaining}
|
||||
</span>
|
||||
</li>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="font-medium text-gray-800 flex items-center gap-2">
|
||||
{cardStyles[urgency].icon}
|
||||
{comp.sub_variable}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-600 flex justify-between">
|
||||
<span>{comp.remaining}</span>
|
||||
<span className={comp.overdue ? "text-red-600" : ""}>
|
||||
{comp.expiry.toLocaleDateString("en-GB")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
) : null
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue