nxtgauge-frontend-solid/src/components/dashboard/ProfessionalResponsesPage.tsx

107 lines
4.4 KiB
TypeScript

import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, CARD } from '~/components/DashboardShell';
import { ROLE_PREFIXES, type RoleKey } from './RoleDashboardShared';
const API = '/api/gateway';
type Props = { roleKey: RoleKey };
type LeadRequestItem = {
id: string;
status?: string;
requirement_id?: string;
requested_at?: string;
expires_at?: string;
decision_at?: string;
};
async function apiFetch(path: string, opts?: RequestInit) {
return fetch(`${API}${path}`, {
...opts,
credentials: 'include',
headers: { 'Content-Type': 'application/json', ...(opts?.headers ?? {}) },
});
}
export default function ProfessionalResponsesPage(props: Props) {
const [rows, setRows] = createSignal<LeadRequestItem[]>([]);
const [loading, setLoading] = createSignal(true);
const [err, setErr] = createSignal('');
const prefix = () => ROLE_PREFIXES[props.roleKey];
const loadRows = async () => {
setLoading(true);
setErr('');
try {
const res = await apiFetch(`/api/${prefix()}/leads/requests/me?page=1&limit=100`);
const data = await res.json().catch(() => ({}));
if (!res.ok) {
setErr(data.error || data.message || 'Failed to load my responses.');
setRows([]);
return;
}
setRows(Array.isArray(data?.data) ? data.data : []);
} catch {
setErr('Network error while loading my responses.');
setRows([]);
} finally {
setLoading(false);
}
};
onMount(loadRows);
return (
<div style={{ display: 'grid', gap: '14px', 'max-width': '980px' }}>
<div style={CARD}>
<p style={{ margin: '0', 'font-size': '22px', 'font-weight': '800', color: '#0D0D2A' }}>My Responses</p>
<p style={{ margin: '4px 0 0', 'font-size': '13px', color: '#6B7280' }}>
Track your lead requests and current response status.
</p>
</div>
<Show when={err()}>
<div style={{ ...CARD, border: '1px solid #FECACA', background: '#FEF2F2', padding: '12px 14px', color: '#B91C1C', 'font-size': '13px', 'font-weight': '600' }}>{err()}</div>
</Show>
<div style={CARD}>
<div style={{ display: 'flex', 'justify-content': 'space-between', 'align-items': 'center', 'margin-bottom': '10px' }}>
<p style={{ margin: '0', 'font-size': '16px', 'font-weight': '700', color: '#111827' }}>Requested Leads</p>
<button type="button" onClick={loadRows} style={BTN_GHOST}>Refresh</button>
</div>
<Show when={loading()}>
<p style={{ margin: '0', color: '#9CA3AF', 'font-size': '13px' }}>Loading my responses...</p>
</Show>
<Show when={!loading() && rows().length === 0}>
<p style={{ margin: '0', color: '#6B7280', 'font-size': '13px' }}>No lead requests yet.</p>
</Show>
<Show when={!loading() && rows().length > 0}>
<div style={{ display: 'grid', gap: '10px' }}>
<For each={rows()}>
{(row) => (
<div style={{ border: '1px solid #E5E7EB', 'border-radius': '12px', padding: '12px', background: '#FCFCFD' }}>
<div style={{ display: 'flex', 'justify-content': 'space-between', gap: '10px', 'flex-wrap': 'wrap' }}>
<div>
<p style={{ margin: '0', 'font-size': '14px', 'font-weight': '800', color: '#111827' }}>Lead Request #{row.id.slice(0, 8)}</p>
<p style={{ margin: '4px 0 0', 'font-size': '12px', color: '#6B7280' }}>
Requirement: {row.requirement_id?.slice(0, 8) || '—'} {row.requested_at ? `${new Date(row.requested_at).toLocaleString('en-IN')}` : ''}
</p>
</div>
<span style={{ display: 'inline-flex', height: '24px', 'align-items': 'center', padding: '0 10px', 'border-radius': '999px', background: '#EEF2FF', color: '#3730A3', 'font-size': '11px', 'font-weight': '700' }}>
{String(row.status || 'REQUESTED').replace(/_/g, ' ')}
</span>
</div>
<p style={{ margin: '8px 0 0', 'font-size': '12px', color: '#6B7280' }}>
Expires: {row.expires_at ? new Date(row.expires_at).toLocaleString('en-IN') : '—'} {row.decision_at ? `• Decision: ${new Date(row.decision_at).toLocaleString('en-IN')}` : ''}
</p>
</div>
)}
</For>
</div>
</Show>
</div>
</div>
);
}