From 29b259352f34ac7a2fd83bf7935cdd8519507e1b Mon Sep 17 00:00:00 2001 From: DaKheera47 Date: Tue, 20 Jan 2026 22:40:43 +0000 Subject: [PATCH] UI intagration into header top section --- .../src/client/components/JobHeader.tsx | 58 +++++++++---------- .../src/client/components/ReadyPanel.tsx | 3 + .../discovered-panel/DecideMode.tsx | 8 ++- .../discovered-panel/DiscoveredPanel.tsx | 3 + .../src/client/pages/OrchestratorPage.tsx | 5 +- .../pages/orchestrator/JobDetailPanel.tsx | 5 ++ .../pages/orchestrator/useOrchestratorData.ts | 15 +++-- 7 files changed, 60 insertions(+), 37 deletions(-) diff --git a/orchestrator/src/client/components/JobHeader.tsx b/orchestrator/src/client/components/JobHeader.tsx index caf7f54..704d9d4 100644 --- a/orchestrator/src/client/components/JobHeader.tsx +++ b/orchestrator/src/client/components/JobHeader.tsx @@ -46,13 +46,13 @@ const ScoreMeter: React.FC<{ score: number | null }> = ({ score }) => { ); }; -interface SponsorBadgeProps { +interface SponsorPillProps { score: number | null; names: string | null; onCheck?: () => Promise; } -const SponsorBadge: React.FC = ({ score, names, onCheck }) => { +const SponsorPill: React.FC = ({ score, names, onCheck }) => { const [isChecking, setIsChecking] = useState(false); const parsedNames = useMemo(() => { @@ -78,12 +78,12 @@ const SponsorBadge: React.FC = ({ score, names, onCheck }) => if (score == null && onCheck) { return ( - + @@ -103,34 +103,30 @@ const SponsorBadge: React.FC = ({ score, names, onCheck }) => ); } - // If no score (and no callback), or error in score, show nothing if (score == null) { return null; } - const isFound = score >= 95; - const tooltipContent = isFound - ? `Confirmed Visa Sponsor (${score}% match: ${parsedNames.join(", ")})` - : `Sponsor Not Found (${score}% match${parsedNames.length > 0 ? `: ${parsedNames.join(", ")}` : ""})`; + const canSponsor = score >= 95; + const label = canSponsor ? "Can Sponsor" : "Unsure if Sponsor"; + const dotClass = canSponsor ? "bg-emerald-500" : "bg-slate-500"; + const tooltipContent = canSponsor + ? `${score}% match` + : `Closest: ${parsedNames.join(", ")} (${score}% match)`; return ( - + - - + + + {label} -

{isFound ? "Found" : "Not Found"}

-

{tooltipContent}

+ {canSponsor &&

{parsedNames.join(", ")}

} + {!canSponsor &&

Unsure if sponsor

} +

{tooltipContent}

@@ -148,13 +144,6 @@ export const JobHeader: React.FC = ({ job, className, showSponso
{job.title}
{job.employer} - {showSponsorInfo && ( - - )}
@@ -186,7 +175,16 @@ export const JobHeader: React.FC = ({ job, className, showSponso {/* Status and score: single line, subdued */}
- +
+ + {showSponsorInfo && ( + + )} +
diff --git a/orchestrator/src/client/components/ReadyPanel.tsx b/orchestrator/src/client/components/ReadyPanel.tsx index acc2ade..068d4ea 100644 --- a/orchestrator/src/client/components/ReadyPanel.tsx +++ b/orchestrator/src/client/components/ReadyPanel.tsx @@ -50,6 +50,7 @@ interface ReadyPanelProps { onJobMoved: (jobId: string) => void; onEditTailoring: () => void; onEditDescription: () => void; + showSponsorInfo?: boolean; } const safeFilenamePart = (value: string | null | undefined) => @@ -61,6 +62,7 @@ export const ReadyPanel: React.FC = ({ onJobMoved, onEditTailoring, onEditDescription, + showSponsorInfo, }) => { const [isMarkingApplied, setIsMarkingApplied] = useState(false); const [isRegenerating, setIsRegenerating] = useState(false); @@ -222,6 +224,7 @@ export const ReadyPanel: React.FC = ({ await api.checkSponsor(job.id); await onJobUpdated(); }} + showSponsorInfo={showSponsorInfo} /> {/* ───────────────────────────────────────────────────────────────────── diff --git a/orchestrator/src/client/components/discovered-panel/DecideMode.tsx b/orchestrator/src/client/components/discovered-panel/DecideMode.tsx index 4308e4e..6d7418b 100644 --- a/orchestrator/src/client/components/discovered-panel/DecideMode.tsx +++ b/orchestrator/src/client/components/discovered-panel/DecideMode.tsx @@ -15,6 +15,7 @@ interface DecideModeProps { onSkip: () => void; isSkipping: boolean; onCheckSponsor?: () => Promise; + showSponsorInfo?: boolean; } export const DecideMode: React.FC = ({ @@ -23,6 +24,7 @@ export const DecideMode: React.FC = ({ onSkip, isSkipping, onCheckSponsor, + showSponsorInfo, }) => { const [showDescription, setShowDescription] = useState(false); const jobLink = job.applicationLink || job.jobUrl; @@ -35,7 +37,11 @@ export const DecideMode: React.FC = ({ return (
- +
)} diff --git a/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx b/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx index e7a1297..563c0bc 100644 --- a/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx +++ b/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx @@ -41,6 +41,7 @@ interface JobDetailPanelProps { onSelectJobId: (jobId: string | null) => void; onJobUpdated: () => Promise; onSetActiveTab: (tab: FilterTab) => void; + showSponsorInfo?: boolean; } export const JobDetailPanel: React.FC = ({ @@ -50,6 +51,7 @@ export const JobDetailPanel: React.FC = ({ onSelectJobId, onJobUpdated, onSetActiveTab, + showSponsorInfo, }) => { const [detailTab, setDetailTab] = useState<"overview" | "tailoring" | "description">("overview"); const [isEditingDescription, setIsEditingDescription] = useState(false); @@ -233,6 +235,7 @@ export const JobDetailPanel: React.FC = ({ job={selectedJob} onJobUpdated={onJobUpdated} onJobMoved={handleJobMoved} + showSponsorInfo={showSponsorInfo} /> ); } @@ -254,6 +257,7 @@ export const JobDetailPanel: React.FC = ({ setIsEditingDescription(true); }, 50); }} + showSponsorInfo={showSponsorInfo} /> ); } @@ -275,6 +279,7 @@ export const JobDetailPanel: React.FC = ({ await api.checkSponsor(selectedJob.id); await onJobUpdated(); }} + showSponsorInfo={showSponsorInfo} />
diff --git a/orchestrator/src/client/pages/orchestrator/useOrchestratorData.ts b/orchestrator/src/client/pages/orchestrator/useOrchestratorData.ts index 2c440cb..0f6dac9 100644 --- a/orchestrator/src/client/pages/orchestrator/useOrchestratorData.ts +++ b/orchestrator/src/client/pages/orchestrator/useOrchestratorData.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; -import type { Job, JobStatus } from "../../../shared/types"; +import type { Job, JobStatus, AppSettings } from "../../../shared/types"; import * as api from "../../api"; const initialStats: Record = { @@ -16,15 +16,20 @@ const initialStats: Record = { export const useOrchestratorData = () => { const [jobs, setJobs] = useState([]); const [stats, setStats] = useState>(initialStats); + const [settings, setSettings] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isPipelineRunning, setIsPipelineRunning] = useState(false); const loadJobs = useCallback(async () => { try { setIsLoading(true); - const data = await api.getJobs(); - setJobs(data.jobs); - setStats(data.byStatus); + const [jobsData, settingsData] = await Promise.all([ + api.getJobs(), + api.getSettings(), + ]); + setJobs(jobsData.jobs); + setStats(jobsData.byStatus); + setSettings(settingsData); } catch (error) { const message = error instanceof Error ? error.message : "Failed to load jobs"; toast.error(message); @@ -54,5 +59,5 @@ export const useOrchestratorData = () => { return () => clearInterval(interval); }, [loadJobs, checkPipelineStatus]); - return { jobs, stats, isLoading, isPipelineRunning, setIsPipelineRunning, loadJobs, checkPipelineStatus }; + return { jobs, stats, settings, isLoading, isPipelineRunning, setIsPipelineRunning, loadJobs, checkPipelineStatus }; };