Implement S03 follow-up draft context loop
This commit is contained in:
@@ -19,7 +19,7 @@ import {
|
||||
} from "@mui/material";
|
||||
|
||||
import { api, getApiErrorMessage } from "../api";
|
||||
import { ApplicationPackageResponse, CandidateFit, FocusPlanResponse, InterviewPrepResponse, JobApplication, ReadinessResponse } from "../types";
|
||||
import { ApplicationPackageResponse, CandidateFit, FocusPlanResponse, FollowUpDraft, InterviewPrepResponse, JobApplication, ReadinessResponse } from "../types";
|
||||
import { useToast } from "../toast";
|
||||
import { useDialogActions } from "../dialogs";
|
||||
|
||||
@@ -38,16 +38,8 @@ type AttachmentItem = {
|
||||
useForAi: boolean;
|
||||
};
|
||||
|
||||
type FollowUpDraft = {
|
||||
subject: string;
|
||||
body: string;
|
||||
reason: string;
|
||||
suggestedSendOn: string;
|
||||
};
|
||||
|
||||
type GenerationMode = "default" | "concise" | "ats" | "achievement" | "interview";
|
||||
type CoverLetterStyle = "balanced" | "concise" | "formal" | "bold";
|
||||
type PackageDraftKind = "tailoredCv" | "coverLetter" | "applicationAnswer" | "recruiterMessage";
|
||||
|
||||
type PackageWorkspaceState = {
|
||||
coverLetter: string;
|
||||
@@ -612,9 +604,20 @@ export default function JobDetailsDialog({ open, jobId, onClose, initialTab = 0,
|
||||
<Box>
|
||||
{loadingDraft ? <Box sx={{ py: 4, display: "flex", justifyContent: "center" }}><CircularProgress size={28} /></Box> : followUpDraft ? (
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2 }}>
|
||||
<Box><Typography variant="overline">{t("jobDetailsReason")}</Typography><Typography>{followUpDraft.reason}</Typography></Box>
|
||||
<Box><Typography variant="overline">{t("jobDetailsSuggestedSendDate")}</Typography><Typography>{new Date(followUpDraft.suggestedSendOn).toLocaleDateString()}</Typography></Box>
|
||||
<Box sx={{ p: 1.5, borderRadius: 3, border: "1px solid", borderColor: "divider", backgroundColor: "background.default" }}>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 1, flexWrap: "wrap", mb: 1 }}>
|
||||
<Typography variant="overline">Follow-up context</Typography>
|
||||
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
|
||||
{followUpDraft.threadSubject ? <Chip size="small" variant="outlined" label={`Thread: ${followUpDraft.threadSubject}`} /> : null}
|
||||
{followUpDraft.lastCorrespondenceAt ? <Chip size="small" variant="outlined" label={`Last activity: ${new Date(followUpDraft.lastCorrespondenceAt).toLocaleDateString()}`} /> : null}
|
||||
</Box>
|
||||
</Box>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap", mb: 1.5 }}>{followUpDraft.contextSummary}</Typography>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2 }}>
|
||||
<Box><Typography variant="overline">Why now</Typography><Typography>{followUpDraft.reason}</Typography></Box>
|
||||
<Box><Typography variant="overline">Last sender</Typography><Typography>{followUpDraft.lastCorrespondenceFrom ?? "No imported sender yet"}</Typography></Box>
|
||||
</Box>
|
||||
{followUpDraft.contextSignals?.length ? <Box sx={{ mt: 1.5 }}><ListCard title="Draft grounding" items={followUpDraft.contextSignals} /></Box> : null}
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||
<FormControl size="small" sx={{ minWidth: 240 }}>
|
||||
@@ -629,9 +632,9 @@ export default function JobDetailsDialog({ open, jobId, onClose, initialTab = 0,
|
||||
</FormControl>
|
||||
<Button variant="outlined" onClick={() => setDraftReloadToken((value) => value + 1)}>{t("jobDetailsRegenerateDraft")}</Button>
|
||||
</Box>
|
||||
<TextField label={t("jobDetailsRecipient")} value={draftRecipient} onChange={(e) => setDraftRecipient(e.target.value)} helperText={t("jobDetailsRecipientHelp")} />
|
||||
<TextField label={t("jobDetailsRecipient")} value={draftRecipient} onChange={(e) => setDraftRecipient(e.target.value)} helperText={`${t("jobDetailsRecipientHelp")} Manual send only — nothing is dispatched until you press send.`} />
|
||||
<TextField label={t("jobDetailsSubject")} value={draftSubject} onChange={(e) => setDraftSubject(e.target.value)} />
|
||||
<TextField label={t("jobDetailsDraft")} multiline minRows={8} value={draftBody} onChange={(e) => setDraftBody(e.target.value)} />
|
||||
<TextField label={t("jobDetailsDraft")} multiline minRows={8} value={draftBody} onChange={(e) => setDraftBody(e.target.value)} helperText="You can edit this before sending. Sending stays manual and logs the sent note back to correspondence." />
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap" }}>
|
||||
<Button variant="outlined" onClick={() => navigator.clipboard.writeText(`${draftSubject}\n\n${draftBody}`)}>{t("jobDetailsCopyDraft")}</Button>
|
||||
<Button variant="contained" disabled={sendingDraft || !draftSubject.trim() || !draftBody.trim()} onClick={async () => {
|
||||
|
||||
Reference in New Issue
Block a user