feat(ai-widget): Save to Profile button for profile_draft responses
All checks were successful
build-and-release / build (push) Successful in 1m52s

- Added confirmSaveProfile() — calls POST /api/ai/chat/confirm with
  action='save_profile', extracting the quoted improved text from the
  LLM's message automatically
- Green 'Save to Profile' button appears on profile_draft messages
  (actionType === 'profile_draft'), distinct from the ticket confirm flow
- actionLabel() extended with 'save_profile' key

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tracewebstudio Dev 2026-08-14 18:43:31 +02:00
parent 614b0ed43a
commit 106561189f

View file

@ -77,6 +77,7 @@ function actionLabel(action: string | undefined): string {
case "open_auto_apply": return "Auto Apply →";
case "open_form_extract": return "Form Assistant →";
case "create_ticket": return "Create Support Ticket";
case "save_profile": return "Save to Profile";
default: return "";
}
}
@ -278,6 +279,61 @@ export function AiChatWidget() {
}
};
/** Called when user clicks "Save to Profile" on a profile_draft message. */
const confirmSaveProfile = async (msgIdx: number, draftText: string) => {
// Extract just the quoted improved text if it's wrapped in our "Here's an improved..." message
const quotedMatch = draftText.match(/"([^"]+)"/);
const cleanDraft = quotedMatch ? quotedMatch[1] : draftText;
setMessages((prev) => prev.map((m, i) => (i === msgIdx ? { ...m, confirmed: true } : m)));
setIsLoading(true);
try {
const res = await fetch(`${API}/ai/chat/confirm`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${sessionStorage.getItem("nxtgauge_access_token") || ""}`,
},
credentials: "include",
body: JSON.stringify({
action: "save_profile",
conversation_id: conversationId() || undefined,
fields: { draft_text: cleanDraft },
}),
});
const data = await res.json().catch(() => ({}));
if (res.ok && data.success) {
setMessages((prev) => [
...prev,
{
role: "assistant",
content: data.message || "Your profile summary has been updated!",
status: "profile_saved",
confirmed: true,
},
]);
} else {
setMessages((prev) => [
...prev,
{
role: "assistant",
content: data.error || "Couldn't save the profile summary. Please try again or update it manually from your profile page.",
},
]);
}
} catch {
setMessages((prev) => [
...prev,
{
role: "assistant",
content: "Couldn't connect to save your profile. Please update it manually from your profile page.",
},
]);
} finally {
setIsLoading(false);
}
};
return (
<>
{/* Floating button */}
@ -533,6 +589,27 @@ export function AiChatWidget() {
Create Support Ticket
</button>
</Show>
{/* Save-profile button — for profile_draft messages */}
<Show when={msg.actionType === "profile_draft"}>
<button
onClick={() => confirmSaveProfile(idx(), msg.content)}
style={{
display: "inline-flex",
"align-items": "center",
padding: "5px 12px",
background: "#16A34A",
border: "none",
"border-radius": "20px",
color: "#fff",
"font-size": "11px",
"font-weight": "600",
cursor: "pointer",
}}
>
Save to Profile
</button>
</Show>
</div>
</Show>
</>