Ready panel can edit now

This commit is contained in:
DaKheera47 2026-01-21 13:17:09 +00:00
parent 7cc5017e56
commit 164256326f
3 changed files with 51 additions and 25 deletions

View File

@ -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<void>;
onJobMoved: (jobId: string) => void;
onEditTailoring: () => void;
onEditDescription: () => void;
}
const safeFilenamePart = (value: string | null | undefined) =>
@ -59,9 +62,8 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
job,
onJobUpdated,
onJobMoved,
onEditTailoring,
onEditDescription,
}) => {
const [mode, setMode] = useState<PanelMode>("ready");
const [isMarkingApplied, setIsMarkingApplied] = useState(false);
const [isRegenerating, setIsRegenerating] = useState(false);
const [catalog, setCatalog] = useState<ResumeProjectCatalogItem[]>([]);
@ -77,6 +79,11 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
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<ReadyPanelProps> = ({
}
}, [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<ReadyPanelProps> = ({
);
}
// Tailor mode - reuse the same TailorMode component with 'ready' variant
if (mode === "tailor") {
return (
<TailorMode
job={job}
onBack={() => setMode("ready")}
onFinalize={handleTailorFinalize}
isFinalizing={isRegenerating}
variant="ready"
/>
);
}
return (
<div className="flex flex-col h-full">
<JobHeader
@ -332,7 +369,7 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
</DropdownMenuTrigger>
<DropdownMenuContent align="center" className="w-56">
{/* Fix/Edit actions */}
<DropdownMenuItem onSelect={onEditTailoring}>
<DropdownMenuItem onSelect={() => setMode("tailor")}>
<Edit2 className="mr-2 h-4 w-4" />
Edit tailoring
</DropdownMenuItem>
@ -345,11 +382,6 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
{isRegenerating ? "Regenerating..." : "Regenerate PDF"}
</DropdownMenuItem>
<DropdownMenuItem onSelect={onEditDescription}>
<Edit2 className="mr-2 h-4 w-4" />
Edit job description
</DropdownMenuItem>
<DropdownMenuSeparator />
{/* Utility actions */}

View File

@ -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<TailorModeProps> = ({
@ -22,6 +24,7 @@ export const TailorMode: React.FC<TailorModeProps> = ({
onBack,
onFinalize,
isFinalizing,
variant = 'discovered',
}) => {
const [catalog, setCatalog] = useState<ResumeProjectCatalogItem[]>([]);
const [summary, setSummary] = useState(job.tailoredSummary || "");
@ -274,7 +277,7 @@ export const TailorMode: React.FC<TailorModeProps> = ({
<div className='space-y-2'>
{!canFinalize && (
<p className='text-[10px] text-center text-muted-foreground'>
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'}.
</p>
)}
<Button
@ -285,17 +288,19 @@ export const TailorMode: React.FC<TailorModeProps> = ({
{isFinalizing ? (
<>
<Loader2 className='mr-2 h-4 w-4 animate-spin' />
Finalizing & generating PDF...
{variant === 'ready' ? 'Regenerating PDF...' : 'Finalizing & generating PDF...'}
</>
) : (
<>
<Check className='mr-2 h-4 w-4' />
Finalize & Move to Ready
{variant === 'ready' ? 'Regenerate PDF' : 'Finalize & Move to Ready'}
</>
)}
</Button>
<p className='text-[10px] text-center text-muted-foreground/70'>
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.'}
</p>
</div>
</div>

View File

@ -243,17 +243,6 @@ export const JobDetailPanel: React.FC<JobDetailPanelProps> = ({
job={selectedJob}
onJobUpdated={onJobUpdated}
onJobMoved={handleJobMoved}
onEditTailoring={() => {
onSetActiveTab("discovered");
setTimeout(() => setDetailTab("tailoring"), 50);
}}
onEditDescription={() => {
onSetActiveTab("discovered");
setTimeout(() => {
setDetailTab("description");
setIsEditingDescription(true);
}, 50);
}}
/>
);
}