@ministryofjustice/hmpps-connect-dps-shared-items 4.4.0 → 5.1.0
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 +8 -6
- package/dist/alertFlags/alertTypes.d.ts +25 -0
- package/dist/alertFlags/alertTypes.test.d.ts +1 -0
- package/dist/alertFlags/getAlertFlagLabelsForAlerts.d.ts +4 -2
- package/dist/assets/dps/components/address-autosuggest/_address-autosuggest.scss +9 -10
- package/dist/assets/dps/components/address-autosuggest/abortable-fetch.js +40 -46
- package/dist/assets/dps/components/address-autosuggest/autosuggest-address.js +74 -85
- package/dist/assets/dps/components/address-autosuggest/autosuggest-ui.js +343 -383
- package/dist/assets/dps/components/address-autosuggest/index.js +9 -8
- package/dist/assets/dps/components/alert-flag/_alert-flag.scss +8 -5
- package/dist/assets/dps/components/alert-flag/macro.njk +1 -1
- package/dist/assets/dps/components/modal/_index.scss +148 -0
- package/dist/assets/dps/components/modal/index.js +171 -0
- package/dist/assets/dps/components/modal/index.ts +203 -0
- package/dist/assets/dps/components/modal/macro.njk +48 -0
- package/dist/assets/dps/components/webcam-capture/_webcam-capture.scss +11 -10
- package/dist/assets/dps/components/webcam-capture/index.js +126 -149
- package/dist/assets/dps/components/webcam-capture/macro.njk +10 -26
- package/dist/assets/js/all.js +10 -5
- package/dist/assets/scss/all.css +844 -0
- package/dist/assets/scss/all.scss +4 -3
- package/dist/index.cjs +57 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.esm.js +56 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/types/public/alertFlags/index.d.ts +1 -0
- package/package.json +18 -7
- package/dist/assets/dps/components/_common.scss +0 -21
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ npm install @ministryofjustice/hmpps-connect-dps-shared-items
|
|
|
27
27
|
Add the `hmpps-connect-dps-shared-items` assets directory to nunjucks configuration in your application:
|
|
28
28
|
|
|
29
29
|
```javascript
|
|
30
|
-
|
|
30
|
+
const njkEnv = nunjucks.configure(
|
|
31
31
|
[
|
|
32
32
|
path.join(__dirname, '../../server/views'),
|
|
33
33
|
...,
|
|
@@ -48,11 +48,11 @@ then import the component into your nunjucks file:
|
|
|
48
48
|
### Styling
|
|
49
49
|
Include the package scss within the `index.scss` file. You can either import all:
|
|
50
50
|
```scss
|
|
51
|
-
|
|
51
|
+
@import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/scss/all';
|
|
52
52
|
```
|
|
53
53
|
or import the specific component scss you are using, e.g:
|
|
54
54
|
```scss
|
|
55
|
-
|
|
55
|
+
@import 'node_modules/@ministryofjustice/hmpps-connect-dps-shared-items/dist/assets/dps/components/alert-flag/alert-flag';
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
### Client side javascript
|
|
@@ -66,10 +66,12 @@ connectDps.initAll()
|
|
|
66
66
|
|
|
67
67
|
## Library Components:
|
|
68
68
|
|
|
69
|
-
1. [
|
|
70
|
-
2. [
|
|
71
|
-
3. [
|
|
69
|
+
1. [Address Autosuggest](readme/components/addressAutosuggest/address-autosuggest.md)
|
|
70
|
+
2. [Alert Flag](readme/components/alertFlag/alert-flag.md)
|
|
71
|
+
3. [Modal](readme/components/modal/modal.md)
|
|
72
|
+
4. [Webcam Upload](readme/components/webcamCapture/webcam-capture.md)
|
|
72
73
|
|
|
73
74
|
## For Library Developers
|
|
74
75
|
|
|
75
76
|
1. [Publishing to NPM](readme/publishing.md)
|
|
77
|
+
2. To preview all components locally, run `npm run build` and then `npm start`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Alert types that have a DPS alert flag style */
|
|
2
|
+
export declare enum AlertType {
|
|
3
|
+
/** Care leaver */
|
|
4
|
+
CareLeaver = "care-leaver",
|
|
5
|
+
/** Ex-armed forces */
|
|
6
|
+
ExArmedForces = "ex-armed-forces",
|
|
7
|
+
/** MAPPP */
|
|
8
|
+
MAPPP = "MAPPP-case",
|
|
9
|
+
/** Medical */
|
|
10
|
+
Medical = "medical",
|
|
11
|
+
/** Risk */
|
|
12
|
+
Risk = "risk",
|
|
13
|
+
/** Security */
|
|
14
|
+
Security = "security",
|
|
15
|
+
/** Self harm */
|
|
16
|
+
SelfHarm = "self-harm",
|
|
17
|
+
/** Vulnerability */
|
|
18
|
+
Vulnerability = "vulnerability",
|
|
19
|
+
/** Other */
|
|
20
|
+
Other = "other"
|
|
21
|
+
}
|
|
22
|
+
/** Find an alert type that has a DPS alert flag style given an alert type code */
|
|
23
|
+
export declare function getAlertTypeForCode(typeCode: string): AlertType | undefined;
|
|
24
|
+
/** Returns the classes for use with the DPS alert flag component (ie. the `AlertFlagLabel.classes` property) */
|
|
25
|
+
export declare function getAlertFlagCssClasses(alertType: AlertType): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { Alert } from '../types/public/alertFlags/Alert';
|
|
2
|
-
import { AlertFlagLabel } from '../types/public/alertFlags/AlertFlagLabel';
|
|
1
|
+
import type { Alert } from '../types/public/alertFlags/Alert';
|
|
2
|
+
import type { AlertFlagLabel } from '../types/public/alertFlags/AlertFlagLabel';
|
|
3
|
+
/** Alerts that need to be flagged prominently */
|
|
3
4
|
export declare const alertFlagLabels: AlertFlagLabel[];
|
|
5
|
+
/** Returns alert flags that should be displayed prominently */
|
|
4
6
|
export declare function getAlertFlagLabelsForAlerts(prisonerAlerts: Alert[]): AlertFlagLabel[];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
@
|
|
2
|
-
@import 'govuk-frontend/dist/govuk/settings/colours-applied';
|
|
1
|
+
@use "govuk-frontend/dist/govuk/helpers/colour";
|
|
3
2
|
|
|
4
3
|
.hmpps-address-autosuggest {
|
|
5
4
|
position: relative;
|
|
@@ -15,7 +14,7 @@
|
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
&__results {
|
|
18
|
-
border: 1px solid
|
|
17
|
+
border: 1px solid colour.govuk-functional-colour(border);
|
|
19
18
|
border-radius: 3px;
|
|
20
19
|
display: none;
|
|
21
20
|
margin: 0 0 0;
|
|
@@ -25,13 +24,13 @@
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
&__results-title {
|
|
28
|
-
background: govuk-colour("
|
|
29
|
-
border-bottom: 1px solid
|
|
27
|
+
background: colour.govuk-colour("black", $variant: "tint-95");
|
|
28
|
+
border-bottom: 1px solid colour.govuk-functional-colour(border);
|
|
30
29
|
padding: 0.25rem 0.5rem;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
&__listbox {
|
|
34
|
-
background: govuk-colour("white");
|
|
33
|
+
background: colour.govuk-colour("white");
|
|
35
34
|
list-style: none;
|
|
36
35
|
margin: 0;
|
|
37
36
|
padding: 0;
|
|
@@ -47,22 +46,22 @@
|
|
|
47
46
|
padding: 0.25rem 0.5rem;
|
|
48
47
|
|
|
49
48
|
&:not(:last-child) {
|
|
50
|
-
border-bottom: 1px solid
|
|
49
|
+
border-bottom: 1px solid colour.govuk-functional-colour(border);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
&--focused:not(&--no-results) {
|
|
54
53
|
background: #1d70b8;
|
|
55
54
|
border-color: #1d70b8;
|
|
56
|
-
color: govuk-colour("white");
|
|
55
|
+
color: colour.govuk-colour("white");
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
&:active:not(&--no-results) {
|
|
60
59
|
background: var(--ons-color-focus);
|
|
61
|
-
color: govuk-colour("black");
|
|
60
|
+
color: colour.govuk-colour("black");
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
&--no-results {
|
|
65
|
-
background: govuk-colour("
|
|
64
|
+
background: colour.govuk-colour("black", $variant: "tint-95");
|
|
66
65
|
cursor: not-allowed;
|
|
67
66
|
padding: 0.25rem 0.5rem;
|
|
68
67
|
}
|
|
@@ -1,51 +1,45 @@
|
|
|
1
1
|
// Based on ONSDigital's https://github.com/ONSdigital/design-system/blob/main/src/js/abortable-fetch.js
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export const abortError = 'AbortError'
|
|
10
|
-
export const abortTimeout = 'AbortTimeout'
|
|
11
|
-
|
|
2
|
+
const FetchStatus = {
|
|
3
|
+
unsent: 'UNSENT',
|
|
4
|
+
loading: 'LOADING',
|
|
5
|
+
done: 'DONE',
|
|
6
|
+
};
|
|
7
|
+
const abortError = 'AbortError';
|
|
8
|
+
const abortTimeout = 'AbortTimeout';
|
|
12
9
|
class AbortableFetch {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
10
|
+
constructor(url, options) {
|
|
11
|
+
this.url = url;
|
|
12
|
+
this.controller = new window.AbortController();
|
|
13
|
+
this.status = FetchStatus.unsent;
|
|
14
|
+
this.fetchDelay = options?.fetchDelay || 500;
|
|
15
|
+
}
|
|
16
|
+
async send() {
|
|
17
|
+
this.status = FetchStatus.loading;
|
|
18
|
+
try {
|
|
19
|
+
// Abortable delay before querying the API to limit the rate of requests when someone is typing:
|
|
20
|
+
await new Promise((resolve) => {
|
|
21
|
+
setTimeout(resolve, this.fetchDelay);
|
|
22
|
+
this.controller.signal.addEventListener('abort', () => { resolve(); }, { once: true });
|
|
23
|
+
});
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
this.controller.abort(abortTimeout);
|
|
26
|
+
}, 5000);
|
|
27
|
+
const response = await window.fetch(this.url, { signal: this.controller.signal });
|
|
28
|
+
if (!(+response.status === 200)) {
|
|
29
|
+
const error = new Error(`API error: ${response?.status ?? 500}`);
|
|
30
|
+
error.response = response;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
this.status = FetchStatus.done;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
abort() {
|
|
40
|
+
this.controller.abort();
|
|
43
41
|
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
abort() {
|
|
47
|
-
this.controller.abort()
|
|
48
|
-
}
|
|
49
42
|
}
|
|
43
|
+
const abortableFetch = (url, options) => new AbortableFetch(url, options);
|
|
50
44
|
|
|
51
|
-
export
|
|
45
|
+
export { FetchStatus, abortError, abortTimeout, abortableFetch };
|
|
@@ -1,91 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { abortableFetch, abortError, FetchStatus } from './abortable-fetch'
|
|
4
|
-
|
|
5
|
-
const classUPRN = 'hmpps-js-uprn'
|
|
6
|
-
const classInputContainer = 'hmpps-address-autosuggest'
|
|
7
|
-
const classInput = 'hmpps-js-autosuggest-input'
|
|
8
|
-
|
|
9
|
-
export class AutosuggestAddress {
|
|
10
|
-
constructor(context) {
|
|
11
|
-
this.context = context
|
|
12
|
-
this.input = context.querySelector(`.${classInput}`)
|
|
13
|
-
this.container = context.querySelector(`.${classInputContainer}`)
|
|
14
|
-
this.uprn = context.querySelector(`.${classUPRN}`)
|
|
15
|
-
this.findUrl = this.container.getAttribute('data-find-url')
|
|
16
|
-
this.fetchDelay = this.container.getAttribute('data-fetch-delay')
|
|
17
|
-
|
|
18
|
-
// State:
|
|
19
|
-
this.fetch = null
|
|
20
|
-
|
|
21
|
-
// Initialise autosuggest:
|
|
22
|
-
this.autosuggest = new AutosuggestUi({
|
|
23
|
-
context: this.container,
|
|
24
|
-
onSelect: this.onAddressSelect.bind(this),
|
|
25
|
-
suggestionFunction: this.suggestAddresses.bind(this),
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
// Check API status:
|
|
29
|
-
this.checkAPIStatus()
|
|
30
|
-
}
|
|
1
|
+
import { AutosuggestUi, NoResults } from './autosuggest-ui.js';
|
|
2
|
+
import { abortableFetch, abortError, FetchStatus } from './abortable-fetch.js';
|
|
31
3
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
|
|
4
|
+
// Based on ONSDigital's https://github.com/ONSdigital/design-system/blob/main/src/components/address-input/autosuggest.address.js
|
|
5
|
+
const classUPRN = 'hmpps-js-uprn';
|
|
6
|
+
const classInputContainer = 'hmpps-address-autosuggest';
|
|
7
|
+
const classInput = 'hmpps-js-autosuggest-input';
|
|
8
|
+
class AutosuggestAddress {
|
|
9
|
+
constructor(context) {
|
|
10
|
+
this.context = context;
|
|
11
|
+
this.input = context.querySelector(`.${classInput}`);
|
|
12
|
+
this.container = context.querySelector(`.${classInputContainer}`);
|
|
13
|
+
this.uprn = context.querySelector(`.${classUPRN}`);
|
|
14
|
+
this.findUrl = this.container.getAttribute('data-find-url');
|
|
15
|
+
this.fetchDelay = this.container.getAttribute('data-fetch-delay');
|
|
16
|
+
// State:
|
|
17
|
+
this.fetch = null;
|
|
18
|
+
// Initialise autosuggest:
|
|
19
|
+
this.autosuggest = new AutosuggestUi({
|
|
20
|
+
context: this.container,
|
|
21
|
+
onSelect: this.onAddressSelect.bind(this),
|
|
22
|
+
suggestionFunction: this.suggestAddresses.bind(this),
|
|
23
|
+
});
|
|
24
|
+
// Check API status:
|
|
25
|
+
this.checkAPIStatus();
|
|
45
26
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
async checkAPIStatus() {
|
|
28
|
+
this.fetch = abortableFetch(`${this.findUrl}/SW1H9AJ`, { fetchDelay: this.fetchDelay });
|
|
29
|
+
try {
|
|
30
|
+
const response = await this.fetch.send();
|
|
31
|
+
const status = response && (await response.json()).status;
|
|
32
|
+
if (status !== 200) {
|
|
33
|
+
this.autosuggest.handleNoResults(NoResults.server_error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error.name !== abortError) {
|
|
38
|
+
this.autosuggest.handleNoResults(NoResults.server_error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
51
41
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
async findAddress(query) {
|
|
60
|
-
this.fetch = abortableFetch(`${this.findUrl}/${query}`, { fetchDelay: this.fetchDelay })
|
|
61
|
-
const data = await this.fetch.send()
|
|
62
|
-
const response = await data.json()
|
|
63
|
-
const status = response.status
|
|
64
|
-
const addresses = response.results
|
|
65
|
-
return this.mapFindResults(addresses, status)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
mapFindResults(results, status) {
|
|
69
|
-
if (!results) return { status }
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
results: this.addressMapping(results),
|
|
73
|
-
status: status,
|
|
42
|
+
async suggestAddresses(query) {
|
|
43
|
+
if (this.fetch && this.fetch.status !== FetchStatus.done) {
|
|
44
|
+
this.fetch.abort();
|
|
45
|
+
}
|
|
46
|
+
// Reset any previously selected result:
|
|
47
|
+
this.uprn.value = '';
|
|
48
|
+
return await this.findAddress(query?.replace(/[^A-Z0-9-.' ]/gi, ''));
|
|
74
49
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
50
|
+
async findAddress(query) {
|
|
51
|
+
this.fetch = abortableFetch(`${this.findUrl}/${query}`, { fetchDelay: this.fetchDelay });
|
|
52
|
+
const data = await this.fetch.send();
|
|
53
|
+
const response = await data.json();
|
|
54
|
+
const status = response.status;
|
|
55
|
+
const addresses = response.results;
|
|
56
|
+
return this.mapFindResults(addresses, status);
|
|
57
|
+
}
|
|
58
|
+
mapFindResults(results, status) {
|
|
59
|
+
if (!results)
|
|
60
|
+
return { status };
|
|
61
|
+
return {
|
|
62
|
+
results: this.addressMapping(results),
|
|
63
|
+
status: status,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
addressMapping(addresses) {
|
|
67
|
+
if (!addresses?.length)
|
|
68
|
+
return [];
|
|
69
|
+
return addresses.map(address => ({ uprn: address.uprn, displayText: address.addressString }));
|
|
70
|
+
}
|
|
71
|
+
async onAddressSelect(selectedResult) {
|
|
72
|
+
if (this.fetch && this.fetch.status !== FetchStatus.done) {
|
|
73
|
+
this.fetch.abort();
|
|
74
|
+
}
|
|
75
|
+
this.autosuggest.input.value = selectedResult.displayText;
|
|
76
|
+
this.uprn.value = selectedResult.uprn;
|
|
86
77
|
}
|
|
87
|
-
|
|
88
|
-
this.autosuggest.input.value = selectedResult.displayText
|
|
89
|
-
this.uprn.value = selectedResult.uprn
|
|
90
|
-
}
|
|
91
78
|
}
|
|
79
|
+
|
|
80
|
+
export { AutosuggestAddress };
|