'use client'; import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import AdminLogo from '../../components/AdminLogo'; interface JobAction { id: number; action_type: string; part_type: string | null; part_id: string | null; custom_price: number; labour_fee: number; created_at: string; } interface Vehicle { id: string; make: string; model: string; capacity: number | null; yom: number | null; owner: number | null; } interface Customer { id: number; name: string; address: string; } interface ServiceRecord { id: number; created_at: string; vehicle: string; metadata: string | null; status: number; mileage: number | null; Vehicles?: Vehicle; } export default function JobsListPage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const router = useRouter(); const [jobs, setJobs] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [customers, setCustomers] = useState([]); const [selectedJob, setSelectedJob] = useState(null); const [jobActions, setJobActions] = useState([]); const [loadingActions, setLoadingActions] = useState(false); useEffect(() => { const adminLoggedIn = sessionStorage.getItem('adminLoggedIn'); if (adminLoggedIn !== 'true') { router.push('/admin'); return; } setIsAuthenticated(true); loadJobs(); loadCustomers(); }, [router]); // Close modal when clicking outside or pressing Escape useEffect(() => { const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape' && selectedJob) { setSelectedJob(null); setJobActions([]); } }; if (selectedJob) { document.addEventListener('keydown', handleEscape); } return () => { document.removeEventListener('keydown', handleEscape); }; }, [selectedJob]); const loadJobs = async () => { try { setLoading(true); const response = await fetch('/api/admin/jobs'); if (response.ok) { const data = await response.json(); setJobs(data); } else { console.error('Failed to load jobs'); } } catch (error) { console.error('Error loading jobs:', error); } finally { setLoading(false); } }; const loadCustomers = async () => { try { const response = await fetch('/api/admin/customers'); if (response.ok) { const data = await response.json(); setCustomers(data); } } catch (error) { console.error('Error loading customers:', error); } }; const getCustomerName = (ownerId: number | null | undefined) => { if (!ownerId) return 'Unknown'; const customer = customers.find(c => c.id === ownerId); return customer ? customer.name : 'Unknown'; }; const getStatusLabel = (status: number) => { switch (status) { case 0: return 'Pending'; case 1: return 'Active'; case 2: return 'Waiting for Customer Response'; case 3: return 'Waiting for Parts'; case 10: return 'Completed'; default: return 'Unknown'; } }; const getStatusColor = (status: number) => { switch (status) { case 0: return 'text-white/60'; case 1: return 'text-cyan-400'; case 2: return 'text-yellow-400'; case 3: return 'text-orange-400'; case 10: return 'text-green-400'; default: return 'text-white/60'; } }; const handleShowDetails = async (job: ServiceRecord) => { setSelectedJob(job); setLoadingActions(true); try { const response = await fetch(`/api/admin/jobs/${job.id}/actions`); if (response.ok) { const data = await response.json(); setJobActions(data); } else { console.error('Failed to load job actions'); setJobActions([]); } } catch (error) { console.error('Error loading job actions:', error); setJobActions([]); } finally { setLoadingActions(false); } }; const filteredJobs = jobs.filter(job => { if (!searchQuery.trim()) return true; const query = searchQuery.toLowerCase(); const vehicleId = job.Vehicles?.id?.toLowerCase() || ''; const vehicleMake = job.Vehicles?.make?.toLowerCase() || ''; const vehicleModel = job.Vehicles?.model?.toLowerCase() || ''; const metadata = job.metadata?.toLowerCase() || ''; const customerName = getCustomerName(job.Vehicles?.owner).toLowerCase(); const statusLabel = getStatusLabel(job.status).toLowerCase(); return ( vehicleId.includes(query) || vehicleMake.includes(query) || vehicleModel.includes(query) || metadata.includes(query) || customerName.includes(query) || statusLabel.includes(query) ); }); if (!isAuthenticated) { return null; } return ( <>
{/* Animated background elements */}

All Jobs

← Back to Dashboard
{/* Search Bar */}
setSearchQuery(e.target.value)} placeholder="Search by vehicle number, make, model, customer, status, or metadata..." className="w-full rounded-lg border-2 border-white/20 bg-black/50 px-4 py-3 font-mono text-white placeholder-white/40 focus:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/30 neon-border transition-all" />
{/* Jobs List */} {loading ? (

Loading Jobs...

) : filteredJobs.length === 0 ? (

{searchQuery ? 'No jobs found matching your search' : 'No jobs found'}

) : (
{filteredJobs.map((job) => (
Vehicle
{job.Vehicles?.id || 'N/A'}
{job.Vehicles?.make || 'N/A'} {job.Vehicles?.model || ''} {job.Vehicles?.capacity && ` (${job.Vehicles.capacity}cc)`}
Customer
{getCustomerName(job.Vehicles?.owner)}
Status
{getStatusLabel(job.status)}
Created At
{new Date(job.created_at).toLocaleString()}
{job.mileage !== null && (
Mileage
{job.mileage.toLocaleString()} km
)}
{job.metadata && (
Notes
{job.metadata}
)}
Service Record ID: {job.id}
))}
)} {!loading && filteredJobs.length > 0 && (

Showing {filteredJobs.length} of {jobs.length} jobs

)}
{/* Job Details Modal */} {selectedJob && (
{ setSelectedJob(null); setJobActions([]); }} >
e.stopPropagation()} >

Job Details

{/* Service Record Details */}
Service Record ID
#{selectedJob.id}
Status
{getStatusLabel(selectedJob.status)}
Vehicle Number
{selectedJob.Vehicles?.id || 'N/A'}
{selectedJob.Vehicles?.make || 'N/A'} {selectedJob.Vehicles?.model || ''} {selectedJob.Vehicles?.capacity && ` (${selectedJob.Vehicles.capacity}cc)`}
Customer
{getCustomerName(selectedJob.Vehicles?.owner)}
{selectedJob.Vehicles?.owner && (
Customer ID: {selectedJob.Vehicles.owner}
)}
Created At
{new Date(selectedJob.created_at).toLocaleString()}
{selectedJob.mileage !== null && (
Mileage
{selectedJob.mileage.toLocaleString()} km
)}
{selectedJob.metadata && (
Metadata / Notes
{selectedJob.metadata}
)}
{/* Job Actions List */}

Job Actions

{jobActions.length} action{jobActions.length !== 1 ? 's' : ''}
{loadingActions ? (

Loading Actions...

) : jobActions.length === 0 ? (

No job actions found

) : (
{jobActions.map((action, index) => { const partsPrice = action.custom_price > 0 && action.custom_price !== -1 ? action.custom_price : 0; const rowTotal = action.labour_fee + partsPrice; return ( ); })}
Action Type Part Type Part ID Labour Fee Parts Price Total
{action.action_type} {action.part_type || '-'} {action.part_id || '-'} රු.{action.labour_fee || 0} {partsPrice > 0 ? `රු.${partsPrice}` : '-'} රු.{rowTotal}
Total Cost: රු.{jobActions.reduce((sum, action) => { const partsPrice = action.custom_price > 0 && action.custom_price !== -1 ? action.custom_price : 0; return sum + action.labour_fee + partsPrice; }, 0)}
Labour: රු.{jobActions.reduce((sum, action) => sum + action.labour_fee, 0)} Parts: රු.{jobActions.reduce((sum, action) => { const partsPrice = action.custom_price > 0 && action.custom_price !== -1 ? action.custom_price : 0; return sum + partsPrice; }, 0)}
)}
)} ); }