Skip to content

Commit 3386071

Browse files
committed
CCM-11492 Remove template action
1 parent 93b6d6d commit 3386071

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { randomUUID } from 'node:crypto';
2+
import { removeTemplateFromMessagePlan } from './actions';
3+
import { getRoutingConfig, updateRoutingConfig } from '@utils/message-plans';
4+
import {
5+
CascadeGroupName,
6+
Channel,
7+
ChannelType,
8+
RoutingConfigStatus,
9+
} from 'nhs-notify-backend-client';
10+
import { redirect } from 'next/navigation';
11+
12+
jest.mock('@utils/message-plans');
13+
jest.mock('next/navigation', () => ({
14+
redirect: jest.fn(),
15+
}));
16+
17+
const mockGetRoutingConfig = jest.mocked(getRoutingConfig);
18+
const mockUpdateRoutingConfig = jest.mocked(updateRoutingConfig);
19+
20+
const routingConfigId = randomUUID();
21+
const baseConfig = {
22+
id: routingConfigId,
23+
campaignId: 'campaign1',
24+
name: 'Test',
25+
clientId: 'client1',
26+
status: 'DRAFT' as RoutingConfigStatus,
27+
createdAt: '2025-01-01T00:00:00.000Z',
28+
updatedAt: '2025-01-01T00:00:00.000Z',
29+
cascade: [
30+
{
31+
channel: 'EMAIL' as Channel,
32+
channelType: 'primary' as ChannelType,
33+
cascadeGroups: ['standard' as CascadeGroupName],
34+
defaultTemplateId: 'template-1',
35+
},
36+
{
37+
channel: 'SMS' as Channel,
38+
channelType: 'primary' as ChannelType,
39+
cascadeGroups: ['standard' as CascadeGroupName],
40+
defaultTemplateId: 'template-2',
41+
},
42+
],
43+
cascadeGroupOverrides: [],
44+
};
45+
46+
describe('removeTemplateFromMessagePlan', () => {
47+
beforeEach(() => {
48+
jest.clearAllMocks();
49+
});
50+
51+
it('removes the template from the correct channel and updates the routing configuration', async () => {
52+
mockGetRoutingConfig.mockResolvedValue(baseConfig);
53+
54+
const formData = new FormData();
55+
formData.set('routingConfigId', routingConfigId);
56+
formData.set('channel', 'EMAIL');
57+
58+
await removeTemplateFromMessagePlan(formData);
59+
60+
expect(mockGetRoutingConfig).toHaveBeenCalledWith(routingConfigId);
61+
62+
expect(mockUpdateRoutingConfig).toHaveBeenCalledWith(
63+
routingConfigId,
64+
expect.objectContaining({
65+
cascade: [
66+
expect.objectContaining({
67+
channel: 'EMAIL',
68+
defaultTemplateId: null,
69+
}),
70+
expect.objectContaining({
71+
channel: 'SMS',
72+
defaultTemplateId: 'template-2',
73+
}),
74+
],
75+
})
76+
);
77+
});
78+
79+
it('refreshes the choose-templates page after successful removal', async () => {
80+
mockGetRoutingConfig.mockResolvedValue(baseConfig);
81+
mockUpdateRoutingConfig.mockResolvedValue(undefined);
82+
83+
const formData = new FormData();
84+
formData.set('routingConfigId', routingConfigId);
85+
formData.set('channel', 'EMAIL');
86+
87+
await removeTemplateFromMessagePlan(formData);
88+
89+
expect(redirect).toHaveBeenCalledWith(
90+
`/message-plans/choose-templates/${routingConfigId}`
91+
);
92+
});
93+
94+
it('throws an error if routing config is not found', async () => {
95+
mockGetRoutingConfig.mockResolvedValue(undefined);
96+
97+
const formData = new FormData();
98+
formData.set('routingConfigId', routingConfigId);
99+
formData.set('channel', 'EMAIL');
100+
101+
await expect(removeTemplateFromMessagePlan(formData)).rejects.toThrow(
102+
/not found/
103+
);
104+
});
105+
106+
it('throws an error if form data is missing', async () => {
107+
const formData = new FormData();
108+
109+
await expect(removeTemplateFromMessagePlan(formData)).rejects.toThrow(
110+
/Invalid form data/
111+
);
112+
});
113+
114+
it('throws an error if form data is invalid', async () => {
115+
const formData = new FormData();
116+
formData.set('routingConfigId', 'invalid-id');
117+
formData.set('channel', 'test');
118+
119+
await expect(removeTemplateFromMessagePlan(formData)).rejects.toThrow(
120+
/Invalid form data/
121+
);
122+
});
123+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use server';
2+
3+
import { z } from 'zod';
4+
import { getRoutingConfig, updateRoutingConfig } from '@utils/message-plans';
5+
import { $Channel } from 'nhs-notify-backend-client';
6+
import { redirect } from 'next/navigation';
7+
8+
export async function removeTemplateFromMessagePlan(formData: FormData) {
9+
console.log('remove template from message plan');
10+
11+
const parseResult = z
12+
.object({
13+
routingConfigId: z.uuidv4(),
14+
channel: $Channel,
15+
})
16+
.safeParse({
17+
routingConfigId: formData.get('routingConfigId'),
18+
channel: formData.get('channel'),
19+
});
20+
21+
if (!parseResult.success) {
22+
throw new Error('Invalid form data');
23+
}
24+
25+
const { routingConfigId, channel } = parseResult.data;
26+
27+
const routingConfig = await getRoutingConfig(routingConfigId);
28+
29+
if (!routingConfig)
30+
throw new Error(`Routing configuration ${routingConfigId} not found`);
31+
32+
const updatedCascade = routingConfig.cascade.map((cascadeItem) => {
33+
if (cascadeItem.channel === channel) {
34+
console.log('template ID to remove', cascadeItem.defaultTemplateId);
35+
return { ...cascadeItem, defaultTemplateId: null };
36+
} else {
37+
return cascadeItem;
38+
}
39+
});
40+
41+
const updatedConfig = { ...routingConfig, cascade: updatedCascade };
42+
43+
await updateRoutingConfig(routingConfigId, updatedConfig);
44+
45+
redirect(`/message-plans/choose-templates/${routingConfigId}`);
46+
}

0 commit comments

Comments
 (0)