Skip to content

Commit ae4460d

Browse files
bhansell1alexnuttall
authored andcommitted
CCM-8962: add submit and delete routes
1 parent fb362e6 commit ae4460d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+8738
-3481
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ reports
6161
tests/screenshots/*
6262
plugin-cache/
6363

64+
# terraform
6465
*.terraform*
6566
terraform.tfstate
6667
terraform.tfstate.backup
@@ -84,3 +85,6 @@ tests/test-team/playwright-report/
8485
tests/test-team/blob-report/
8586
tests/test-team/playwright/.cache/
8687
lambdas/backend-api/src/email/email-template.json
88+
89+
# vscode
90+
.vscode/settings.local.json

.vscode/settings.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
{
22
"markdownlint.config": {
33
"MD013": false,
4-
"MD024": { "siblings_only": true },
4+
"MD024": {
5+
"siblings_only": true
6+
},
57
"MD033": false
68
},
79
"editor.codeActionsOnSave": {
810
"source.fixAll.eslint": "explicit"
911
},
10-
"eslint.codeActionsOnSave.mode": "problems"
11-
}
12+
"eslint.codeActionsOnSave.mode": "problems",
13+
"jestrunner.jestPath": "/Users/benjamin.hansell/projects/nhs-notify-web-template-management/node_modules/jest/bin/jest.js",
14+
"jestrunner.projectPath": "/Users/benjamin.hansell/projects/nhs-notify-web-template-management/frontend"
15+
}

frontend/src/__tests__/components/forms/DeleteTemplate/server-action.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
deleteTemplateNoAction,
55
} from '@forms/DeleteTemplate/server-action';
66
import { NHSAppTemplate } from 'nhs-notify-web-template-management-utils';
7-
import { saveTemplate } from '@utils/form-actions';
7+
import { setTemplateToDeleted } from '@utils/form-actions';
88

99
jest.mock('next/navigation');
1010
jest.mock('@utils/form-actions');
@@ -27,7 +27,7 @@ test('redirects', async () => {
2727

2828
test('calls form action and redirects', async () => {
2929
const mockRedirect = jest.mocked(redirect);
30-
const mockSaveTemplate = jest.mocked(saveTemplate);
30+
const mockSetTemplateToDeleted = jest.mocked(setTemplateToDeleted);
3131

3232
const mockTemplate: NHSAppTemplate = {
3333
id: 'template-id',
@@ -41,10 +41,7 @@ test('calls form action and redirects', async () => {
4141

4242
await deleteTemplateYesAction(mockTemplate);
4343

44-
expect(mockSaveTemplate).toHaveBeenCalledWith({
45-
...mockTemplate,
46-
templateStatus: 'DELETED',
47-
});
44+
expect(mockSetTemplateToDeleted).toHaveBeenCalledWith('template-id');
4845

4946
expect(mockRedirect).toHaveBeenCalledWith(
5047
'/manage-templates',

frontend/src/__tests__/components/forms/SubmitTemplate/server-action.test.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { submitTemplate } from '@forms/SubmitTemplate/server-action';
55
import { getMockFormData } from '@testhelpers';
66
import { redirect } from 'next/navigation';
7-
import { getTemplate, saveTemplate } from '@utils/form-actions';
7+
import { getTemplate, setTemplateToSubmitted } from '@utils/form-actions';
88
import { TemplateDto } from 'nhs-notify-backend-client';
99

1010
jest.mock('next/navigation');
@@ -13,7 +13,7 @@ jest.mock('@utils/amplify-utils');
1313

1414
const redirectMock = jest.mocked(redirect);
1515
const getTemplateMock = jest.mocked(getTemplate);
16-
const saveTemplateMock = jest.mocked(saveTemplate);
16+
const setTemplateToSubmittedMock = jest.mocked(setTemplateToSubmitted);
1717

1818
const mockNhsAppTemplate = {
1919
templateType: 'NHS_APP',
@@ -63,7 +63,7 @@ describe('submitTemplate', () => {
6363
it('should handle error when failing to save template', async () => {
6464
getTemplateMock.mockResolvedValueOnce(mockNhsAppTemplate);
6565

66-
saveTemplateMock.mockImplementationOnce(() => {
66+
setTemplateToSubmittedMock.mockImplementationOnce(() => {
6767
throw new Error('failed to save template');
6868
});
6969

@@ -85,17 +85,8 @@ describe('submitTemplate', () => {
8585

8686
await submitTemplate('submit-route', formData);
8787

88-
expect(saveTemplateMock).toHaveBeenCalledWith(
89-
expect.objectContaining({
90-
createdAt: '2025-01-13T10:19:25.579Z',
91-
id: '1',
92-
message: 'body',
93-
name: 'name',
94-
templateStatus: 'SUBMITTED',
95-
templateType: 'NHS_APP',
96-
updatedAt: '2025-01-13T10:19:25.579Z',
97-
})
98-
);
88+
expect(setTemplateToSubmittedMock).toHaveBeenCalledWith('1');
89+
9990
expect(redirectMock).toHaveBeenCalledWith('/submit-route/1', 'push');
10091
});
10192
});

frontend/src/__tests__/utils/form-actions.test.ts

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
getTemplate,
1313
getTemplates,
1414
createLetterTemplate,
15+
setTemplateToDeleted,
16+
setTemplateToSubmitted,
1517
} from '@utils/form-actions';
1618
import { getAccessTokenServer } from '@utils/amplify-utils';
1719
import { TemplateDto } from 'nhs-notify-backend-client';
@@ -283,7 +285,7 @@ describe('form-actions', () => {
283285
});
284286

285287
const updateTemplateInput: NHSAppTemplate = {
286-
id: 'pickle',
288+
id: 'id',
287289
templateType: 'NHS_APP',
288290
templateStatus: 'NOT_YET_SUBMITTED',
289291
name: 'name',
@@ -312,7 +314,7 @@ describe('form-actions', () => {
312314
});
313315

314316
const updateTemplateInput: NHSAppTemplate = {
315-
id: 'pickle',
317+
id: 'id',
316318
templateType: 'NHS_APP',
317319
templateStatus: 'NOT_YET_SUBMITTED',
318320
name: 'name',
@@ -337,7 +339,7 @@ describe('form-actions', () => {
337339
authIdTokenServerMock.mockResolvedValueOnce(undefined);
338340

339341
const updateTemplateInput: NHSAppTemplate = {
340-
id: 'pickle',
342+
id: 'id',
341343
templateType: 'NHS_APP',
342344
templateStatus: 'NOT_YET_SUBMITTED',
343345
name: 'name',
@@ -483,4 +485,102 @@ describe('form-actions', () => {
483485

484486
expect(actualOrder).toEqual(expectedOrder);
485487
});
488+
489+
describe('setTemplateToSubmitted', () => {
490+
test('submitTemplate successfully', async () => {
491+
const responseData = {
492+
id: 'id',
493+
templateType: 'NHS_APP',
494+
templateStatus: 'NOT_YET_SUBMITTED',
495+
name: 'name',
496+
message: 'message',
497+
createdAt: '2025-01-13T10:19:25.579Z',
498+
updatedAt: '2025-01-13T10:19:25.579Z',
499+
} satisfies TemplateDto;
500+
501+
mockedTemplateClient.submitTemplate.mockResolvedValueOnce({
502+
data: responseData,
503+
});
504+
505+
const response = await setTemplateToSubmitted('id');
506+
507+
expect(mockedTemplateClient.submitTemplate).toHaveBeenCalledWith(
508+
'id',
509+
'token'
510+
);
511+
512+
expect(response).toEqual(responseData);
513+
});
514+
515+
test('submitTemplate - should thrown error when saving unexpectedly fails', async () => {
516+
mockedTemplateClient.submitTemplate.mockResolvedValueOnce({
517+
error: {
518+
code: 400,
519+
message: 'Bad request',
520+
},
521+
});
522+
523+
await expect(setTemplateToSubmitted('id')).rejects.toThrow(
524+
'Failed to save template data'
525+
);
526+
527+
expect(mockedTemplateClient.submitTemplate).toHaveBeenCalledWith(
528+
'id',
529+
'token'
530+
);
531+
});
532+
533+
test('submitTemplate - should thrown error when no token', async () => {
534+
authIdTokenServerMock.mockReset();
535+
authIdTokenServerMock.mockResolvedValueOnce(undefined);
536+
537+
await expect(setTemplateToSubmitted('id')).rejects.toThrow(
538+
'Failed to get access token'
539+
);
540+
});
541+
});
542+
543+
describe('setTemplateToDeleted', () => {
544+
test('deleteTemplate successfully', async () => {
545+
mockedTemplateClient.deleteTemplate.mockResolvedValueOnce({
546+
data: undefined,
547+
});
548+
549+
const response = await setTemplateToDeleted('id');
550+
551+
expect(mockedTemplateClient.deleteTemplate).toHaveBeenCalledWith(
552+
'id',
553+
'token'
554+
);
555+
556+
expect(response).toEqual(undefined);
557+
});
558+
559+
test('deleteTemplate - should thrown error when saving unexpectedly fails', async () => {
560+
mockedTemplateClient.deleteTemplate.mockResolvedValueOnce({
561+
error: {
562+
code: 400,
563+
message: 'Bad request',
564+
},
565+
});
566+
567+
await expect(setTemplateToDeleted('id')).rejects.toThrow(
568+
'Failed to save template data'
569+
);
570+
571+
expect(mockedTemplateClient.deleteTemplate).toHaveBeenCalledWith(
572+
'id',
573+
'token'
574+
);
575+
});
576+
577+
test('deleteTemplate - should thrown error when no token', async () => {
578+
authIdTokenServerMock.mockReset();
579+
authIdTokenServerMock.mockResolvedValueOnce(undefined);
580+
581+
await expect(setTemplateToDeleted('id')).rejects.toThrow(
582+
'Failed to get access token'
583+
);
584+
});
585+
});
486586
});
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { redirect, RedirectType } from 'next/navigation';
2-
import { saveTemplate } from '@utils/form-actions';
2+
import { setTemplateToDeleted } from '@utils/form-actions';
33
import { TemplateDto } from 'nhs-notify-backend-client';
44

55
export const deleteTemplateNoAction = async () => {
@@ -9,10 +9,7 @@ export const deleteTemplateNoAction = async () => {
99
export const deleteTemplateYesAction = async (
1010
template: TemplateDto
1111
): Promise<never> => {
12-
await saveTemplate({
13-
...template,
14-
templateStatus: 'DELETED',
15-
});
12+
await setTemplateToDeleted(template.id);
1613

1714
redirect('/manage-templates', RedirectType.push);
1815
};

frontend/src/components/forms/SubmitTemplate/server-action.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use server';
22

33
import { redirect, RedirectType } from 'next/navigation';
4-
import { getTemplate, saveTemplate } from '@utils/form-actions';
4+
import { getTemplate, setTemplateToSubmitted } from '@utils/form-actions';
55
import { z } from 'zod';
66
import { validateTemplate } from 'nhs-notify-web-template-management-utils';
77
import { logger } from 'nhs-notify-web-template-management-utils/logger';
@@ -26,10 +26,7 @@ export async function submitTemplate(route: string, formData: FormData) {
2626
}
2727

2828
try {
29-
await saveTemplate({
30-
...validatedTemplate,
31-
templateStatus: 'SUBMITTED',
32-
});
29+
await setTemplateToSubmitted(templateId);
3330
} catch (error) {
3431
logger.error('Failed to submit template', {
3532
error,

frontend/src/utils/form-actions.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,43 @@ export async function saveTemplate(
7878
return data;
7979
}
8080

81+
export async function setTemplateToSubmitted(
82+
templateId: string
83+
): Promise<TemplateDto> {
84+
const token = await getAccessTokenServer();
85+
86+
if (!token) {
87+
throw new Error('Failed to get access token');
88+
}
89+
90+
const { data, error } = await templateClient.submitTemplate(
91+
templateId,
92+
token
93+
);
94+
95+
if (error) {
96+
logger.error('Failed to save template', { error });
97+
throw new Error('Failed to save template data');
98+
}
99+
100+
return data;
101+
}
102+
103+
export async function setTemplateToDeleted(templateId: string): Promise<void> {
104+
const token = await getAccessTokenServer();
105+
106+
if (!token) {
107+
throw new Error('Failed to get access token');
108+
}
109+
110+
const { error } = await templateClient.deleteTemplate(templateId, token);
111+
112+
if (error) {
113+
logger.error('Failed to save template', { error });
114+
throw new Error('Failed to save template data');
115+
}
116+
}
117+
81118
export async function getTemplate(
82119
templateId: string
83120
): Promise<TemplateDto | undefined> {

infrastructure/terraform/modules/backend-api/iam_role_api_gateway_execution_role.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5252
module.create_template_lambda.function_arn,
5353
module.create_letter_template_lambda.function_arn,
5454
module.update_template_lambda.function_arn,
55+
module.submit_template_lambda.function_arn,
56+
module.delete_template_lambda.function_arn,
5557
module.get_template_lambda.function_arn,
5658
module.list_template_lambda.function_arn
5759
]

infrastructure/terraform/modules/backend-api/locals.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ locals {
1010
CREATE_LAMBDA_ARN = module.create_template_lambda.function_arn
1111
CREATE_LETTER_LAMBDA_ARN = module.create_letter_template_lambda.function_arn
1212
UPDATE_LAMBDA_ARN = module.update_template_lambda.function_arn
13+
SUBMIT_LAMBDA_ARN = module.submit_template_lambda.function_arn
14+
DELETE_LAMBDA_ARN = module.delete_template_lambda.function_arn
1315
GET_LAMBDA_ARN = module.get_template_lambda.function_arn
1416
LIST_LAMBDA_ARN = module.list_template_lambda.function_arn
1517
})
@@ -19,6 +21,8 @@ locals {
1921
create_letter_template = "src/templates/create-letter.ts"
2022
get_template = "src/templates/get.ts"
2123
update_template = "src/templates/update.ts"
24+
submit_template = "src/templates/submit.ts"
25+
delete_template = "src/templates/delete.ts"
2226
list_template = "src/templates/list.ts"
2327
template_client = "src/index.ts"
2428
}

0 commit comments

Comments
 (0)