import type { Job, JobStatus } from "@shared/types.js"; import { ArrowUpRight, Calendar, DollarSign, Loader2, MapPin, Search, } from "lucide-react"; import type React from "react"; import { useMemo, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn, formatDate, sourceLabel } from "@/lib/utils"; import { useSettings } from "../hooks/useSettings"; import { defaultStatusToken, statusTokens, } from "../pages/orchestrator/constants"; interface JobHeaderProps { job: Job; className?: string; onCheckSponsor?: () => Promise; } const StatusPill: React.FC<{ status: JobStatus }> = ({ status }) => { const tokens = statusTokens[status] ?? defaultStatusToken; return ( {tokens.label} ); }; const ScoreMeter: React.FC<{ score: number | null }> = ({ score }) => { if (score == null) { return -; } return (
{score}
); }; interface SponsorPillProps { score: number | null; names: string | null; onCheck?: () => Promise; } const SponsorPill: React.FC = ({ score, names, onCheck }) => { const [isChecking, setIsChecking] = useState(false); const parsedNames = useMemo(() => { if (!names) return []; try { return JSON.parse(names) as string[]; } catch { return []; } }, [names]); const handleCheck = async () => { if (!onCheck) return; setIsChecking(true); try { await onCheck(); } finally { setIsChecking(false); } }; // Show "Check" button if no score and callback provided if (score == null && onCheck) { return (

Check if employer is a visa sponsor

); } if (score == null) { return null; } const getStatus = (s: number) => { if (s >= 95) return { label: "Confirmed Sponsor", dot: "bg-emerald-500", color: "text-emerald-400", }; if (s >= 80) return { label: "Potential Sponsor", dot: "bg-amber-500", color: "text-amber-400", }; return { label: "Sponsor Not Found", dot: "bg-slate-500", color: "text-slate-400", }; }; const status = getStatus(score); const tooltipContent = `${score}% match`; return ( {status.label} {parsedNames.length > 0 && (

Matched {parsedNames.join(", ")}

)}

{tooltipContent}

); }; export const JobHeader: React.FC = ({ job, className, onCheckSponsor, }) => { const { showSponsorInfo } = useSettings(); const { pathname } = useLocation(); const isJobPage = pathname.startsWith("/job/"); const deadline = formatDate(job.deadline); return (
{/* Detail header: lighter weight than list items */}
{job.title}
{job.employer}
{sourceLabel[job.source]} {job.isRemote === true && ( Remote )} {!isJobPage && ( )}
{/* Tertiary metadata - subdued */}
{job.location && ( {job.location} )} {deadline && ( {deadline} )} {job.salary && ( {job.salary} )}
{/* Status and score: single line, subdued */}
{showSponsorInfo && ( )}
); };