diff --git a/orchestrator/src/client/components/ReadyPanel.tsx b/orchestrator/src/client/components/ReadyPanel.tsx index acc2ade..580cb63 100644 --- a/orchestrator/src/client/components/ReadyPanel.tsx +++ b/orchestrator/src/client/components/ReadyPanel.tsx @@ -3,6 +3,8 @@ * * Designed for a single, fast, repeatable workflow: verify → download → apply → mark applied. * The PDF is the primary artifact, represented abstractly through an Application Kit summary. + * + * Now includes inline tailoring mode for editing and regenerating PDFs without switching tabs. */ import React, { useCallback, useEffect, useMemo, useState } from "react"; @@ -42,14 +44,15 @@ import { import { cn, copyTextToClipboard, formatJobForWebhook } from "@/lib/utils"; import * as api from "../api"; import { FitAssessment, JobHeader, TailoredSummary } from "."; +import { TailorMode } from "./discovered-panel/TailorMode"; import type { Job, ResumeProjectCatalogItem } from "../../shared/types"; +type PanelMode = "ready" | "tailor"; + interface ReadyPanelProps { job: Job | null; onJobUpdated: () => void | Promise; onJobMoved: (jobId: string) => void; - onEditTailoring: () => void; - onEditDescription: () => void; } const safeFilenamePart = (value: string | null | undefined) => @@ -59,9 +62,8 @@ export const ReadyPanel: React.FC = ({ job, onJobUpdated, onJobMoved, - onEditTailoring, - onEditDescription, }) => { + const [mode, setMode] = useState("ready"); const [isMarkingApplied, setIsMarkingApplied] = useState(false); const [isRegenerating, setIsRegenerating] = useState(false); const [catalog, setCatalog] = useState([]); @@ -77,6 +79,11 @@ export const ReadyPanel: React.FC = ({ api.getProfileProjects().then(setCatalog).catch(console.error); }, []); + // Reset mode when job changes + useEffect(() => { + setMode("ready"); + }, [job?.id]); + // Compute derived values const pdfHref = job ? `/pdfs/resume_${job.id}.pdf?v=${encodeURIComponent(job.updatedAt)}` @@ -198,6 +205,23 @@ export const ReadyPanel: React.FC = ({ } }, [job]); + // Handler for regenerating PDF after tailoring edits + const handleTailorFinalize = useCallback(async () => { + if (!job) return; + try { + setIsRegenerating(true); + await api.generateJobPdf(job.id); + toast.success("PDF regenerated"); + setMode("ready"); + await onJobUpdated(); + } catch (error) { + const message = error instanceof Error ? error.message : "Failed to regenerate PDF"; + toast.error(message); + } finally { + setIsRegenerating(false); + } + }, [job, onJobUpdated]); + // Empty state if (!job) { return ( @@ -213,6 +237,19 @@ export const ReadyPanel: React.FC = ({ ); } + // Tailor mode - reuse the same TailorMode component with 'ready' variant + if (mode === "tailor") { + return ( + setMode("ready")} + onFinalize={handleTailorFinalize} + isFinalizing={isRegenerating} + variant="ready" + /> + ); + } + return (
= ({ {/* Fix/Edit actions */} - + setMode("tailor")}> Edit tailoring @@ -345,11 +382,6 @@ export const ReadyPanel: React.FC = ({ {isRegenerating ? "Regenerating..." : "Regenerate PDF"} - - - Edit job description - - {/* Utility actions */} diff --git a/orchestrator/src/client/components/discovered-panel/TailorMode.tsx b/orchestrator/src/client/components/discovered-panel/TailorMode.tsx index 0af6b53..e25e07e 100644 --- a/orchestrator/src/client/components/discovered-panel/TailorMode.tsx +++ b/orchestrator/src/client/components/discovered-panel/TailorMode.tsx @@ -15,6 +15,8 @@ interface TailorModeProps { onBack: () => void; onFinalize: () => void; isFinalizing: boolean; + /** Variant controls the finalize button text. Default is 'discovered'. */ + variant?: 'discovered' | 'ready'; } export const TailorMode: React.FC = ({ @@ -22,6 +24,7 @@ export const TailorMode: React.FC = ({ onBack, onFinalize, isFinalizing, + variant = 'discovered', }) => { const [catalog, setCatalog] = useState([]); const [summary, setSummary] = useState(job.tailoredSummary || ""); @@ -274,7 +277,7 @@ export const TailorMode: React.FC = ({
{!canFinalize && (

- Add a summary and select at least one project to finalize. + Add a summary and select at least one project to {variant === 'ready' ? 'regenerate' : 'finalize'}.

)}

- This will generate your tailored PDF and move the job to Ready. + {variant === 'ready' + ? 'This will save your changes and regenerate the tailored PDF.' + : 'This will generate your tailored PDF and move the job to Ready.'}

diff --git a/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx b/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx index e7a1297..44ea8cd 100644 --- a/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx +++ b/orchestrator/src/client/pages/orchestrator/JobDetailPanel.tsx @@ -243,17 +243,6 @@ export const JobDetailPanel: React.FC = ({ job={selectedJob} onJobUpdated={onJobUpdated} onJobMoved={handleJobMoved} - onEditTailoring={() => { - onSetActiveTab("discovered"); - setTimeout(() => setDetailTab("tailoring"), 50); - }} - onEditDescription={() => { - onSetActiveTab("discovered"); - setTimeout(() => { - setDetailTab("description"); - setIsEditingDescription(true); - }, 50); - }} /> ); }