- Job wizard now calls real API: create job → upload source → launch - Dashboard and monitoring pages use live data instead of mock data - Monitoring page polls every 3s while job is active - Backend enriches job responses with client_name, created_by_name, source_line_count from eager-loaded relationships - Frontend response mappers handle backend→frontend type differences (lowercase enum values, field name mapping, computed progress/stage) - Source file parser accepts column aliases (Line type, Context notes) with case-insensitive matching for real-world Excel files - Clients list endpoint accessible to all authenticated users - Fixed uploadSource to use PUT, uploadSupplementary per-file - Removed all hardcoded mock data from useJobs hook Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 lines
1.5 KiB
TypeScript
61 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useCallback } from "react";
|
|
import type { Job, JobFilters, PaginatedResponse } from "@/lib/types";
|
|
import { getJobs, getJob } from "@/lib/api";
|
|
|
|
export function useJobs(filters?: JobFilters) {
|
|
const [jobs, setJobs] = useState<Job[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [total, setTotal] = useState(0);
|
|
|
|
const fetchJobs = useCallback(async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const response: PaginatedResponse<Job> = await getJobs(filters);
|
|
setJobs(response.items);
|
|
setTotal(response.total);
|
|
} catch {
|
|
setError("Failed to load jobs");
|
|
setJobs([]);
|
|
setTotal(0);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [filters]);
|
|
|
|
useEffect(() => {
|
|
fetchJobs();
|
|
}, [fetchJobs]);
|
|
|
|
return { jobs, loading, error, total, refetch: fetchJobs };
|
|
}
|
|
|
|
export function useJob(jobId: string) {
|
|
const [job, setJob] = useState<Job | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchJob = useCallback(async () => {
|
|
if (!jobId) return;
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const data = await getJob(jobId);
|
|
setJob(data);
|
|
} catch {
|
|
setError("Failed to load job");
|
|
setJob(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [jobId]);
|
|
|
|
useEffect(() => {
|
|
fetchJob();
|
|
}, [fetchJob]);
|
|
|
|
return { job, loading, error, refetch: fetchJob };
|
|
}
|