shoc-frontend-new/src/app/v/[token]/dashboard.tsx
2026-08-10 13:16:26 -03:00

100 lines
3.5 KiB
TypeScript

import { useMemo, useState } from "react";
import { useNavigate } from "react-router";
import { useQuery } from "@tanstack/react-query";
import { useVendorPortal } from "@/app/v/_components/vendor-portal-context";
import { Text } from "@/components/ui/text";
import { vendorPortalApi } from "@/domain/vendor-portal/api/vendor-portal-api";
import {
formatVendorPortalDateTime,
vendorPortalStatusClass,
} from "@/domain/vendor-portal/lib/status-helpers";
import {
VENDOR_PORTAL_DISPATCH_FILTERS,
applyVendorPortalDispatchFilter,
getVendorPortalDispatchFilter,
type VendorPortalDispatchFilterKey,
} from "@/domain/vendor-portal/lib/dispatch-filters";
import { queryKeys } from "@/infra/query-key/query-key";
export default function VendorPortalDashboardPage() {
const { token } = useVendorPortal();
const navigate = useNavigate();
const [filter, setFilter] = useState<VendorPortalDispatchFilterKey>("open");
const {
data: dispatches = [],
isLoading,
error,
} = useQuery({
queryKey: queryKeys.vendorPortal.dispatches(token),
queryFn: () => vendorPortalApi.listDispatches(token),
enabled: Boolean(token),
});
const activeFilter = getVendorPortalDispatchFilter(filter);
const filtered = useMemo(
() => applyVendorPortalDispatchFilter(dispatches, activeFilter),
[dispatches, activeFilter],
);
return (
<>
<div className="vp-card">
<Text variant="title">Your Work</Text>
<div className="vp-muted" style={{ marginBottom: 12 }}>
Active dispatches and work orders assigned to your company.
</div>
<div className="vp-actions" style={{ marginTop: 0 }}>
{VENDOR_PORTAL_DISPATCH_FILTERS.map((item) => (
<button
key={item.key}
type="button"
className={`vp-btn ${filter === item.key ? "vp-btn-primary" : "vp-btn-ghost"}`}
onClick={() => setFilter(item.key)}
>
{item.label}{" "}
<span style={{ opacity: 0.7, fontWeight: 400 }}>
({dispatches.filter(item.match).length})
</span>
</button>
))}
</div>
</div>
{isLoading && <div className="vp-card vp-muted">Loading dispatches…</div>}
<Text variant="error" when={Boolean(error)} className="vp-error">
{error?.message}
</Text>
{!isLoading && !error && filtered.length === 0 && (
<div className="vp-card vp-empty">No dispatches in this view.</div>
)}
<div className="vp-dispatch-list">
{filtered.map((dispatch) => (
<div
key={dispatch.id}
className="vp-dispatch-card"
onClick={() => navigate(`../dispatch/${dispatch.id}`)}
>
<div>
<div className="vp-dispatch-title">
{dispatch.dispatchNumber} — {dispatch.workOrderTitle || "(untitled)"}
</div>
<div className="vp-dispatch-meta">
WO#{dispatch.internalWONumber}
{dispatch.locationName ? ` · ${dispatch.locationName}` : ""}
{dispatch.locationCity ? `, ${dispatch.locationCity}` : ""}
{dispatch.locationState ? `, ${dispatch.locationState}` : ""}
{dispatch.scheduledDate
? ` · Scheduled ${formatVendorPortalDateTime(dispatch.scheduledDate)}`
: ""}
</div>
</div>
<span className={vendorPortalStatusClass(dispatch.status)}>{dispatch.status}</span>
</div>
))}
</div>
</>
);
}