import { useRouter } from 'next/router'; import { useCallback, useEffect, useState } from 'react'; import Layout from '../../components/Layout'; import JobMap from '../../components/map/JobMap'; import type { MapPoint } from '../../components/map/types'; import { api } from '../../lib/api'; import { useRequireAuth } from '../../lib/auth-context'; import { useJobStream } from '../../lib/use-job-stream'; interface JobDetail { id: string; ticketNumber: string; title: string; description: string | null; address: string | null; status: string; source: string; dueAt: string | null; createdAt: string; assignedTo: { id: string; name: string; email: string } | null; _count: { points: number }; } const STATUSES = ['OPEN', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED']; export default function JobDetailPage() { const { user, activeOrg, loading } = useRequireAuth(); const router = useRouter(); const jobId = typeof router.query.jobId === 'string' ? router.query.jobId : null; const orgId = activeOrg?.org.id ?? null; const [job, setJob] = useState(null); const [points, setPoints] = useState([]); const [live, setLive] = useState(0); const [error, setError] = useState(null); useEffect(() => { if (!orgId || !jobId) { return; } api .get(`/api/orgs/${orgId}/jobs/${jobId}`) .then(setJob) .catch((err) => setError(err.message)); api .get<{ points: MapPoint[] }>(`/api/orgs/${orgId}/jobs/${jobId}/points`) .then((res) => setPoints(res.points)) .catch((err) => setError(err.message)); }, [orgId, jobId]); const onLivePoints = useCallback((incoming: MapPoint[]) => { setPoints((prev) => { const seen = new Set(prev.map((p) => p.id)); const fresh = incoming.filter((p) => !seen.has(p.id)); return fresh.length > 0 ? [...prev, ...fresh] : prev; }); setLive((n) => n + incoming.length); }, []); useJobStream(jobId, onLivePoints); const updateStatus = async (status: string) => { if (!orgId || !jobId) { return; } try { setJob(await api.patch(`/api/orgs/${orgId}/jobs/${jobId}`, { status })); } catch (err: any) { setError(err.message); } }; if (loading || !user) { return null; } return ( {error &&

{error}

} {job && ( <>

{job.ticketNumber}

{job.title}

{job.address && <>{job.address} · } source {job.source} · created {new Date(job.createdAt).toLocaleString()} {job.assignedTo && <> · assigned to {job.assignedTo.name}} {job.dueAt && <> · locate by {new Date(job.dueAt).toLocaleString()}}

{job.description &&

{job.description}

}
{points.length} points 0 ? '#388e3c' : '#999' }}> ● live{live > 0 ? ` (+${live} this session)` : ''}
)}
); }