From 557859d8dcc0d9fc976961bbf3cbfb92ce05c835 Mon Sep 17 00:00:00 2001 From: James Grant Date: Mon, 20 Feb 2023 09:20:52 +0000 Subject: [PATCH 1/3] CDPS-59 - Staff Contacts component --- assets/scss/components/_alerts.scss | 3 +- helm_deploy/values-dev.yaml | 2 + integration_tests/e2e/overviewPage.cy.ts | 9 + integration_tests/pages/overviewPage.ts | 2 + package-lock.json | 314 +----------------- package.json | 1 + server/config.ts | 16 + server/data/allocationManagerApiClient.ts | 19 ++ .../interfaces/allocationManagerClient.ts | 5 + server/data/interfaces/keyWorkerClient.ts | 5 + server/data/interfaces/prisonApiClient.ts | 4 + server/data/keyWorkersApiClient.ts | 22 ++ server/data/localMockData/keyWorker.ts | 12 + server/data/localMockData/pom.ts | 10 + server/data/localMockData/staffContacts.ts | 16 + server/data/prisonApiClient.ts | 19 ++ server/interfaces/caseNote.ts | 7 + server/interfaces/keyWorker.ts | 6 + server/interfaces/pom.ts | 4 + server/interfaces/staffContacts.ts | 38 +++ server/routes/index.ts | 12 +- server/services/overviewPageService.test.ts | 85 ++++- server/services/overviewPageService.ts | 90 ++++- server/utils/utils.ts | 21 ++ .../staffContacts/staffContacts.njk | 6 +- 25 files changed, 410 insertions(+), 318 deletions(-) create mode 100644 server/data/allocationManagerApiClient.ts create mode 100644 server/data/interfaces/allocationManagerClient.ts create mode 100644 server/data/interfaces/keyWorkerClient.ts create mode 100644 server/data/keyWorkersApiClient.ts create mode 100644 server/data/localMockData/keyWorker.ts create mode 100644 server/data/localMockData/pom.ts create mode 100644 server/data/localMockData/staffContacts.ts create mode 100644 server/interfaces/caseNote.ts create mode 100644 server/interfaces/keyWorker.ts create mode 100644 server/interfaces/pom.ts create mode 100644 server/interfaces/staffContacts.ts diff --git a/assets/scss/components/_alerts.scss b/assets/scss/components/_alerts.scss index 16b6fd7d4..62a4e9eff 100644 --- a/assets/scss/components/_alerts.scss +++ b/assets/scss/components/_alerts.scss @@ -12,7 +12,6 @@ font-weight: 300; text-align: center; line-height: 1; - min-width: 100px; } @media print { @@ -40,7 +39,7 @@ gap: 15px; li { - padding: 0 5px; + padding: 0 10px; margin-bottom: 0; background-color: govuk-colour('white'); } diff --git a/helm_deploy/values-dev.yaml b/helm_deploy/values-dev.yaml index c5b2abfda..d56f31efb 100644 --- a/helm_deploy/values-dev.yaml +++ b/helm_deploy/values-dev.yaml @@ -17,6 +17,8 @@ generic-service: DPS_HOME_PAGE_URL: "https://digital-dev.prison.service.justice.gov.uk" PRISONER_SEARCH_API_URL: "https://prisoner-offender-search-dev.prison.service.justice.gov.uk" PRISON_API_URL: "https://api-dev.prison.service.justice.gov.uk" + ALLOCATION_MANAGER_ENDPOINT_URL: "https://allocation-manager-staging.apps.live-1.cloud-platform.service.justice.gov.uk" + KEYWORKER_API_URL: "https://keyworker-api-dev.prison.service.justice.gov.uk" generic-prometheus-alerts: alertSeverity: digital-prison-service-dev diff --git a/integration_tests/e2e/overviewPage.cy.ts b/integration_tests/e2e/overviewPage.cy.ts index e8dde3942..2ad279839 100644 --- a/integration_tests/e2e/overviewPage.cy.ts +++ b/integration_tests/e2e/overviewPage.cy.ts @@ -155,4 +155,13 @@ context('SignIn', () => { overviewPage.personalDetails().should('exist') }) }) + + context('Staff contacts', () => { + it('Displays the offender staff contact details', () => { + cy.task('stubDpsOverviewPage') + cy.signIn() + const overviewPage = Page.verifyOnPage(OverviewPage) + overviewPage.staffContacts().should('exist') + }) + }) }) diff --git a/integration_tests/pages/overviewPage.ts b/integration_tests/pages/overviewPage.ts index 990a81e1a..4d6c8c735 100644 --- a/integration_tests/pages/overviewPage.ts +++ b/integration_tests/pages/overviewPage.ts @@ -64,4 +64,6 @@ export default class OverviewPage extends Page { }) personalDetails = (): PageElement => cy.get('[data-qa=personal-details]') + + staffContacts = (): PageElement => cy.get('[data-qa=staff-contacts]') } diff --git a/package-lock.json b/package-lock.json index 43958ed14..ab7c3f848 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "http-errors": "^2.0.0", "jquery": "^3.6.3", "jwt-decode": "^3.1.2", + "moment": "^2.29.4", "nocache": "^3.0.4", "nunjucks": "^3.2.3", "passport": "^0.6.0", @@ -3607,7 +3608,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, + "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4058,7 +4059,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8" } @@ -4138,7 +4139,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -4146,13 +4147,6 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true, - "peer": true - }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", @@ -4402,7 +4396,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "devOptional": true, + "dev": true, "funding": [ { "type": "individual", @@ -4429,7 +4423,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -5158,19 +5152,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -5284,16 +5265,6 @@ "semver": "bin/semver" } }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", @@ -6467,7 +6438,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6521,16 +6492,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "peer": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -7010,16 +6971,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "peer": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/helmet": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/helmet/-/helmet-6.0.1.tgz", @@ -7323,7 +7274,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, + "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -7423,7 +7374,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -7453,7 +7404,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -7493,7 +7444,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.12.0" } @@ -7522,16 +7473,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -9276,47 +9217,6 @@ "node": ">=10" } }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, "node_modules/mocha-junit-reporter": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-2.2.0.tgz", @@ -9333,111 +9233,6 @@ "mocha": ">=2.2.5" } }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "peer": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "peer": true - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "peer": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -9511,19 +9306,6 @@ "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "optional": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -9714,7 +9496,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -10127,7 +9909,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, + "dev": true, "engines": { "node": ">=8.6" }, @@ -10436,16 +10218,6 @@ "node": ">= 0.8" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -10478,7 +10250,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, + "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -10895,16 +10667,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -11512,7 +11274,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -12044,13 +11806,6 @@ "node": ">=0.10.0" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true, - "peer": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -12159,45 +11914,6 @@ "node": ">=12" } }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "peer": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/package.json b/package.json index 3fb072c2f..c36fe0a23 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "http-errors": "^2.0.0", "jquery": "^3.6.3", "jwt-decode": "^3.1.2", + "moment": "^2.29.4", "nocache": "^3.0.4", "nunjucks": "^3.2.3", "passport": "^0.6.0", diff --git a/server/config.ts b/server/config.ts index e51e105fa..d0230f639 100755 --- a/server/config.ts +++ b/server/config.ts @@ -83,6 +83,22 @@ export default { agent: new AgentConfig(Number(get('PRISONER_SEARCH_API_TIMEOUT_DEADLINE', 20000))), }, dpsHomePageUrl: get('DPS_HOME_PAGE_URL', 'http://localhost:3001', requiredInProduction), + allocationManager: { + url: process.env.ALLOCATION_MANAGER_ENDPOINT_URL || '', + timeout: { + response: Number(get('ALLOCATION_MANAGER_API_TIMEOUT_SECONDS', 20000)), + deadline: Number(get('ALLOCATION_MANAGER_API_TIMEOUT_SECONDS', 20000)), + }, + agent: new AgentConfig(Number(get('ALLOCATION_MANAGER_API_TIMEOUT_DEADLINE', 20000))), + }, + keyworker: { + url: process.env.KEYWORKER_API_URL || 'http://localhost:8081/', + timeout: { + response: Number(get('KEYWORKER_API_TIMEOUT_SECONDS', 20000)), + deadline: Number(get('AKEYWORKER_API_TIMEOUT_SECONDS', 20000)), + }, + agent: new AgentConfig(Number(get('KEYWORKER_API_TIMEOUT_DEADLINE', 20000))), + }, }, domain: get('INGRESS_URL', 'http://localhost:3000', requiredInProduction), localMockData: get('LOCAL_MOCK_DATA', false), diff --git a/server/data/allocationManagerApiClient.ts b/server/data/allocationManagerApiClient.ts new file mode 100644 index 000000000..447bd37ae --- /dev/null +++ b/server/data/allocationManagerApiClient.ts @@ -0,0 +1,19 @@ +import RestClient from './restClient' +import config from '../config' +import { Pom } from '../interfaces/pom' + +export default class AllocationManagerClient { + restClient: RestClient + + constructor(token: string) { + this.restClient = new RestClient('Allocation Manager API', config.apis.allocationManager, token) + } + + async getPomByOffenderNo(offenderNumber: string): Promise { + try { + return await this.restClient.get({ path: `/api/allocation/${offenderNumber}` }) + } catch (error) { + return error + } + } +} diff --git a/server/data/interfaces/allocationManagerClient.ts b/server/data/interfaces/allocationManagerClient.ts new file mode 100644 index 000000000..6d1fe7e23 --- /dev/null +++ b/server/data/interfaces/allocationManagerClient.ts @@ -0,0 +1,5 @@ +import { Pom } from '../../interfaces/pom' + +export default interface AllocationManagerClient { + getPomByOffenderNo(prisonerNumber: string): Promise +} diff --git a/server/data/interfaces/keyWorkerClient.ts b/server/data/interfaces/keyWorkerClient.ts new file mode 100644 index 000000000..fc62775bd --- /dev/null +++ b/server/data/interfaces/keyWorkerClient.ts @@ -0,0 +1,5 @@ +import { KeyWorker } from '../../interfaces/keyWorker' + +export default interface KeyWorkerClient { + getOffendersKeyWorker(prisonerNumber: string): Promise +} diff --git a/server/data/interfaces/prisonApiClient.ts b/server/data/interfaces/prisonApiClient.ts index 6d11b2a7a..3b4411780 100644 --- a/server/data/interfaces/prisonApiClient.ts +++ b/server/data/interfaces/prisonApiClient.ts @@ -6,6 +6,8 @@ import { AdjudicationSummary } from '../../interfaces/adjudicationSummary' import { VisitSummary } from '../../interfaces/visitSummary' import { VisitBalances } from '../../interfaces/visitBalances' import { Assessment } from '../../interfaces/assessment' +import { OffenderContacts } from '../../interfaces/staffContacts' +import { CaseNote } from '../../interfaces/caseNote' export interface PrisonApiClient { getUserLocations(): Promise @@ -16,4 +18,6 @@ export interface PrisonApiClient { getVisitSummary(bookingId: number): Promise getVisitBalances(prisonerNumber: string): Promise getAssessments(bookingId: number): Promise + getOffenderContacts(bookingId: number): Promise + getCaseNoteSummaryByTypes(params: object): Promise } diff --git a/server/data/keyWorkersApiClient.ts b/server/data/keyWorkersApiClient.ts new file mode 100644 index 000000000..3d65b931b --- /dev/null +++ b/server/data/keyWorkersApiClient.ts @@ -0,0 +1,22 @@ +import RestClient from './restClient' +import config from '../config' +import { KeyWorker } from '../interfaces/keyWorker' + +export default class KeyWorkerClient { + restClient: RestClient + + caseLoadId: string + + constructor(token: string, caseLoadId: string) { + this.restClient = new RestClient('KeyWorkers API', config.apis.keyworker, token) + this.caseLoadId = caseLoadId + } + + async getOffendersKeyWorker(offenderNumber: string): Promise { + try { + return await this.restClient.get({ path: `/key-worker/${this.caseLoadId}/offender/${offenderNumber}` }) + } catch (error) { + return error + } + } +} diff --git a/server/data/localMockData/keyWorker.ts b/server/data/localMockData/keyWorker.ts new file mode 100644 index 000000000..56e5cb88a --- /dev/null +++ b/server/data/localMockData/keyWorker.ts @@ -0,0 +1,12 @@ +import { KeyWorker } from '../../interfaces/keyWorker' + +export const keyWorkerMock: KeyWorker = { + staffId: 3532453, + firstName: 'Dave', + lastName: 'Stevens', + email: '1@1.com', +} + +export default { + keyWorkerMock, +} diff --git a/server/data/localMockData/pom.ts b/server/data/localMockData/pom.ts new file mode 100644 index 000000000..ee27bb15e --- /dev/null +++ b/server/data/localMockData/pom.ts @@ -0,0 +1,10 @@ +import { Pom } from '../../interfaces/pom' + +export const pomMock: Pom = { + primary_pom: { staff_id: 485887, name: 'MARKE, ANDY' }, + secondary_pom: { staff_id: 485829, name: 'HUDSON, ANDY' }, +} + +export default { + pomMock, +} diff --git a/server/data/localMockData/staffContacts.ts b/server/data/localMockData/staffContacts.ts new file mode 100644 index 000000000..1847bb4d0 --- /dev/null +++ b/server/data/localMockData/staffContacts.ts @@ -0,0 +1,16 @@ +import { convertToTitleCase } from '../../utils/utils' +import { keyWorkerMock } from './keyWorker' + +export const StaffContactsMock = { + keyWorker: { + name: `${convertToTitleCase(keyWorkerMock.firstName)} ${convertToTitleCase(keyWorkerMock.lastName)}`, + lastSession: '', + }, + prisonOffenderManager: 'Andy Marke', + coworkingPrisonOffenderManager: 'Andy Hudson', + communityOffenderManager: 'Not assigned', +} + +export default { + StaffContactsMock, +} diff --git a/server/data/prisonApiClient.ts b/server/data/prisonApiClient.ts index 288f8212b..c8fce7f86 100644 --- a/server/data/prisonApiClient.ts +++ b/server/data/prisonApiClient.ts @@ -13,6 +13,9 @@ import { AdjudicationSummary } from '../interfaces/adjudicationSummary' import { VisitSummary } from '../interfaces/visitSummary' import { VisitBalances } from '../interfaces/visitBalances' import { Assessment } from '../interfaces/assessment' +import { OffenderContacts } from '../interfaces/staffContacts' +import { mapToQueryString } from '../utils/utils' +import { CaseNote } from '../interfaces/caseNote' export default class PrisonApiRestClient implements PrisonApiClient { restClient: RestClient @@ -109,4 +112,20 @@ export default class PrisonApiRestClient implements PrisonApiClient { return error } } + + async getOffenderContacts(bookingId: number): Promise { + try { + return await this.restClient.get({ path: `/api/bookings/${bookingId}/contacts` }) + } catch (error) { + return error + } + } + + async getCaseNoteSummaryByTypes(params: object): Promise { + try { + return await this.restClient.get({ path: `/api/case-notes/summary?${mapToQueryString(params)}` }) + } catch (error) { + return error + } + } } diff --git a/server/interfaces/caseNote.ts b/server/interfaces/caseNote.ts new file mode 100644 index 000000000..4f299111c --- /dev/null +++ b/server/interfaces/caseNote.ts @@ -0,0 +1,7 @@ +export type CaseNote = { + bookingId: number + caseNoteType: string + caseNoteSubType: string + numCaseNotes: number + latestCaseNote: string +} diff --git a/server/interfaces/keyWorker.ts b/server/interfaces/keyWorker.ts new file mode 100644 index 000000000..8b24009d5 --- /dev/null +++ b/server/interfaces/keyWorker.ts @@ -0,0 +1,6 @@ +export interface KeyWorker { + staffId: number + firstName: string + lastName: string + email: string +} diff --git a/server/interfaces/pom.ts b/server/interfaces/pom.ts new file mode 100644 index 000000000..95230fd0c --- /dev/null +++ b/server/interfaces/pom.ts @@ -0,0 +1,4 @@ +export interface Pom { + primary_pom: { staff_id: number; name: string } + secondary_pom: { staff_id: number; name: string } +} diff --git a/server/interfaces/staffContacts.ts b/server/interfaces/staffContacts.ts new file mode 100644 index 000000000..5202f1451 --- /dev/null +++ b/server/interfaces/staffContacts.ts @@ -0,0 +1,38 @@ +export interface StaffContacts { + keyWorker: KeyWorkerUI + prisonOffenderManager: string + coworkingPrisonOffenderManager: string + communityOffenderManager: string +} + +export interface KeyWorkerUI { + name: string + lastSession: string +} + +export interface OffenderContact { + lastName: string + firstName: string + middleName: string + contactType: string + contactTypeDescription: string + relationship: string + relationshipDescription: string + commentText: string + emergencyContact: boolean + nextOfKin: boolean + relationshipId: number + personId: number + activeFlag: boolean + expiryDate: string + approvedVisitorFlag: boolean + canBeContactedFlag: boolean + awareOfChargesFlag: boolean + contactRootOffenderId: number + bookingId: number + createDateTime: string +} + +export interface OffenderContacts { + otherContacts: OffenderContact[] +} diff --git a/server/routes/index.ts b/server/routes/index.ts index 02f764c7b..43f02998e 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -11,6 +11,9 @@ import PrisonerSearchClient from '../data/prisonerSearchClient' import { mapHeaderData } from '../mappers/headerMappers' import { PageConfig } from '../interfaces/pageConfig' +import AllocationManagerClient from '../data/allocationManagerApiClient' +import KeyWorkersClient from '../data/keyWorkersApiClient' +import { convertToTitleCase } from '../utils/utils' // eslint-disable-next-line @typescript-eslint/no-unused-vars export default function routes(service: Services): Router { @@ -27,10 +30,13 @@ export default function routes(service: Services): Router { get('/prisoner/:prisonerNumber', async (req, res, next) => { const prisonerSearchClient = new PrisonerSearchClient(res.locals.clientToken) + const prisonApiClient = new PrisonApiRestClient(res.locals.clientToken) + const allocationManagerClient = new AllocationManagerClient(res.locals.clientToken) + const keyWorkersClient = new KeyWorkersClient(res.locals.clientToken, res.locals.user.activeCaseLoadId) + const prisonerData: Prisoner = await prisonerSearchClient.getPrisonerDetails(req.params.prisonerNumber) - const prisonApi = new PrisonApiRestClient(res.locals.clientToken) - const overviewPageService = new OverviewPageService(prisonApi) + const overviewPageService = new OverviewPageService(prisonApiClient, allocationManagerClient, keyWorkersClient) const overviewPageData = await overviewPageService.get(prisonerData) const pageConfig: PageConfig = DisplayBanner @@ -65,7 +71,7 @@ export default function routes(service: Services): Router { href: '#', }, { - text: `${prisonerData.lastName} ,${prisonerData.firstName}`, + text: `${convertToTitleCase(prisonerData.lastName)} ,${convertToTitleCase(prisonerData.firstName)}`, href: `/prisoner/${req.params.prisonerNumber}`, }, ] diff --git a/server/services/overviewPageService.test.ts b/server/services/overviewPageService.test.ts index f375bd398..bbc87e538 100644 --- a/server/services/overviewPageService.test.ts +++ b/server/services/overviewPageService.test.ts @@ -13,6 +13,12 @@ import { } from '../data/localMockData/miniSummaryMock' import { PrisonerMockDataA, PrisonerMockDataB } from '../data/localMockData/prisoner' +import AllocationManagerClient from '../data/interfaces/allocationManagerClient' +import KeyWorkerClient from '../data/interfaces/keyWorkerClient' +import { pomMock } from '../data/localMockData/pom' +import { keyWorkerMock } from '../data/localMockData/keyWorker' +import { StaffContactsMock } from '../data/localMockData/staffContacts' + describe('OverviewPageService', () => { const prisonApiClient: PrisonApiClient = { getNonAssociationDetails: jest.fn(async () => nonAssociationDetailsDummyData), @@ -23,17 +29,35 @@ describe('OverviewPageService', () => { getAdjudications: jest.fn(async () => adjudicationSummaryMock), getAccountBalances: jest.fn(async () => accountBalancesMock), getAssessments: jest.fn(async () => assessmentsMock), + getOffenderContacts: jest.fn(), + getCaseNoteSummaryByTypes: jest.fn(), + } + + const allocationManagerApiClient: AllocationManagerClient = { + getPomByOffenderNo: jest.fn(async () => pomMock), + } + + const keyWorkerApiClient: KeyWorkerClient = { + getOffendersKeyWorker: jest.fn(async () => keyWorkerMock), } describe('Non-associations', () => { it.each(['ABC123', 'DEF321'])('Gets the non-associations for the prisoner', async (prisonerNumber: string) => { - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) await overviewPageService.get({ prisonerNumber } as Prisoner) expect(prisonApiClient.getNonAssociationDetails).toHaveBeenCalledWith(prisonerNumber) }) it('Converts the non-associations into the correct rows', async () => { - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ prisonerNumber: 'ABC123' } as Prisoner) expect(res.nonAssociations.length).toEqual(2) const associationRowOne = res.nonAssociations[0] @@ -52,7 +76,11 @@ describe('OverviewPageService', () => { const nonAssocations = { ...nonAssociationDetailsDummyData } nonAssocations.nonAssociations[0].offenderNonAssociation.agencyDescription = 'Somewhere else' prisonApiClient.getNonAssociationDetails = jest.fn(async () => nonAssocations) - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ prisonerNumber: 'ABC123' } as Prisoner) const expectedPrisonNumber = nonAssocations.nonAssociations[1].offenderNonAssociation.offenderNo expect(res.nonAssociations.length).toEqual(1) @@ -63,7 +91,11 @@ describe('OverviewPageService', () => { const nonAssocations = { ...nonAssociationDetailsDummyData } nonAssocations.nonAssociations = [] prisonApiClient.getNonAssociationDetails = jest.fn(async () => nonAssocations) - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ prisonerNumber: 'ABC123' } as Prisoner) expect(res.nonAssociations.length).toEqual(0) }) @@ -74,7 +106,11 @@ describe('OverviewPageService', () => { const prisonerNumber = 'A1234BC' const bookingId = 123456 - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) await overviewPageService.get({ prisonerNumber, bookingId } as Prisoner) expect(prisonApiClient.getAccountBalances).toHaveBeenCalledWith(bookingId) expect(prisonApiClient.getAdjudications).toHaveBeenCalledWith(bookingId) @@ -86,7 +122,11 @@ describe('OverviewPageService', () => { const prisonerNumber = 'A1234BC' const bookingId = 123456 - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ prisonerNumber, bookingId } as Prisoner) expect(res.miniSummaryGroupA).toEqual(miniSummaryGroupAMock) @@ -98,7 +138,11 @@ describe('OverviewPageService', () => { const prisonerNumber = 'A1234BC' const bookingId = 123456 - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) await overviewPageService.get({ ...PrisonerMockDataA, prisonerNumber, bookingId } as Prisoner) expect(prisonApiClient.getAssessments).toHaveBeenCalledWith(bookingId) }) @@ -107,7 +151,11 @@ describe('OverviewPageService', () => { const prisonerNumber = 'A1234BC' const bookingId = 123456 - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ ...PrisonerMockDataA, prisonerNumber, bookingId } as Prisoner) expect(res.miniSummaryGroupB).toEqual(miniSummaryGroupBMock) @@ -119,9 +167,28 @@ describe('OverviewPageService', () => { const prisonerNumber = '123123' const bookingId = 567567 - const overviewPageService = new OverviewPageService(prisonApiClient) + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) const res = await overviewPageService.get({ ...PrisonerMockDataB, prisonerNumber, bookingId } as Prisoner) expect(res.personalDetails).toEqual(overviewPageService.getPersonalDetails(PrisonerMockDataB)) }) }) + + describe('getStaffContactDetails', () => { + it('should get the staff contact details for a prisoner', async () => { + const prisonerNumber = '123123' + const bookingId = 567567 + + const overviewPageService = new OverviewPageService( + prisonApiClient, + allocationManagerApiClient, + keyWorkerApiClient, + ) + const res = await overviewPageService.get({ ...PrisonerMockDataB, prisonerNumber, bookingId } as Prisoner) + expect(res.staffContacts).toEqual(StaffContactsMock) + }) + }) }) diff --git a/server/services/overviewPageService.ts b/server/services/overviewPageService.ts index 4254bf2ef..033413887 100644 --- a/server/services/overviewPageService.ts +++ b/server/services/overviewPageService.ts @@ -1,18 +1,39 @@ -import { schedule, staffContacts, statuses } from '../data/overviewPage' +import moment from 'moment' +import { schedule, statuses } from '../data/overviewPage' import { MiniSummary, MiniSummaryData } from '../interfaces/miniSummary' import { OverviewNonAssociation, OverviewPage } from '../interfaces/overviewPage' import { PrisonApiClient } from '../data/interfaces/prisonApiClient' -import { convertToTitleCase, formatDate, formatMoney, formatPrivilegedVisitsSummary } from '../utils/utils' +import { + convertToTitleCase, + formatDate, + formatMoney, + formatPrivilegedVisitsSummary, + getNamesFromString, +} from '../utils/utils' import { Assessment } from '../interfaces/assessment' import { AssessmentCode } from '../data/enums/assessmentCode' import { Incentive, Prisoner } from '../interfaces/prisoner' import { PersonalDetails } from '../interfaces/personalDetails' +import { StaffContacts } from '../interfaces/staffContacts' +import AllocationManagerClient from '../data/interfaces/allocationManagerClient' +import KeyWorkerClient from '../data/interfaces/keyWorkerClient' +import { Pom } from '../interfaces/pom' export default class OverviewPageService { private prisonApiClient: PrisonApiClient - constructor(prisonApiClient: PrisonApiClient) { + private allocationManagerClient: AllocationManagerClient + + private keyWorkerClient: KeyWorkerClient + + constructor( + prisonApiClient: PrisonApiClient, + allocationManagerClient: AllocationManagerClient, + keyWorkerClient: KeyWorkerClient, + ) { this.prisonApiClient = prisonApiClient + this.allocationManagerClient = allocationManagerClient + this.keyWorkerClient = keyWorkerClient } public async get(prisonerData: Prisoner): Promise { @@ -22,6 +43,7 @@ export default class OverviewPageService { const miniSummaryGroupA = await this.getMiniSummaryGroupA(prisonerNumber, bookingId) const miniSummaryGroupB = await this.getMiniSummaryGroupB(currentIncentive, bookingId) const personalDetails = this.getPersonalDetails(prisonerData) + const staffContacts = await this.getStaffContacts(prisonerData) return { miniSummaryGroupA, @@ -34,6 +56,68 @@ export default class OverviewPageService { } } + public async getStaffContacts(prisonerData: Prisoner): Promise { + const { bookingId } = prisonerData + const [offenderContacts, allocationManager, offenderKeyWorker, keyWorkerSessions] = await Promise.all([ + this.prisonApiClient.getOffenderContacts(prisonerData.bookingId), + this.allocationManagerClient.getPomByOffenderNo(prisonerData.prisonerNumber).catch(() => undefined), + this.keyWorkerClient.getOffendersKeyWorker(prisonerData.prisonerNumber), + this.prisonApiClient.getCaseNoteSummaryByTypes({ type: 'KA', subType: 'KS', numMonths: 36, bookingId }), + ]) + + const communityOffenderManager = offenderContacts + ? offenderContacts.otherContacts + .filter(contact => contact && contact.relationship === 'COM') + .map(contact => ({ + firstName: contact ? contact?.firstName : undefined, + lastName: contact ? contact?.lastName : undefined, + })) + : [] + + const prisonOffenderManager = + allocationManager && + (allocationManager as Pom).primary_pom && + (allocationManager as Pom).primary_pom.name && + getNamesFromString((allocationManager as Pom).primary_pom.name) + + const coworkingPrisonOffenderManager = + allocationManager && + (allocationManager as Pom).secondary_pom && + (allocationManager as Pom).secondary_pom.name && + getNamesFromString((allocationManager as Pom).secondary_pom.name) + + const staffContacts = { + keyWorker: { + name: + offenderKeyWorker && offenderKeyWorker.firstName + ? `${convertToTitleCase(offenderKeyWorker.firstName)} ${convertToTitleCase(offenderKeyWorker.lastName)}` + : 'Not allocated', + lastSession: + keyWorkerSessions !== undefined && keyWorkerSessions[0] !== undefined + ? keyWorkerSessions && + keyWorkerSessions[0] && + moment(keyWorkerSessions[0].latestCaseNote).format('D MMMM YYYY') + : '', + }, + prisonOffenderManager: + prisonOffenderManager !== undefined + ? `${prisonOffenderManager[0]} ${prisonOffenderManager[1]}` + : 'Not assigned', + coworkingPrisonOffenderManager: + coworkingPrisonOffenderManager !== undefined + ? `${coworkingPrisonOffenderManager[0]} ${coworkingPrisonOffenderManager[1]}` + : 'Not assigned', + communityOffenderManager: + communityOffenderManager && communityOffenderManager[0] !== undefined + ? `${convertToTitleCase(communityOffenderManager[0].firstName)} ${convertToTitleCase( + communityOffenderManager[0].lastName, + )}` + : 'Not assigned', + } + + return staffContacts + } + public getPersonalDetails(prisonerData: Prisoner): PersonalDetails { const personalDetailsMain = [ { diff --git a/server/utils/utils.ts b/server/utils/utils.ts index 999a351ef..a2e62ed91 100644 --- a/server/utils/utils.ts +++ b/server/utils/utils.ts @@ -94,3 +94,24 @@ export const formatMoney = (val: number, emptyState: string = undefined, currenc export const formatPrivilegedVisitsSummary = (count: number): string => { return `Including ${count} privileged visits` } + +export const arrayToQueryString = (array: string[] | number[] | boolean[], key: string): string => + array && array.map(item => `${key}=${encodeURIComponent(item)}`).join('&') + +export const mapToQueryString = (params: Record): string => + Object.keys(params) + .filter(key => params[key]) + .map(key => { + if (Array.isArray(params[key])) return arrayToQueryString(params[key], key) + return `${key}=${encodeURIComponent(params[key])}` + }) + .join('&') + +export const getNamesFromString = (string: string): string[] => + string && + string + .split(', ') + .reverse() + .join(' ') + .split(' ') + .map(name => properCaseName(name)) diff --git a/server/views/partials/overviewPage/staffContacts/staffContacts.njk b/server/views/partials/overviewPage/staffContacts/staffContacts.njk index 798ade136..dd7e521ab 100644 --- a/server/views/partials/overviewPage/staffContacts/staffContacts.njk +++ b/server/views/partials/overviewPage/staffContacts/staffContacts.njk @@ -1,12 +1,14 @@ {% from "../macros/summaryCardMacro.njk" import summaryCard %} {% from "govuk/components/summary-list/macro.njk" import govukSummaryList %} {%- call summaryCard({title: "Staff contacts"}) -%} -
+
{% set keyWorkerHtml %}

{{ staffContacts.keyWorker.name }} - - last session: {{ staffContacts.keyWorker.lastSession | formatDate }} + {% if(staffContacts.keyWorker.lastSession) %} + - last session: {{ staffContacts.keyWorker.lastSession | formatDate }} + {% endif %}

{% endset %} {{ govukSummaryList({ From 7df6ec652b8cf618b29b5a766cca35c34d2cad17 Mon Sep 17 00:00:00 2001 From: James Grant Date: Mon, 20 Feb 2023 09:26:43 +0000 Subject: [PATCH 2/3] CDPS-59 - update package --- package-lock.json | 314 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 1 - 2 files changed, 299 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab7c3f848..43958ed14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ "http-errors": "^2.0.0", "jquery": "^3.6.3", "jwt-decode": "^3.1.2", - "moment": "^2.29.4", "nocache": "^3.0.4", "nunjucks": "^3.2.3", "passport": "^0.6.0", @@ -3608,7 +3607,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, + "devOptional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4059,7 +4058,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -4139,7 +4138,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, + "devOptional": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -4147,6 +4146,13 @@ "node": ">=8" } }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "peer": true + }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", @@ -4396,7 +4402,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, + "devOptional": true, "funding": [ { "type": "individual", @@ -4423,7 +4429,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, + "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -5152,6 +5158,19 @@ } } }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -5265,6 +5284,16 @@ "semver": "bin/semver" } }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", @@ -6438,7 +6467,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "devOptional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6492,6 +6521,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "peer": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -6971,6 +7010,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "peer": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/helmet": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/helmet/-/helmet-6.0.1.tgz", @@ -7274,7 +7323,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, + "devOptional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -7374,7 +7423,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -7404,7 +7453,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -7444,7 +7493,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.12.0" } @@ -7473,6 +7522,16 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -9217,6 +9276,47 @@ "node": ">=10" } }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, "node_modules/mocha-junit-reporter": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-2.2.0.tgz", @@ -9233,6 +9333,111 @@ "mocha": ">=2.2.5" } }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "peer": true + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "peer": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -9306,6 +9511,19 @@ "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "optional": true }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -9496,7 +9714,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -9909,7 +10127,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8.6" }, @@ -10218,6 +10436,16 @@ "node": ">= 0.8" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -10250,7 +10478,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, + "devOptional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -10667,6 +10895,16 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -11274,7 +11512,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "devOptional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -11806,6 +12044,13 @@ "node": ">=0.10.0" } }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true, + "peer": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11914,6 +12159,45 @@ "node": ">=12" } }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "peer": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/package.json b/package.json index c36fe0a23..3fb072c2f 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,6 @@ "http-errors": "^2.0.0", "jquery": "^3.6.3", "jwt-decode": "^3.1.2", - "moment": "^2.29.4", "nocache": "^3.0.4", "nunjucks": "^3.2.3", "passport": "^0.6.0", From 6dddd565e0ec7804fe6c1de0f400f2d76b7c3d11 Mon Sep 17 00:00:00 2001 From: James Grant Date: Mon, 20 Feb 2023 10:29:08 +0000 Subject: [PATCH 3/3] CDPS-59 - updated the format --- server/services/overviewPageService.ts | 9 +++------ .../overviewPage/staffContacts/staffContacts.njk | 4 +++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/server/services/overviewPageService.ts b/server/services/overviewPageService.ts index 033413887..1d7281580 100644 --- a/server/services/overviewPageService.ts +++ b/server/services/overviewPageService.ts @@ -1,4 +1,3 @@ -import moment from 'moment' import { schedule, statuses } from '../data/overviewPage' import { MiniSummary, MiniSummaryData } from '../interfaces/miniSummary' import { OverviewNonAssociation, OverviewPage } from '../interfaces/overviewPage' @@ -62,7 +61,7 @@ export default class OverviewPageService { this.prisonApiClient.getOffenderContacts(prisonerData.bookingId), this.allocationManagerClient.getPomByOffenderNo(prisonerData.prisonerNumber).catch(() => undefined), this.keyWorkerClient.getOffendersKeyWorker(prisonerData.prisonerNumber), - this.prisonApiClient.getCaseNoteSummaryByTypes({ type: 'KA', subType: 'KS', numMonths: 36, bookingId }), + this.prisonApiClient.getCaseNoteSummaryByTypes({ type: 'KA', subType: 'KS', numMonths: 38, bookingId }), ]) const communityOffenderManager = offenderContacts @@ -93,10 +92,8 @@ export default class OverviewPageService { ? `${convertToTitleCase(offenderKeyWorker.firstName)} ${convertToTitleCase(offenderKeyWorker.lastName)}` : 'Not allocated', lastSession: - keyWorkerSessions !== undefined && keyWorkerSessions[0] !== undefined - ? keyWorkerSessions && - keyWorkerSessions[0] && - moment(keyWorkerSessions[0].latestCaseNote).format('D MMMM YYYY') + keyWorkerSessions !== undefined && keyWorkerSessions[0].latestCaseNote !== undefined + ? formatDate(keyWorkerSessions[0].latestCaseNote, 'short') : '', }, prisonOffenderManager: diff --git a/server/views/partials/overviewPage/staffContacts/staffContacts.njk b/server/views/partials/overviewPage/staffContacts/staffContacts.njk index dd7e521ab..87242e7f4 100644 --- a/server/views/partials/overviewPage/staffContacts/staffContacts.njk +++ b/server/views/partials/overviewPage/staffContacts/staffContacts.njk @@ -7,7 +7,9 @@

{{ staffContacts.keyWorker.name }} {% if(staffContacts.keyWorker.lastSession) %} - - last session: {{ staffContacts.keyWorker.lastSession | formatDate }} + - last session: {{ staffContacts.keyWorker.lastSession }} + {% else %} + - No previous session {% endif %}

{% endset %}