import { For, Show, createMemo, createSignal, onMount } from 'solid-js'; import AdminShell from '~/components/AdminShell'; import type { CrudRecord } from '~/lib/admin/types'; const API = '/api/gateway'; type JobRecord = CrudRecord & { title: string; company?: string; location?: string; rate?: string; status: 'ACTIVE' | 'DRAFT' | 'PENDING_APPROVAL' | 'CLOSED' | 'EXPIRED'; postedDate?: string; }; const FALLBACK_JOBS: JobRecord[] = [ { id: 'j1', name: 'Senior UI/UX Designer', title: 'Senior UI/UX Designer', company: 'Creative Designs', location: 'Remote', rate: '₹800–₹1200/hr', status: 'ACTIVE', postedDate: '2026-03-25', updatedAt: '2026-03-27' }, { id: 'j2', name: 'Full Stack Developer', title: 'Full Stack Developer', company: 'Tech Solutions Inc', location: 'Mumbai', rate: '₹1000–₹1500/hr', status: 'PENDING_APPROVAL', postedDate: '2026-03-24', updatedAt: '2026-03-27' }, { id: 'j3', name: 'Marketing Specialist', title: 'Marketing Specialist', company: 'Global Brands', location: 'Delhi', rate: '₹500–₹700/hr', status: 'DRAFT', postedDate: '2026-03-26', updatedAt: '2026-03-27' }, ]; function StatusBadge(props: { status: string }) { const getColors = () => { switch (props.status) { case 'ACTIVE': return { border: '#B7E4C7', bg: '#DEF7E8', text: '#0B8A4A', dot: '#0B8A4A' }; case 'PENDING_APPROVAL': return { border: '#F6D78F', bg: '#FFF3D6', text: '#B7791F', dot: '#B7791F' }; case 'DRAFT': return { border: '#D1D5DB', bg: '#F3F4F6', text: '#4B5563', dot: '#9CA3AF' }; case 'CLOSED': return { border: '#FECACA', bg: '#FEF2F2', text: '#DC2626', dot: '#DC2626' }; case 'EXPIRED': return { border: '#FECACA', bg: '#FEF2F2', text: '#DC2626', dot: '#DC2626' }; default: return { border: '#D1D5DB', bg: '#F3F4F6', text: '#4B5563', dot: '#9CA3AF' }; } }; const colors = getColors(); const label = props.status.split('_').map(w => w.charAt(0) + w.slice(1).toLowerCase()).join(' '); return ( {label} ); } export default function JobsManagementPage() { const [view, setView] = createSignal<'list' | 'detail'>('list'); const [listTab, setListTab] = createSignal<'all' | 'active' | 'pending'>('all'); const [search, setSearch] = createSignal(''); const [rows, setRows] = createSignal([]); const [selectedJob, setSelectedJob] = createSignal(null); const [openMenuId, setOpenMenuId] = createSignal(null); const load = async () => { try { const res = await fetch(`${API}/api/jobs?limit=100`); if (!res.ok) throw new Error(); const data = await res.json(); const list = Array.isArray(data) ? data : (data.jobs || []); if (list.length === 0) setRows(FALLBACK_JOBS); else setRows(list.map(j => ({ id: j.id, name: j.title || '—', title: j.title || '—', company: j.company_name || j.client_name || '—', location: j.location || '—', rate: j.hourly_rate_min ? `₹${j.hourly_rate_min}–₹${j.hourly_rate_max ?? j.hourly_rate_min}/hr` : '—', status: (j.status || 'ACTIVE').toUpperCase(), postedDate: j.created_at ? new Date(j.created_at).toLocaleDateString() : '—', updatedAt: j.updated_at || '' } as JobRecord))); } catch { setRows(FALLBACK_JOBS); } }; onMount(() => void load()); const filteredRows = createMemo(() => { let list = rows(); if (listTab() === 'active') list = list.filter(r => r.status === 'ACTIVE'); if (listTab() === 'pending') list = list.filter(r => r.status === 'PENDING_APPROVAL'); const q = search().toLowerCase(); if (q) list = list.filter(r => r.title.toLowerCase().includes(q) || r.company?.toLowerCase().includes(q)); return list; }); const openDetail = (row: JobRecord) => { setSelectedJob(row); setView('detail'); setOpenMenuId(null); }; return (

Jobs Management

Review and manage live job postings from companies and clients

{([ { key: 'all', label: 'All Jobs', action: () => setListTab('all') }, { key: 'active', label: 'Active', action: () => setListTab('active') }, { key: 'pending', label: 'Pending Approval', action: () => setListTab('pending') }, ] as const).map((tab) => ( ))}
setSearch(e.currentTarget.value)} placeholder="Search jobs..." style="height:34px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:13px;color:#111827;outline:none" />
{['Job Title', 'Company', 'Rate', 'Location', 'Status', 'Actions'].map(h => ( ))} {(row) => ( )}
{h}
{row.title} {row.company || '—'} {row.rate || '—'} {row.location || '—'}

{selectedJob()!.title}

{selectedJob()!.company} • Posted {selectedJob()!.postedDate}

Full job description, applicant list, and status history will be displayed here.

); }