Wire up dashboard tiles with live data, keep tables

- Fetch stats from /api/Dashboard/Stats endpoint
- KPI tiles show real counts and navigate on click
- Restore Priority Analysis and Invoice Analysis tables (placeholder data)
This commit is contained in:
Adam Moussa 2026-04-16 19:25:42 -04:00
parent 2477bcf5a6
commit 5aa194c7be
2 changed files with 67 additions and 39 deletions

View file

@ -25,6 +25,12 @@
align-items: center;
gap: 15px;
min-height: 100px;
cursor: pointer;
transition: filter 0.15s;
}
.kpiCard:hover {
filter: brightness(0.9);
}
.bg-success { background-color: #28a745; }

View file

@ -1,48 +1,71 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { get } from "../apiUtil";
import { API_URL } from "../constants";
import "./Dashboard.css";
const Dashboard = () => {
const navigate = useNavigate();
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
get(`${API_URL}/Dashboard/Stats`)
.then((data) => setStats(data))
.catch(() => {})
.finally(() => setLoading(false));
}, []);
const kpis = [
{ title: "Create a Work Order", icon: "✓", color: "success", desc: "Report a problem you need fixed" },
{ title: "Open Work Orders", icon: "📂", color: "primary", stat: "885" },
{ title: "Not Dispatched", icon: "⏱", color: "info", stat: "503" },
{ title: "Completed Orders", icon: "📋", color: "warning", stat: "4,088" },
];
const priorities = [
{ priority: "5", total: "665", "0-14": "83", "15-29": "79", "30-59": "62", "60+": "441" },
{ priority: "4", total: "327", "0-14": "4", "15-29": "19", "30-59": "3", "60+": "301" },
{ priority: "3", total: "295", "0-14": "69", "15-29": "64", "30-59": "42", "60+": "120" },
{ priority: "2", total: "95", "0-14": "26", "15-29": "38", "30-59": "11", "60+": "20" },
];
const invoices = [
{ name: "Draft", count: 0, amount: "0.00" },
{ name: "Challenged", count: 0, amount: "0.00" },
{ name: "Pending Approval", count: 0, amount: "0.00" },
{ name: "Approved", count: 0, amount: "0.00" },
{ name: "Paid", count: 0, amount: "0.00" },
{
title: "Create a Work Order",
icon: "fa-plus",
color: "success",
desc: "Report a problem you need fixed",
onClick: () => navigate("/workorders/new"),
},
{
title: "Open Work Orders",
icon: "fa-folder-open",
color: "primary",
stat: loading ? "..." : stats?.open ?? 0,
onClick: () => navigate("/workorders"),
},
{
title: "Not Dispatched",
icon: "fa-clock-o",
color: "info",
stat: loading ? "..." : stats?.notDispatched ?? 0,
onClick: () => navigate("/workorders"),
},
{
title: "Completed Orders",
icon: "fa-check-circle",
color: "warning",
stat: loading ? "..." : stats?.completed ?? 0,
onClick: () => navigate("/workorders"),
},
];
return (
<section className="dashboardPage">
<div className="pageTitle">Dashboard</div>
{/* KPI Cards */}
<div className="kpiContainer">
{kpis.map((kpi, idx) => (
<div key={idx} className={`kpiCard bg-${kpi.color}`}>
<div className="kpiIcon">{kpi.icon}</div>
<div key={idx} className={`kpiCard bg-${kpi.color}`} onClick={kpi.onClick}>
<div className="kpiIcon">
<i className={`fa ${kpi.icon}`}></i>
</div>
<div className="kpiContent">
<h5>{kpi.title}</h5>
{kpi.stat && <div className="kpiStat">{kpi.stat}</div>}
{kpi.stat !== undefined && <div className="kpiStat">{kpi.stat?.toLocaleString?.() ?? kpi.stat}</div>}
{kpi.desc && <p>{kpi.desc}</p>}
</div>
</div>
))}
</div>
{/* Priority Analysis */}
<div className="card mt-4">
<div className="cardHeader">
<h3>Priority Analysis</h3>
@ -61,14 +84,14 @@ const Dashboard = () => {
</tr>
</thead>
<tbody>
{priorities.map((row, idx) => (
<tr key={idx}>
<td>{row.priority}</td>
<td className="text-right">{row.total}</td>
<td className="text-right">{row["0-14"]}</td>
<td className="text-right">{row["15-29"]}</td>
<td className="text-right">{row["30-59"]}</td>
<td className="text-right">{row["60+"]}</td>
{[5, 4, 3, 2, 1].map((p) => (
<tr key={p}>
<td>{p}</td>
<td className="text-right">—</td>
<td className="text-right">—</td>
<td className="text-right">—</td>
<td className="text-right">—</td>
<td className="text-right">—</td>
</tr>
))}
</tbody>
@ -76,7 +99,6 @@ const Dashboard = () => {
</div>
</div>
{/* Invoice Analysis */}
<div className="card mt-4">
<div className="cardHeader">
<h3>Invoice Analysis</h3>
@ -91,11 +113,11 @@ const Dashboard = () => {
</tr>
</thead>
<tbody>
{invoices.map((inv, idx) => (
<tr key={idx}>
<td>{inv.name}</td>
<td className="text-right">{inv.count}</td>
<td className="text-right">${inv.amount}</td>
{["Draft", "Challenged", "Pending Approval", "Approved", "Paid"].map((s) => (
<tr key={s}>
<td>{s}</td>
<td className="text-right">0</td>
<td className="text-right">$0.00</td>
</tr>
))}
</tbody>