import Link from 'next/link'; import { useEffect, useState } from 'react'; import Layout from '../components/Layout'; import { api } from '../lib/api'; import { useRequireAuth } from '../lib/auth-context'; interface JobRow { id: string; ticketNumber: string; title: string; address: string | null; status: string; source: string; createdAt: string; assignedTo: { id: string; name: string } | null; _count: { points: number }; } const STATUSES = ['', 'OPEN', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED']; const STATUS_COLORS: Record = { OPEN: '#1976d2', IN_PROGRESS: '#f57c00', COMPLETED: '#388e3c', CANCELLED: '#9e9e9e', }; export default function JobsPage() { const { user, activeOrg, loading } = useRequireAuth(); const [jobs, setJobs] = useState([]); const [total, setTotal] = useState(0); const [status, setStatus] = useState(''); const [q, setQ] = useState(''); const [error, setError] = useState(null); useEffect(() => { if (!activeOrg) { return; } const params = new URLSearchParams(); if (status) params.set('status', status); if (q) params.set('q', q); api .get<{ jobs: JobRow[]; total: number }>(`/api/orgs/${activeOrg.org.id}/jobs?${params}`) .then((res) => { setJobs(res.jobs); setTotal(res.total); setError(null); }) .catch((err) => setError(err.message)); }, [activeOrg, status, q]); if (loading || !user) { return null; } return (

Jobs

{total} total
setQ(e.target.value)} />
{error &&

{error}

} {jobs.map((job) => ( ))} {jobs.length === 0 && !error && ( )}
Ticket Title Address Status Source Assignee Points
{job.ticketNumber} {job.title} {job.address ?? '—'} {job.status} {job.source} {job.assignedTo?.name ?? '—'} {job._count.points}
No jobs yet. Create one, or let a device post points to auto-create its ticket.
); }