Add outreach candidate editing controls

This commit is contained in:
Jamie Brunton committed 2026-08-14 09:12:54 +01:00
1 parent c75e71f26e
commit 79c508be2b
19 files changed
+434 -12

No files matched your search

+28
View File
@@ -116,6 +116,8 @@ describe('dashboard foundation', () => {
it('shows the live outreach stages and the potential posts being burned down', async () => {
installSuccessfulApi();
const user = userEvent.setup();
let editedMessage: string | null = null;
let removedCandidate: string | null = null;
server.use(
http.get('/api/login/status', () => HttpResponse.json({ ready: true, loggedIn: true, status: 'authenticated' })),
http.get('/api/chats/sync', () => HttpResponse.json({
@@ -148,6 +150,15 @@ describe('dashboard foundation', () => {
note: null, owner: null,
}],
})),
http.patch('/api/outreach/:postId/message', async ({ params, request }) => {
const body = await request.json() as { message: string };
editedMessage = body.message;
return HttpResponse.json({ success: true, postId: params.postId, message: body.message });
}),
http.delete('/api/outreach/:postId', ({ params }) => {
removedCandidate = String(params.postId);
return HttpResponse.json({ success: true, postId: params.postId });
}),
);
renderDashboard('/outreach');
@@ -170,6 +181,23 @@ describe('dashboard foundation', () => {
expect(sourceImage).toHaveClass('is-blurred');
await user.click(within(preparation).getByRole('button', { name: 'Reveal source image: [25F] A potential post' }));
expect(sourceImage).not.toHaveClass('is-blurred');
const candidateList = screen.getByRole('list', { name: 'Active outreach candidates' });
await user.click(within(candidateList).getByRole('button', { name: 'Edit message' }));
const editDialog = screen.getByRole('dialog', { name: 'Edit message for u/alice' });
const editor = within(editDialog).getByRole('textbox', { name: 'Message' });
await user.clear(editor);
await user.type(editor, 'A carefully revised opener');
await user.click(within(editDialog).getByRole('button', { name: 'Save message' }));
await waitFor(() => expect(editedMessage).toBe('A carefully revised opener'));
expect(await screen.findByText('Message for u/alice updated.')).toBeInTheDocument();
await user.click(within(candidateList).getByRole('button', { name: 'Remove' }));
const deleteDialog = screen.getByRole('dialog', { name: 'Remove u/alice from the funnel?' });
expect(deleteDialog).toHaveTextContent('retained in the audit history');
await user.click(within(deleteDialog).getByRole('button', { name: 'Remove candidate' }));
await waitFor(() => expect(removedCandidate).toBe('candidate-1'));
expect(await screen.findByText('Removed u/alice from the funnel.')).toBeInTheDocument();
});
it('requires confirmation before clearing unsent outreach and preserves in-flight sends', async () => {