feat(analyzer): phase 7 — share-via-email

sendAnalysisShareEmail() reuses the existing nodemailer SMTP transport
(same path as magic-link/invitation mail). Share route persists the
audit row first, then attempts send; on failure returns
{share, emailSent:false, emailError} at HTTP 200 so the audit log
stays intact. Modal surfaces send failures as a warning toast.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
lorentz 2026-04-29 11:03:11 -04:00
parent 8f8b5ab7be
commit ed3b363d02
4 changed files with 231 additions and 9 deletions

View file

@ -39,11 +39,22 @@ export function ShareModal({ analysisId }: ShareModalProps) {
note: note.trim() || undefined,
}),
});
const data = (await res.json().catch(() => ({}))) as {
error?: string;
message?: string;
emailSent?: boolean;
emailError?: string | null;
};
if (!res.ok) {
const data = (await res.json().catch(() => ({}))) as { error?: string; message?: string };
throw new Error(data.message ?? data.error ?? `Request failed: ${res.status}`);
}
toast.success(`Shared with ${recipientEmail}`);
if (data.emailSent === false) {
toast.warning(
`Share recorded for ${recipientEmail}, but email failed: ${data.emailError ?? 'unknown error'}`
);
} else {
toast.success(`Shared with ${recipientEmail}`);
}
setOpen(false);
setRecipientEmail('');
setNote('');