diff --git a/.snyk b/.snyk index ea261fbb..9eb79de1 100644 --- a/.snyk +++ b/.snyk @@ -44,4 +44,10 @@ ignore: expires: 2024-07-16T00:00:00.000Z created: 2024-04-16T11:0522.224Z -patch: {} \ No newline at end of file + SNYK-JS-BRACES-6838727: + - '*': + reason: No upgrade or patch available yet + expires: 2024-08-13T00:00:00.000Z + created: 2024-05-13T11:0522.224Z + +patch: {} diff --git a/acceptance-test/test-config.js b/acceptance-test/test-config.js index d8eed6f5..03e9e351 100644 --- a/acceptance-test/test-config.js +++ b/acceptance-test/test-config.js @@ -22,6 +22,8 @@ module.exports = { HOW_WERE_THEY_TREATED: '#how-they-were-treated', WHY_THEY_STAYED: '#why-they-stayed', WHY_DID_THEY_LEAVE: '#how-why-did-they-leave-the-situation', + WHEN_LAST_CONTACT_LAST_WEEK: '#when-last-contact-last-week', + DETAILS_LAST_CONTACT: '#details-last-contact', FIRST_CHANCE_TO_REPORT_NO: '#is-this-the-first-chance-to-report-no', WHY_REPORT_NOW: '#why-report-now', WHY_ARE_YOU_MAKING_REFERRAL: '#why-are-you-making-the-referral', diff --git a/acceptance-test/user-pathways/happy-path/happy-path.test.js b/acceptance-test/user-pathways/happy-path/happy-path.test.js index aab44f4c..1c7fb635 100644 --- a/acceptance-test/user-pathways/happy-path/happy-path.test.js +++ b/acceptance-test/user-pathways/happy-path/happy-path.test.js @@ -11,6 +11,7 @@ const { START_REPORT, CONTINUE_BUTTON, DOWNLOAD_REPORT, + DETAILS_LAST_CONTACT, REFERENCE_INPUT, ORGANISATION_INPUT, EMAIL_INPUT, @@ -43,6 +44,7 @@ const { CURRENT_PV_LOCATION_UK_CITY, CURRENT_PV_LOCATION_UK_REGION, WHO_EXPLOITED_PV, + WHEN_LAST_CONTACT_LAST_WEEK, ANY_OTHER_PVS_NO_OPTION, PV_HAS_CRIME_REFERENCE_NUMBER_NO_OPTION, REFER_CASE_TO_NRM_YES_OPTION, @@ -211,6 +213,10 @@ describe.only('User path(s)', () => { await clickSelector(page, CONTINUE_BUTTON); await focusThenType(page, WHY_DID_THEY_LEAVE, 'Test input of why they left'); await clickSelector(page, CONTINUE_BUTTON); + await clickSelector(page, WHEN_LAST_CONTACT_LAST_WEEK); + await clickSelector(page, CONTINUE_BUTTON); + await focusThenType(page, DETAILS_LAST_CONTACT, 'Test input of details last contact'); + await clickSelector(page, CONTINUE_BUTTON); await clickSelector(page, FIRST_CHANCE_TO_REPORT_NO); await clickSelector(page, CONTINUE_BUTTON); await focusThenType(page, WHY_REPORT_NOW, 'Test input of why reporting now'); diff --git a/apps/nrm/behaviours/format-answers.js b/apps/nrm/behaviours/format-answers.js index 49200ca9..88d444f8 100644 --- a/apps/nrm/behaviours/format-answers.js +++ b/apps/nrm/behaviours/format-answers.js @@ -118,6 +118,12 @@ const formatAnswers = req => { }); } + if (req.sessionModel.get('when-last-contact')) { + data = Object.assign({}, data, { + formattedWhenLastContact: capitaliseText(removeDashesFromText(req.sessionModel.get('when-last-contact')), true) + }); + } + if (req.sessionModel.get('is-this-the-first-chance-to-report')) { data = Object.assign({}, data, { formattedIsThisTheFirstChanceToReport: removeDashesFromText(capitaliseText( diff --git a/apps/nrm/fields/index.js b/apps/nrm/fields/index.js index 229be08b..3cc813b8 100644 --- a/apps/nrm/fields/index.js +++ b/apps/nrm/fields/index.js @@ -278,6 +278,32 @@ module.exports = { } ] }, + 'when-last-contact': { + mixin: 'radio-group', + validate: ['required'], + legend: { + className: 'visuallyhidden' + }, + options: [ + 'last-week', + 'last-month', + 'last-3-months', + 'last-6-months', + 'year-ago', + 'Not-sure' + ] + }, + 'details-last-contact': { + mixin: 'textarea', + validate: ['notUrl', { type: 'maxlength', arguments: 15000 }], + className: 'govuk-textarea', + attributes: [ + { + attribute: 'rows', + value: 14 + } + ] + }, 'is-this-the-first-chance-to-report': { mixin: 'radio-group', validate: ['required'], diff --git a/apps/nrm/index.js b/apps/nrm/index.js index 435d7334..8e3e6d18 100644 --- a/apps/nrm/index.js +++ b/apps/nrm/index.js @@ -164,7 +164,25 @@ module.exports = { saveFormSession ], fields: ['how-why-did-they-leave-the-situation'], - next: '/is-this-the-first-chance-to-report' + next: '/when-last-contact' + }, + '/when-last-contact': { + behaviours: [ + saveFormSession + ], + fields: ['when-last-contact'], + forks: [{ + target: '/is-this-the-first-chance-to-report', + condition: req=> req.sessionModel.get('when-last-contact') === 'Not-sure' + }], + next: '/details-last-contact', + }, + '/details-last-contact': { + behaviours: [ + saveFormSession + ], + fields: ['details-last-contact'], + next: '/is-this-the-first-chance-to-report', }, '/is-this-the-first-chance-to-report': { behaviours: [ diff --git a/apps/nrm/models/submission.js b/apps/nrm/models/submission.js index 52166b4f..873cd580 100644 --- a/apps/nrm/models/submission.js +++ b/apps/nrm/models/submission.js @@ -202,6 +202,8 @@ module.exports = data => { response.ExploitationTreatment = data['how-they-were-treated']; response.ExploitationWhyTheyStayed = data['why-they-stayed']; response.ExploitationReasonTheyLeft = data['how-why-did-they-leave-the-situation']; + response.PVExploitersLastContact = data['when-last-contact']; + response.DetailsLastContact = data['details-last-contact']; const firstChangeToReport = { yes: 'Yes', diff --git a/apps/nrm/translations/src/en/fields.json b/apps/nrm/translations/src/en/fields.json index fd9e0073..e9901afd 100644 --- a/apps/nrm/translations/src/en/fields.json +++ b/apps/nrm/translations/src/en/fields.json @@ -134,6 +134,34 @@ "label": "How and why they left", "hint": "Ask if it was their decision to leave and if anyone helped them. " }, + "when-last-contact":{ + "legend": "when victim and exploiters last in contact", + "hint": "This includes in person conversations, phone calls, instant messages, emails, writing, or communicating through another person", + "options": { + "last-week": { + "label": "Within the last week" + }, + "last-month": { + "label": "Within the last month" + }, + "last-3-months": { + "label": "Within the last 3 months" + }, + "last-6-months": { + "label": "Within the last 6 months" + }, + "year-ago": { + "label": "Over a year ago" + }, + "Not-sure": { + "label": "Not sure" + } + } + }, + "details-last-contact": { + "label": "Details of last contact", + "hint": "You can email any files as evidence to us after you have submitted the report" + }, "is-this-the-first-chance-to-report": { "legend": "Is this the first chance they have had to report this?", "options": { diff --git a/apps/nrm/translations/src/en/pages.json b/apps/nrm/translations/src/en/pages.json index 4a38bc84..9fa3e2a7 100644 --- a/apps/nrm/translations/src/en/pages.json +++ b/apps/nrm/translations/src/en/pages.json @@ -51,6 +51,16 @@ "how-why-did-they-leave-the-situation": { "header": "How and why did they leave the situation?" }, + "when-last-contact": { + "header": "When were the potential victim and exploiters last in contact?" + }, + "details-last-contact": { + "header" : "Last contact between the potential victim and their exploiters", + "paragraph-1" : "To assess the risk that the potential victim may be exploited or trafficked again, we need to know about any communication between them and their exploiters.", + "paragraph-2" : "You can provide information about how they communicated, what was said and who was involved.", + "paragraph-3": "Include details about any threats the exploiters have made. If applicable, describe any steps the potential victim has taken to prevent contact with their exploiters.", + "second-header": "Details of the last contact (optional)" + }, "is-this-the-first-chance-to-report": { "header": "Is this the first chance they have had to report this?" }, @@ -262,6 +272,12 @@ "how-why-did-they-leave-the-situation": { "label": "How and why they left the situation" }, + "when-last-contact": { + "label": "Victim and exploiters last in contact?" + }, + "details-last-contact": { + "label": "Details of last contact" + }, "is-this-the-first-chance-to-report": { "label": "Is this the first chance they have had to report this?" }, diff --git a/apps/nrm/translations/src/en/validation.json b/apps/nrm/translations/src/en/validation.json index 67ef0353..f2fd399d 100644 --- a/apps/nrm/translations/src/en/validation.json +++ b/apps/nrm/translations/src/en/validation.json @@ -86,6 +86,9 @@ "required": "Enter how and why they left", "maxlength": "Enter no more than 15,000 characters" }, + "when-last-contact": { + "required": "Tell us when they were last in contact" + }, "is-this-the-first-chance-to-report" : { "required": "You must select an option" }, diff --git a/apps/nrm/views/details-last-contact.html b/apps/nrm/views/details-last-contact.html new file mode 100644 index 00000000..d63f0725 --- /dev/null +++ b/apps/nrm/views/details-last-contact.html @@ -0,0 +1,16 @@ +{{{{#t}}pages.details-last-contact.paragraph-1{{/t}}

+

{{#t}}pages.details-last-contact.paragraph-2{{/t}}

+

{{#t}}pages.details-last-contact.paragraph-3{{/t}}

+ +

Details of the last contact (optional)

+ +{{#fields}} + {{#renderField}}{{/renderField}} + {{/fields}} + + + {{#input-submit}}continue{{/input-submit}} {{> partials-save-and-exit-link}} +{{/page-content}} +{{/partials-page}} \ No newline at end of file diff --git a/apps/nrm/views/partials/summary-table-your-report.html b/apps/nrm/views/partials/summary-table-your-report.html index 0a067c43..d8de2a70 100644 --- a/apps/nrm/views/partials/summary-table-your-report.html +++ b/apps/nrm/views/partials/summary-table-your-report.html @@ -378,6 +378,30 @@

{{#t}}pages.confirm.sections.your-report.header{{/t}} {{/values.is-this-the-first-chance-to-report}} + {{#values.when-last-contact}} + + {{#t}}pages.confirm.fields.when-last-contact.label{{/t}} + + {{formattedWhenLastContact}} + + + Change + + + {{/values.when-last-contact}} + + {{#values.details-last-contact}} + + {{#t}}pages.confirm.fields.details-last-contact.label{{/t}} + + {{values.details-last-contact}} + + + Change + + + {{/values.details-last-contact}} + {{#values.why-report-now}} {{#t}}pages.confirm.fields.why-report-now.label{{/t}} diff --git a/apps/nrm/views/when-last-contact.html b/apps/nrm/views/when-last-contact.html new file mode 100644 index 00000000..5093d4e4 --- /dev/null +++ b/apps/nrm/views/when-last-contact.html @@ -0,0 +1,8 @@ +{{ partials-save-and-exit-link}} +{{/page-content}} +{{/partials-page}} \ No newline at end of file diff --git a/assets/scss/app.scss b/assets/scss/app.scss index 44136dca..89a6753e 100644 --- a/assets/scss/app.scss +++ b/assets/scss/app.scss @@ -341,4 +341,4 @@ textarea { .govuk-list--bullet { margin-left: 15px; padding-left: 20px; -} +} \ No newline at end of file diff --git a/package.json b/package.json index 6cc7fe37..5bab93f5 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "ms-uk-local-authorities": "^2.2.3", "ms-uk-police-forces": "^2.0.0", "ms-uk-regions": "^2.1.1", - "notifications-node-client": "8.0.0", + "notifications-node-client": "^8.0.0", "pg": "^8.7.1", "request": "^2.88.0", "sqs-producer": "^1.6.3", diff --git a/test/_ui-integration/nrm/application.spec.js b/test/_ui-integration/nrm/application.spec.js index 4fc2458d..99c170da 100644 --- a/test/_ui-integration/nrm/application.spec.js +++ b/test/_ui-integration/nrm/application.spec.js @@ -143,9 +143,29 @@ describe('the journey of a nrm application', () => { const response = await passStep(URI, { 'how-why-did-they-leave-the-situation': 'Test' }); - expect(response.text).to.contain('Found. Redirecting to /nrm/is-this-the-first-chance-to-report'); + expect(response.text).to.contain('Found. Redirecting to /nrm/when-last-contact'); }); + it('goes to the when-last-contact page when user enters how and why the last contact was', + async () => { + const URI = '/when-last-contact'; + await initSession(URI); + const response = await passStep(URI, { + 'when-last-contact': 'last-week' + }); + expect(response.text).to.contain('Found. Redirecting to /nrm/details-last-contact'); + }); + + it('goes to the is-this-the-first-chance-to-report page when user enters optional details of last contact', + async () => { + const URI = '/details-last-contact'; + await initSession(URI); + const response = await passStep(URI, { + 'details-last-contact': 'optional text' + }); + expect(response.text).to.contain('Found. Redirecting to /nrm/is-this-the-first-chance-to-report'); + }); + it('goes to the is-this-the-first-chance-to-report page when user enters Is this the first chance they have ' + 'had to report this?', async () => { const URI = '/is-this-the-first-chance-to-report'; diff --git a/test/_ui-integration/nrm/automatic-referral-application.spec.js b/test/_ui-integration/nrm/automatic-referral-application.spec.js index f761c8a5..ebaba82f 100644 --- a/test/_ui-integration/nrm/automatic-referral-application.spec.js +++ b/test/_ui-integration/nrm/automatic-referral-application.spec.js @@ -158,9 +158,29 @@ describe('the journey of a nrm automatic referral application', () => { const response = await passStep(URI, { 'how-why-did-they-leave-the-situation': 'Test' }); - expect(response.text).to.contain('Found. Redirecting to /nrm/is-this-the-first-chance-to-report'); + expect(response.text).to.contain('Found. Redirecting to /nrm/when-last-contact'); }); + it('goes to the when-last-contact page when user enters how and why the last contact was', + async () => { + const URI = '/when-last-contact'; + await initSession(URI); + const response = await passStep(URI, { + 'when-last-contact': 'last-week' + }); + expect(response.text).to.contain('Found. Redirecting to /nrm/details-last-contact'); + }); + + it('goes to the is-this-the-first-chance-to-report page when user enters optional details of last contact', + async () => { + const URI = '/details-last-contact'; + await initSession(URI); + const response = await passStep(URI, { + 'details-last-contact': 'optional text' + }); + expect(response.text).to.contain('Found. Redirecting to /nrm/is-this-the-first-chance-to-report'); + }); + it('goes to the is-this-the-first-chance-to-report page when user enters Is this the first chance they have ' + 'had to report this?', async () => { const URI = '/is-this-the-first-chance-to-report'; diff --git a/test/_ui-integration/nrm/validations.spec.js b/test/_ui-integration/nrm/validations.spec.js index 5fa008b7..b53945db 100644 --- a/test/_ui-integration/nrm/validations.spec.js +++ b/test/_ui-integration/nrm/validations.spec.js @@ -255,6 +255,21 @@ describe('validation checks of the nrm journey', () => { }); }); + describe('First Responder exploiters last in contact Validation', () => { + it('does not pass the when-last-contact page if nothing entered', async () => { + const URI = '/when-last-contact'; + await initSession(URI); + await passStep(URI, {}); + const res = await getUrl(URI); + const docu = await parseHtml(res); + const validationSummary = docu.find('.validation-summary'); + + expect(validationSummary.length === 1).to.be.true; + expect(validationSummary.html()) + .to.match(/Tell us when they were last in contact/); + }); + }); + describe('User enters is this the first chance to report Validation', () => { it('does not pass is this the first chance to report page if nothing entered', async () => { const URI = '/is-this-the-first-chance-to-report'; diff --git a/test/helpers/supertest_session/session-data/nrm/steps.js b/test/helpers/supertest_session/session-data/nrm/steps.js index afca0fe7..fb65aff7 100644 --- a/test/helpers/supertest_session/session-data/nrm/steps.js +++ b/test/helpers/supertest_session/session-data/nrm/steps.js @@ -17,6 +17,8 @@ module.exports = [ '/were-they-taken-somewhere-by-their-exploiter', '/how-they-were-treated', '/how-why-did-they-leave-the-situation', + '/when-last-contact', + '/details-last-contact', '/is-this-the-first-chance-to-report', '/why-report-now', '/why-are-you-making-the-referral',