feat(ai-widget): Copy Cover Letter button + draft_content plumbing
All checks were successful
build-and-release / build (push) Successful in 1m46s
All checks were successful
build-and-release / build (push) Successful in 1m46s
- ChatMessage now carries draftContent?: string (from API draft_content field)
- ChatResponse interface extended with draft_content?: string
- sendMessage populates draftContent on assistant messages
- confirmSaveProfile uses draftContent directly (no more regex parsing)
- 'Save to Profile' button guards on msg.draftContent being truthy
- New blue 'Copy Cover Letter' button for cover_letter_draft messages:
copies msg.draftContent to clipboard, marks message confirmed,
appends a confirmation assistant message
- 'Open Cover Letter Tool →' nav link still shows alongside the Copy button
via the existing navUrl('open_cover_letter') path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
106561189f
commit
ff2dde1900
1 changed files with 46 additions and 7 deletions
|
|
@ -9,10 +9,12 @@ interface ChatMessage {
|
||||||
intent?: string;
|
intent?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
suggestedAction?: string;
|
suggestedAction?: string;
|
||||||
/** Semantic category: ticket_created | ticket_pending | kb_results | usage_info | navigation */
|
/** Semantic category: ticket_created | ticket_pending | kb_results | usage_info | navigation | profile_draft | cover_letter_draft */
|
||||||
actionType?: string;
|
actionType?: string;
|
||||||
/** Original user text — stored so ticket confirm has a description to send */
|
/** Original user text — stored so ticket confirm has a description to send */
|
||||||
userQuery?: string;
|
userQuery?: string;
|
||||||
|
/** Raw generated content (profile draft, cover letter body) for save/copy actions */
|
||||||
|
draftContent?: string;
|
||||||
/** True once the user has clicked the confirm/action button on this message */
|
/** True once the user has clicked the confirm/action button on this message */
|
||||||
confirmed?: boolean;
|
confirmed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
@ -29,6 +31,8 @@ interface ChatResponse {
|
||||||
status?: string;
|
status?: string;
|
||||||
suggested_action?: string;
|
suggested_action?: string;
|
||||||
action_type?: string;
|
action_type?: string;
|
||||||
|
/** Raw generated text (profile draft, cover letter body) for copy/save actions */
|
||||||
|
draft_content?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusLabel(status?: string): string | null {
|
function statusLabel(status?: string): string | null {
|
||||||
|
|
@ -195,6 +199,7 @@ export function AiChatWidget() {
|
||||||
status: data.status,
|
status: data.status,
|
||||||
suggestedAction: data.suggested_action,
|
suggestedAction: data.suggested_action,
|
||||||
actionType: data.action_type,
|
actionType: data.action_type,
|
||||||
|
draftContent: data.draft_content,
|
||||||
userQuery: text,
|
userQuery: text,
|
||||||
confirmed: false,
|
confirmed: false,
|
||||||
};
|
};
|
||||||
|
|
@ -280,10 +285,8 @@ export function AiChatWidget() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Called when user clicks "Save to Profile" on a profile_draft message. */
|
/** Called when user clicks "Save to Profile" on a profile_draft message. */
|
||||||
const confirmSaveProfile = async (msgIdx: number, draftText: string) => {
|
const confirmSaveProfile = async (msgIdx: number, draftContent: string) => {
|
||||||
// Extract just the quoted improved text if it's wrapped in our "Here's an improved..." message
|
const cleanDraft = draftContent;
|
||||||
const quotedMatch = draftText.match(/"([^"]+)"/);
|
|
||||||
const cleanDraft = quotedMatch ? quotedMatch[1] : draftText;
|
|
||||||
|
|
||||||
setMessages((prev) => prev.map((m, i) => (i === msgIdx ? { ...m, confirmed: true } : m)));
|
setMessages((prev) => prev.map((m, i) => (i === msgIdx ? { ...m, confirmed: true } : m)));
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
@ -591,9 +594,9 @@ export function AiChatWidget() {
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
{/* Save-profile button — for profile_draft messages */}
|
{/* Save-profile button — for profile_draft messages */}
|
||||||
<Show when={msg.actionType === "profile_draft"}>
|
<Show when={msg.actionType === "profile_draft" && msg.draftContent}>
|
||||||
<button
|
<button
|
||||||
onClick={() => confirmSaveProfile(idx(), msg.content)}
|
onClick={() => confirmSaveProfile(idx(), msg.draftContent!)}
|
||||||
style={{
|
style={{
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
"align-items": "center",
|
"align-items": "center",
|
||||||
|
|
@ -610,6 +613,42 @@ export function AiChatWidget() {
|
||||||
Save to Profile
|
Save to Profile
|
||||||
</button>
|
</button>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
{/* Copy button — for cover_letter_draft messages */}
|
||||||
|
<Show when={msg.actionType === "cover_letter_draft" && msg.draftContent}>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(msg.draftContent!).then(() => {
|
||||||
|
// Mark confirmed so the buttons disappear after copy
|
||||||
|
setMessages((prev) =>
|
||||||
|
prev.map((m, i) => (i === idx() ? { ...m, confirmed: true } : m))
|
||||||
|
);
|
||||||
|
setMessages((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
role: "assistant" as const,
|
||||||
|
content: "Cover letter copied to clipboard! Paste it into your application and tailor it to the specific role.",
|
||||||
|
confirmed: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
display: "inline-flex",
|
||||||
|
"align-items": "center",
|
||||||
|
padding: "5px 12px",
|
||||||
|
background: "#2563EB",
|
||||||
|
border: "none",
|
||||||
|
"border-radius": "20px",
|
||||||
|
color: "#fff",
|
||||||
|
"font-size": "11px",
|
||||||
|
"font-weight": "600",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Copy Cover Letter
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue