@ministryofjustice/hmpps-mpop-frontend-components-lib 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # hmpps-mpop-frontend-components-lib
2
+ MPoP front-end library
@@ -0,0 +1,10 @@
1
+ import type { AuthOptions } from '@ministryofjustice/hmpps-rest-client';
2
+ import type { AuthenticationClient } from '@ministryofjustice/hmpps-auth-clients';
3
+ import type Logger from 'bunyan';
4
+ import type { MPoPComponentsConfig } from './types/MPoPComponentsConfig';
5
+ import type { LatestTierResponse } from './types/TierCalculation';
6
+ export default class MPoPComponents {
7
+ private readonly tierApiRestClient;
8
+ constructor(authenticationClient: AuthenticationClient, config: MPoPComponentsConfig, logger?: Logger | Console);
9
+ getTierDetails(authOptions: AuthOptions | string, crn: string): Promise<LatestTierResponse>;
10
+ }
@@ -0,0 +1,8 @@
1
+ import type { RestClient, AuthOptions } from '@ministryofjustice/hmpps-rest-client';
2
+ import type Logger from 'bunyan';
3
+ export declare class SuppressingRestClient {
4
+ private readonly restClient;
5
+ private readonly logger;
6
+ constructor(restClient: RestClient, logger: Logger | Console);
7
+ get<T>(path: string, authOptions: AuthOptions | string): Promise<T | null>;
8
+ }
package/dist/_all.scss ADDED
@@ -0,0 +1,4 @@
1
+ // MPOP Frontend Components Library
2
+ // Requires govuk-frontend to be imported first
3
+
4
+ @import "./mpop/components/supervision-package/supervision-package";
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ var hmppsRestClient = require('@ministryofjustice/hmpps-rest-client');
4
+
5
+ class SuppressingRestClient {
6
+ constructor(restClient, logger) {
7
+ this.restClient = restClient;
8
+ this.logger = logger;
9
+ }
10
+ async get(path, authOptions) {
11
+ return this.restClient.get({
12
+ path,
13
+ errorHandler: (requestPath, method, error) => {
14
+ if (error.responseStatus === 404) {
15
+ this.logger.debug(`API returned 404 (Not Found) for ${method}: ${requestPath}`);
16
+ return null;
17
+ }
18
+ throw error;
19
+ },
20
+ }, authOptions);
21
+ }
22
+ }
23
+
24
+ class MPoPComponents {
25
+ constructor(authenticationClient, config, logger = console) {
26
+ this.tierApiRestClient = new SuppressingRestClient(new hmppsRestClient.RestClient('Tier API', config, logger, authenticationClient), logger);
27
+ }
28
+ async getTierDetails(authOptions, crn) {
29
+ var _a;
30
+ try {
31
+ const response = await this.tierApiRestClient.get(`/v3/crn/${crn}/tier`, authOptions);
32
+ if (!response) {
33
+ return {
34
+ calculation: null,
35
+ httpStatus: 404,
36
+ };
37
+ }
38
+ return {
39
+ calculation: response,
40
+ httpStatus: 200,
41
+ };
42
+ }
43
+ catch (error) {
44
+ const err = error;
45
+ return {
46
+ calculation: null,
47
+ httpStatus: (_a = err === null || err === void 0 ? void 0 : err.responseStatus) !== null && _a !== void 0 ? _a : 500,
48
+ };
49
+ }
50
+ }
51
+ }
52
+
53
+ exports.MPoPComponents = MPoPComponents;
54
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/SuppressingRestClient.ts","../src/MPoPComponents.ts"],"sourcesContent":[null,null],"names":["RestClient"],"mappings":";;;;MAGa,qBAAqB,CAAA;IAChC,WAAA,CACmB,UAAsB,EACtB,MAAwB,EAAA;QADxB,IAAA,CAAA,UAAU,GAAV,UAAU;QACV,IAAA,CAAA,MAAM,GAAN,MAAM;IACtB;AAEH,IAAA,MAAM,GAAG,CAAI,IAAY,EAAE,WAAiC,EAAA;AAC1D,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CACxB;YACE,IAAI;YACJ,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,KAAI;AAC3C,gBAAA,IAAI,KAAK,CAAC,cAAc,KAAK,GAAG,EAAE;oBAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,iCAAA,EAAoC,MAAM,CAAA,EAAA,EAAK,WAAW,CAAA,CAAE,CAAC;AAC/E,oBAAA,OAAO,IAAI;gBACb;AACA,gBAAA,MAAM,KAAK;YACb,CAAC;SACF,EACD,WAAW,CACZ;IACH;AACD;;ACfa,MAAO,cAAc,CAAA;AAGjC,IAAA,WAAA,CACE,oBAA0C,EAC1C,MAA4B,EAC5B,SAA2B,OAAO,EAAA;QAElC,IAAI,CAAC,iBAAiB,GAAG,IAAI,qBAAqB,CAChD,IAAIA,0BAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAChE,MAAM,CACP;IACH;AAEA,IAAA,MAAM,cAAc,CAAC,WAAiC,EAAE,GAAW,EAAA;;AACjE,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAa,WAAW,GAAG,CAAA,KAAA,CAAO,EAAE,WAAW,CAAC;YAEjG,IAAI,CAAC,QAAQ,EAAE;gBACb,OAAO;AACL,oBAAA,WAAW,EAAE,IAAI;AACjB,oBAAA,UAAU,EAAE,GAAG;iBAChB;YACH;YAEA,OAAO;AACL,gBAAA,WAAW,EAAE,QAAQ;AACrB,gBAAA,UAAU,EAAE,GAAG;aAChB;QACH;QAAE,OAAO,KAAK,EAAE;YACd,MAAM,GAAG,GAAG,KAEJ;YAER,OAAO;AACL,gBAAA,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,CAAA,EAAA,GAAA,GAAG,KAAA,IAAA,IAAH,GAAG,uBAAH,GAAG,CAAE,cAAc,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,GAAG;aACvC;QACH;IACF;AACD;;;;"}
@@ -0,0 +1,27 @@
1
+ import { ApiConfig, AuthOptions } from '@ministryofjustice/hmpps-rest-client';
2
+ import { AuthenticationClient } from '@ministryofjustice/hmpps-auth-clients';
3
+ import Logger from 'bunyan';
4
+
5
+ interface MPoPComponentsConfig extends ApiConfig {
6
+ }
7
+
8
+ type LatestTier = {
9
+ tierScore: string;
10
+ calculationId: string;
11
+ calculationDate: string;
12
+ changeReason: string;
13
+ provisional: boolean;
14
+ };
15
+ type LatestTierResponse = {
16
+ calculation: LatestTier | null;
17
+ httpStatus: number;
18
+ };
19
+
20
+ declare class MPoPComponents {
21
+ private readonly tierApiRestClient;
22
+ constructor(authenticationClient: AuthenticationClient, config: MPoPComponentsConfig, logger?: Logger | Console);
23
+ getTierDetails(authOptions: AuthOptions | string, crn: string): Promise<LatestTierResponse>;
24
+ }
25
+
26
+ export { MPoPComponents };
27
+ export type { MPoPComponentsConfig };
@@ -0,0 +1,52 @@
1
+ import { RestClient } from '@ministryofjustice/hmpps-rest-client';
2
+
3
+ class SuppressingRestClient {
4
+ constructor(restClient, logger) {
5
+ this.restClient = restClient;
6
+ this.logger = logger;
7
+ }
8
+ async get(path, authOptions) {
9
+ return this.restClient.get({
10
+ path,
11
+ errorHandler: (requestPath, method, error) => {
12
+ if (error.responseStatus === 404) {
13
+ this.logger.debug(`API returned 404 (Not Found) for ${method}: ${requestPath}`);
14
+ return null;
15
+ }
16
+ throw error;
17
+ },
18
+ }, authOptions);
19
+ }
20
+ }
21
+
22
+ class MPoPComponents {
23
+ constructor(authenticationClient, config, logger = console) {
24
+ this.tierApiRestClient = new SuppressingRestClient(new RestClient('Tier API', config, logger, authenticationClient), logger);
25
+ }
26
+ async getTierDetails(authOptions, crn) {
27
+ var _a;
28
+ try {
29
+ const response = await this.tierApiRestClient.get(`/v3/crn/${crn}/tier`, authOptions);
30
+ if (!response) {
31
+ return {
32
+ calculation: null,
33
+ httpStatus: 404,
34
+ };
35
+ }
36
+ return {
37
+ calculation: response,
38
+ httpStatus: 200,
39
+ };
40
+ }
41
+ catch (error) {
42
+ const err = error;
43
+ return {
44
+ calculation: null,
45
+ httpStatus: (_a = err === null || err === void 0 ? void 0 : err.responseStatus) !== null && _a !== void 0 ? _a : 500,
46
+ };
47
+ }
48
+ }
49
+ }
50
+
51
+ export { MPoPComponents };
52
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/SuppressingRestClient.ts","../src/MPoPComponents.ts"],"sourcesContent":[null,null],"names":[],"mappings":";;MAGa,qBAAqB,CAAA;IAChC,WAAA,CACmB,UAAsB,EACtB,MAAwB,EAAA;QADxB,IAAA,CAAA,UAAU,GAAV,UAAU;QACV,IAAA,CAAA,MAAM,GAAN,MAAM;IACtB;AAEH,IAAA,MAAM,GAAG,CAAI,IAAY,EAAE,WAAiC,EAAA;AAC1D,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CACxB;YACE,IAAI;YACJ,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,KAAI;AAC3C,gBAAA,IAAI,KAAK,CAAC,cAAc,KAAK,GAAG,EAAE;oBAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,iCAAA,EAAoC,MAAM,CAAA,EAAA,EAAK,WAAW,CAAA,CAAE,CAAC;AAC/E,oBAAA,OAAO,IAAI;gBACb;AACA,gBAAA,MAAM,KAAK;YACb,CAAC;SACF,EACD,WAAW,CACZ;IACH;AACD;;ACfa,MAAO,cAAc,CAAA;AAGjC,IAAA,WAAA,CACE,oBAA0C,EAC1C,MAA4B,EAC5B,SAA2B,OAAO,EAAA;QAElC,IAAI,CAAC,iBAAiB,GAAG,IAAI,qBAAqB,CAChD,IAAI,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAChE,MAAM,CACP;IACH;AAEA,IAAA,MAAM,cAAc,CAAC,WAAiC,EAAE,GAAW,EAAA;;AACjE,QAAA,IAAI;AACF,YAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAa,WAAW,GAAG,CAAA,KAAA,CAAO,EAAE,WAAW,CAAC;YAEjG,IAAI,CAAC,QAAQ,EAAE;gBACb,OAAO;AACL,oBAAA,WAAW,EAAE,IAAI;AACjB,oBAAA,UAAU,EAAE,GAAG;iBAChB;YACH;YAEA,OAAO;AACL,gBAAA,WAAW,EAAE,QAAQ;AACrB,gBAAA,UAAU,EAAE,GAAG;aAChB;QACH;QAAE,OAAO,KAAK,EAAE;YACd,MAAM,GAAG,GAAG,KAEJ;YAER,OAAO;AACL,gBAAA,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,CAAA,EAAA,GAAA,GAAG,KAAA,IAAA,IAAH,GAAG,uBAAH,GAAG,CAAE,cAAc,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,GAAG;aACvC;QACH;IACF;AACD;;;;"}
@@ -0,0 +1,22 @@
1
+ $supervision-package-border-colour: govuk-colour("mid-grey");
2
+ $supervision-package-accent-colour: govuk-colour("blue");
3
+
4
+ .supervision-package {
5
+ border-top: 5px solid $supervision-package-accent-colour;
6
+ border-right: 1px solid $supervision-package-border-colour;
7
+ border-bottom: 1px solid $supervision-package-border-colour;
8
+ border-left: 1px solid $supervision-package-border-colour;
9
+
10
+ padding-top: govuk-spacing(4);
11
+ padding-right: govuk-spacing(4);
12
+ padding-left: govuk-spacing(4);
13
+
14
+ margin-bottom: govuk-spacing(6);
15
+ }
16
+
17
+ .app-tier-header {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: govuk-spacing(2);
21
+ margin-bottom: govuk-spacing(3);
22
+ }
@@ -0,0 +1,3 @@
1
+ {% macro supervisionPackage(params) %}
2
+ {% include "./template.njk" %}
3
+ {% endmacro %}
@@ -0,0 +1,31 @@
1
+ <div class="govuk-width-container supervision-package">
2
+ <h2 class="govuk-heading-m">{{ params.heading or "Supervision package" }}</h2>
3
+
4
+ <div class="govuk-grid-row">
5
+ <div class="govuk-grid-column-two-thirds">
6
+ <div class="app-tier-header">
7
+ <h3 class="govuk-heading-s govuk-!-margin-bottom-0">
8
+ Tier {{ params.tierScore }}
9
+ </h3>
10
+
11
+ {% if params.provisional %}
12
+ <strong class="govuk-tag govuk-tag--orange">Provisional</strong>
13
+ {% endif %}
14
+ </div>
15
+
16
+ {% if params.provisional %}
17
+ <p class="govuk-body">
18
+ We will calculate the supervision package once the tier is confirmed.
19
+ </p>
20
+ {% endif %}
21
+
22
+ {% if params.historyHref %}
23
+ <p class="govuk-body">
24
+ <a href="{{ params.historyHref }}" class="govuk-link govuk-link--no-visited-state">
25
+ {{ params.historyText or "View tier change history" }}
26
+ </a>
27
+ </p>
28
+ {% endif %}
29
+ </div>
30
+ </div>
31
+ </div>
@@ -0,0 +1,3 @@
1
+ import type { ApiConfig } from '@ministryofjustice/hmpps-rest-client';
2
+ export interface MPoPComponentsConfig extends ApiConfig {
3
+ }
@@ -0,0 +1,11 @@
1
+ export type LatestTier = {
2
+ tierScore: string;
3
+ calculationId: string;
4
+ calculationDate: string;
5
+ changeReason: string;
6
+ provisional: boolean;
7
+ };
8
+ export type LatestTierResponse = {
9
+ calculation: LatestTier | null;
10
+ httpStatus: number;
11
+ };
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@ministryofjustice/hmpps-mpop-frontend-components-lib",
3
+ "version": "0.0.1",
4
+ "description": "MPOP front-end components library",
5
+ "main": "./dist/index.cjs.js",
6
+ "module": "./dist/index.esm.js",
7
+ "types": "./dist/index.d.ts",
8
+ "sass": "./dist/_all.scss",
9
+ "files": [
10
+ "dist/**/*"
11
+ ],
12
+ "scripts": {
13
+ "prepare": "hmpps-precommit-hooks-prepare",
14
+ "build": "rollup -c rollup.config.ts --bundleConfigAsCjs",
15
+ "clean": "rm -rf ./dist/ && find . -name '.eslintcache' -delete",
16
+ "test": "jest",
17
+ "test:coverage": "jest --coverage",
18
+ "test:ci": "jest --runInBand --passWithNoTests",
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint . --cache --max-warnings 0",
21
+ "lint:fix": "eslint . --cache --max-warnings 0 --fix",
22
+ "security_audit": "npx audit-ci --config audit-ci.json",
23
+ "setup": "npm ci && hmpps-npm-script-run-allowlist",
24
+ "preview": "tsx scripts/preview.ts",
25
+ "preview:api": "tsx scripts/preview-api.ts"
26
+ },
27
+ "lint-staged": {
28
+ "*.{ts,css}": [
29
+ "prettier --write",
30
+ "eslint --fix"
31
+ ],
32
+ "*.json": [
33
+ "prettier --write"
34
+ ]
35
+ },
36
+ "jest": {
37
+ "transform": {
38
+ "^.+\\.(ts|js|mjs|tsx|jsx)$": "babel-jest"
39
+ },
40
+ "transformIgnorePatterns": [
41
+ "/node_modules/(?!(@exodus|@csstools|jsdom|parse5|abab|entities|nunjucks|@asamuzakjp)/)"
42
+ ],
43
+ "testMatch": [
44
+ "<rootDir>/**/**/?(*.)(cy|test).{ts,js,jsx,mjs}"
45
+ ],
46
+ "testEnvironment": "node",
47
+ "moduleFileExtensions": [
48
+ "web.js",
49
+ "js",
50
+ "json",
51
+ "node",
52
+ "ts"
53
+ ]
54
+ },
55
+ "keywords": [],
56
+ "author": "",
57
+ "license": "ISC",
58
+ "devDependencies": {
59
+ "@babel/core": "^7.29.7",
60
+ "@babel/preset-env": "^7.29.7",
61
+ "@babel/preset-typescript": "^7.29.7",
62
+ "@ministryofjustice/eslint-config-hmpps": "1.0.3",
63
+ "@ministryofjustice/hmpps-npm-script-allowlist": "0.0.6",
64
+ "@ministryofjustice/hmpps-precommit-hooks": "3.0.1",
65
+ "@rollup/plugin-node-resolve": "^16.0.3",
66
+ "@rollup/plugin-typescript": "^12.3.0",
67
+ "@types/bunyan": "^1.8.11",
68
+ "@types/jest": "^30.0.0",
69
+ "@types/jsdom": "^28.0.3",
70
+ "@types/node": "25.9.1",
71
+ "@typescript-eslint/eslint-plugin": "8.60.1",
72
+ "babel-jest": "^30.4.1",
73
+ "dotenv": "17.4.2",
74
+ "eslint-import-resolver-typescript": "4.4.5",
75
+ "eslint-plugin-no-only-tests": "3.4.0",
76
+ "govuk-frontend": "^6.2.0",
77
+ "jest": "^30.4.2",
78
+ "jsdom": "^29.1.1",
79
+ "lint-staged": "17.0.7",
80
+ "nunjucks": "^3.2.4",
81
+ "prettier": "3.8.3",
82
+ "rollup": "^4.61.1",
83
+ "rollup-plugin-copy": "3.5.0",
84
+ "rollup-plugin-dts": "^6.4.1",
85
+ "tslib": "^2.8.1",
86
+ "tsx": "4.22.4",
87
+ "typescript": "^6.0.3"
88
+ },
89
+ "type": "commonjs",
90
+ "dependencies": {
91
+ "@ministryofjustice/hmpps-auth-clients": "^1.0.2",
92
+ "@ministryofjustice/hmpps-rest-client": "^1.2.1",
93
+ "@types/nunjucks": "3.2.6",
94
+ "sass": "^1.100.0"
95
+ }
96
+ }