nxtgauge-frontend-solid/src/components/dashboard/widgets/RequirementsWidget.tsx
2026-04-26 23:58:43 +02:00

101 lines
2.9 KiB
TypeScript

import { createResource, For, Show } from 'solid-js';
import { ClipboardList } from 'lucide-solid';
import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway';
async function apiFetch(path: string, opts?: RequestInit) {
const token =
typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
...opts,
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
...(opts?.headers ?? {}),
},
});
}
type Props = {
roleKey: RoleKey;
};
async function fetchRequirementsData(_roleKey: RoleKey) {
const res = await apiFetch('/api/customers/requirements?page=1&limit=100');
if (!res.ok) return null;
const json = await res.json();
return Array.isArray(json?.data) ? json.data : [];
}
function ReqStatRow(props: { label: string; value: number | string; color?: string }) {
return (
<div
style={{
display: 'flex',
'align-items': 'center',
'justify-content': 'space-between',
padding: '6px 0',
'border-bottom': '1px solid #F9FAFB',
}}
>
<span style={{ 'font-size': '12px', color: '#6B7280' }}>{props.label}</span>
<span
style={{
'font-size': '15px',
'font-weight': '800',
color: props.color || '#111827',
}}
>
{props.value}
</span>
</div>
);
}
export default function RequirementsWidget(props: Props) {
const [data] = createResource(() => props.roleKey, fetchRequirementsData);
const stats = () => {
const items = data() || [];
const total = items.length;
const open = items.filter(
(r: any) => String(r.status || '').toUpperCase() === 'OPEN'
).length;
const pending = items.filter((r: any) =>
String(r.status || '').toUpperCase().includes('PENDING')
).length;
const closed = items.filter(
(r: any) => String(r.status || '').toUpperCase() === 'CLOSED'
).length;
const draft = items.filter(
(r: any) => String(r.status || '').toUpperCase() === 'DRAFT'
).length;
return { total, open, pending, closed, draft };
};
return (
<DashboardWidget
title="My Requirements"
loading={data.loading}
error={data.error ? 'Failed to load' : undefined}
icon={<ClipboardList size={16} />}
>
<Show when={stats()}>
<For each={[
['Total Requirements', stats()!.total, '#374151'],
['Open', stats()!.open, '#059669'],
['In Verification', stats()!.pending, '#D97706'],
['Closed', stats()!.closed, '#6B7280'],
]}>
{([label, value, color]) => <ReqStatRow label={label} value={value} color={color} />}
</For>
</Show>
</DashboardWidget>
);
}