@ministryofjustice/hmpps-connect-dps-shared-items 5.1.0 → 5.2.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/dist/assets/dps/components/address-autosuggest/_address-autosuggest.scss +7 -0
- package/dist/assets/dps/components/address-autosuggest/abortable-fetch.d.ts +26 -0
- package/dist/assets/dps/components/address-autosuggest/abortable-fetch.js +20 -8
- package/dist/assets/dps/components/address-autosuggest/abortable-fetch.ts +76 -0
- package/dist/assets/dps/components/address-autosuggest/autosuggest-address.d.ts +18 -0
- package/dist/assets/dps/components/address-autosuggest/autosuggest-address.js +27 -13
- package/dist/assets/dps/components/address-autosuggest/autosuggest-address.ts +108 -0
- package/dist/assets/dps/components/address-autosuggest/autosuggest-ui.d.ts +82 -0
- package/dist/assets/dps/components/address-autosuggest/autosuggest-ui.js +83 -53
- package/dist/assets/dps/components/address-autosuggest/autosuggest-ui.ts +459 -0
- package/dist/assets/dps/components/address-autosuggest/index.d.ts +1 -0
- package/dist/assets/dps/components/address-autosuggest/index.js +4 -4
- package/dist/assets/dps/components/address-autosuggest/index.ts +9 -0
- package/dist/assets/dps/components/alert-flag/_alert-flag.scss +2 -1
- package/dist/assets/dps/components/modal/index.d.ts +34 -0
- package/dist/assets/dps/components/modal/macro.njk +2 -1
- package/dist/assets/dps/components/webcam-capture/_webcam-capture.scss +2 -2
- package/dist/assets/dps/components/webcam-capture/index.d.ts +1 -0
- package/dist/assets/dps/components/webcam-capture/index.js +14 -8
- package/dist/assets/dps/components/webcam-capture/index.ts +165 -0
- package/dist/assets/js/all.d.ts +1 -0
- package/dist/assets/js/all.ts +10 -0
- package/dist/assets/scss/all.css +66 -16
- package/dist/index.d.ts +10 -1
- package/dist/types/public/addressAutosuggest/addressAutosuggestResponse.d.ts +9 -0
- package/package.json +4 -4
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
function hmppsWebcamCapture(component: HTMLElement): Promise<void> {
|
|
2
|
+
const video = document.getElementById('hmpps-webcam__webcam') as HTMLVideoElement
|
|
3
|
+
const captureBtn = document.getElementById('hmpps-webcam__captureImageButton') as HTMLButtonElement
|
|
4
|
+
const clearImageBtn = document.getElementById('hmpps-webcam__clearImageButton') as HTMLButtonElement
|
|
5
|
+
const snapshot = document.getElementById('hmpps-webcam__snapshot') as HTMLImageElement
|
|
6
|
+
const webcamImageFileInput = document.getElementById('hmpps-webcam__webcam-image-input') as HTMLInputElement
|
|
7
|
+
const webcamSelect = document.getElementById('hmpps-webcam__select-webcam') as HTMLSelectElement
|
|
8
|
+
const webcamSelectFormGroup = document.getElementById('hmpps-webcam__webcam-select-form-group') as HTMLDivElement
|
|
9
|
+
const webcamSubmit = document.getElementById('hmpps-webcam__webcam-submit') as HTMLButtonElement
|
|
10
|
+
const webcamPlaceholder = document.getElementById('hmpps-webcam__webcam-placeholder') as HTMLDivElement
|
|
11
|
+
const fileName = component.dataset.fileName ?? 'webcam-capture'
|
|
12
|
+
const enableReporting = component.dataset.reportErrors === 'true'
|
|
13
|
+
|
|
14
|
+
// Permissions
|
|
15
|
+
const permissionRequested = document.getElementById('hmpps-webcam__permission-requested') as HTMLParagraphElement
|
|
16
|
+
const permissionGranted = document.getElementById('hmpps-webcam__permission-granted') as HTMLDivElement
|
|
17
|
+
|
|
18
|
+
// Preview elements
|
|
19
|
+
const photoPreviewContainer = document.getElementById('hmpps-webcam__photo-preview-container') as HTMLDivElement
|
|
20
|
+
const photoCaptureContainer = document.getElementById('hmpps-webcam__photo-capture-container') as HTMLDivElement
|
|
21
|
+
const photoCaptureErrorContainer = document.getElementById(
|
|
22
|
+
'hmpps-webcam__photo-capture-container__error',
|
|
23
|
+
) as HTMLDivElement
|
|
24
|
+
|
|
25
|
+
const mimetype = 'image/jpeg'
|
|
26
|
+
|
|
27
|
+
let stream: MediaStream | null = null
|
|
28
|
+
|
|
29
|
+
function updateWebcamList(activeDeviceId: string): void {
|
|
30
|
+
webcamSelect.querySelectorAll('option').forEach(option => {
|
|
31
|
+
if (option.value === activeDeviceId && option.label.indexOf('- Active') === -1) {
|
|
32
|
+
// eslint-disable-next-line no-param-reassign
|
|
33
|
+
option.label = `${option.label} - Active`
|
|
34
|
+
} else if (option.value !== activeDeviceId && option.label.indexOf('- Active') > -1) {
|
|
35
|
+
// eslint-disable-next-line no-param-reassign
|
|
36
|
+
option.label = option.label.replace(' - Active', '')
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function getWebcamList(): Promise<void> {
|
|
42
|
+
// get camera permissions
|
|
43
|
+
try {
|
|
44
|
+
permissionRequested.style.display = 'block'
|
|
45
|
+
await navigator.mediaDevices.getUserMedia({ video: true, audio: false })
|
|
46
|
+
|
|
47
|
+
navigator.mediaDevices.enumerateDevices().then(devices => {
|
|
48
|
+
const videoDevices = devices.filter(device => device.kind === 'videoinput')
|
|
49
|
+
|
|
50
|
+
videoDevices.forEach((device, index) => {
|
|
51
|
+
const option = document.createElement('option')
|
|
52
|
+
option.value = device.deviceId
|
|
53
|
+
option.text = device.label || `Camera ${index + 1}`
|
|
54
|
+
webcamSelect.appendChild(option)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if (videoDevices.length < 2) {
|
|
58
|
+
webcamSelectFormGroup.style.display = 'none'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (videoDevices.length > 0) {
|
|
62
|
+
startWebcam(videoDevices[0].deviceId)
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
} catch (e) {
|
|
66
|
+
photoCaptureContainer.style.display = 'none'
|
|
67
|
+
photoCaptureErrorContainer.style.display = 'block'
|
|
68
|
+
if (enableReporting) {
|
|
69
|
+
// @ts-expect-error error type is not known
|
|
70
|
+
const error = 'name' in e ? e.name : e.message
|
|
71
|
+
// eslint-disable-next-line no-restricted-globals
|
|
72
|
+
await fetch(`/api/report-error?pageUrl=${encodeURIComponent(location.href)}&error=${error}`, {
|
|
73
|
+
method: 'GET',
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function stopWebcam(): void {
|
|
80
|
+
if (stream) {
|
|
81
|
+
stream.getTracks().forEach(track => track.stop())
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function startWebcam(deviceId: string): Promise<void> {
|
|
86
|
+
try {
|
|
87
|
+
stopWebcam()
|
|
88
|
+
stream = await navigator.mediaDevices.getUserMedia({
|
|
89
|
+
video: {
|
|
90
|
+
deviceId: { exact: deviceId },
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
video.srcObject = stream
|
|
94
|
+
permissionRequested.style.display = 'none'
|
|
95
|
+
permissionGranted.style.display = 'block'
|
|
96
|
+
webcamPlaceholder.style.display = 'none'
|
|
97
|
+
video.style.display = 'block'
|
|
98
|
+
captureBtn.disabled = false
|
|
99
|
+
updateWebcamList(deviceId)
|
|
100
|
+
} catch (error) {
|
|
101
|
+
permissionRequested.style.display = 'none'
|
|
102
|
+
photoCaptureContainer.style.display = 'none'
|
|
103
|
+
photoCaptureErrorContainer.style.display = 'block'
|
|
104
|
+
// eslint-disable-next-line no-console
|
|
105
|
+
console.error('Webcam error:', error)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
webcamSelect.addEventListener('change', (): void => {
|
|
110
|
+
startWebcam(webcamSelect.value)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
clearImageBtn.addEventListener('click', (): void => {
|
|
114
|
+
snapshot.src = ''
|
|
115
|
+
|
|
116
|
+
photoPreviewContainer.style.display = 'none'
|
|
117
|
+
photoCaptureContainer.style.display = 'block'
|
|
118
|
+
webcamSubmit.disabled = true
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
captureBtn.addEventListener('click', (): void => {
|
|
122
|
+
const canvas = document.createElement('canvas')
|
|
123
|
+
canvas.width = video.videoWidth
|
|
124
|
+
canvas.height = video.videoHeight
|
|
125
|
+
const ctx = canvas.getContext('2d')!
|
|
126
|
+
|
|
127
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
|
|
128
|
+
|
|
129
|
+
snapshot.src = canvas.toDataURL(mimetype)
|
|
130
|
+
|
|
131
|
+
canvas.toBlob(
|
|
132
|
+
blob => {
|
|
133
|
+
if (!blob) return
|
|
134
|
+
|
|
135
|
+
const file = new File([blob], `${fileName}.jpg`, { type: mimetype })
|
|
136
|
+
|
|
137
|
+
const dataTransfer = new DataTransfer()
|
|
138
|
+
dataTransfer.items.add(file)
|
|
139
|
+
webcamImageFileInput.files = dataTransfer.files
|
|
140
|
+
},
|
|
141
|
+
mimetype,
|
|
142
|
+
0.92,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
photoPreviewContainer.style.display = 'block'
|
|
146
|
+
photoCaptureContainer.style.display = 'none'
|
|
147
|
+
webcamSubmit.disabled = false
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
function pageInit(): Promise<void> {
|
|
151
|
+
photoPreviewContainer.style.display = 'none'
|
|
152
|
+
photoCaptureContainer.style.display = 'block'
|
|
153
|
+
return getWebcamList()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return pageInit()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
160
|
+
export function init(): void {
|
|
161
|
+
const webcamContainer = document.getElementById('hmpps-webcam-capture-component')
|
|
162
|
+
if (webcamContainer) {
|
|
163
|
+
hmppsWebcamCapture(webcamContainer)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initAll(): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as addressAutosuggest from '../dps/components/address-autosuggest'
|
|
2
|
+
import { Modal } from '../dps/components/modal'
|
|
3
|
+
import * as webcamCapture from '../dps/components/webcam-capture'
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
6
|
+
export function initAll() {
|
|
7
|
+
addressAutosuggest.init()
|
|
8
|
+
Modal.init()
|
|
9
|
+
webcamCapture.init()
|
|
10
|
+
}
|
package/dist/assets/scss/all.css
CHANGED
|
@@ -4,11 +4,33 @@
|
|
|
4
4
|
border: 3px solid;
|
|
5
5
|
padding: 5px 10px;
|
|
6
6
|
height: initial;
|
|
7
|
-
font-size: 16px;
|
|
8
7
|
text-align: center;
|
|
9
8
|
line-height: 1;
|
|
10
9
|
user-select: none;
|
|
11
10
|
border-radius: 5px;
|
|
11
|
+
font-family: "GDS Transport", arial, sans-serif;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
/*! Copyright (c) 2011 by Margaret Calvert & Henrik Kubel. All rights reserved. The font has been customised for exclusive use on gov.uk. This cut is not commercially available. */ /* stylelint-disable-line scss/comment-no-loud */
|
|
16
|
+
@font-face {
|
|
17
|
+
font-family: "GDS Transport";
|
|
18
|
+
font-style: normal;
|
|
19
|
+
font-weight: normal;
|
|
20
|
+
font-display: fallback;
|
|
21
|
+
src: url("/assets/fonts/light-94a07e06a1-v2.woff2") format("woff2"), url("/assets/fonts/light-f591b13f7d-v2.woff") format("woff");
|
|
22
|
+
}
|
|
23
|
+
@font-face {
|
|
24
|
+
font-family: "GDS Transport";
|
|
25
|
+
font-style: normal;
|
|
26
|
+
font-weight: bold;
|
|
27
|
+
font-display: fallback;
|
|
28
|
+
src: url("/assets/fonts/bold-b542beb274-v2.woff2") format("woff2"), url("/assets/fonts/bold-affa96571d-v2.woff") format("woff");
|
|
29
|
+
}
|
|
30
|
+
.dps-alert-status {
|
|
31
|
+
font-weight: 400;
|
|
32
|
+
font-size: 1rem;
|
|
33
|
+
line-height: 1.25;
|
|
12
34
|
}
|
|
13
35
|
}
|
|
14
36
|
@media print {
|
|
@@ -497,6 +519,9 @@ a.dps-alert-status--visor:focus {
|
|
|
497
519
|
position: relative;
|
|
498
520
|
max-width: 630px;
|
|
499
521
|
}
|
|
522
|
+
.hmpps-address-autosuggest .hmpps-display-none {
|
|
523
|
+
display: none;
|
|
524
|
+
}
|
|
500
525
|
.hmpps-address-autosuggest .govuk-form-group {
|
|
501
526
|
margin-bottom: 10px;
|
|
502
527
|
}
|
|
@@ -517,6 +542,25 @@ a.dps-alert-status--visor:focus {
|
|
|
517
542
|
background: #f3f3f3;
|
|
518
543
|
border-bottom: 1px solid var(--govuk-border-colour, #cecece);
|
|
519
544
|
padding: 0.25rem 0.5rem;
|
|
545
|
+
font-family: "GDS Transport", arial, sans-serif;
|
|
546
|
+
-webkit-font-smoothing: antialiased;
|
|
547
|
+
-moz-osx-font-smoothing: grayscale;
|
|
548
|
+
}
|
|
549
|
+
@media print {
|
|
550
|
+
.hmpps-address-autosuggest__results-title {
|
|
551
|
+
font-family: sans-serif;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
.hmpps-address-autosuggest__results-title {
|
|
555
|
+
font-weight: 400;
|
|
556
|
+
font-size: 1.1875rem;
|
|
557
|
+
line-height: 1.3157894737;
|
|
558
|
+
}
|
|
559
|
+
@media print {
|
|
560
|
+
.hmpps-address-autosuggest__results-title {
|
|
561
|
+
font-size: 14pt;
|
|
562
|
+
line-height: 1.15;
|
|
563
|
+
}
|
|
520
564
|
}
|
|
521
565
|
.hmpps-address-autosuggest__listbox {
|
|
522
566
|
background: #ffffff;
|
|
@@ -527,6 +571,27 @@ a.dps-alert-status--visor:focus {
|
|
|
527
571
|
.hmpps-address-autosuggest__listbox:focus {
|
|
528
572
|
outline: none;
|
|
529
573
|
}
|
|
574
|
+
.hmpps-address-autosuggest__listbox {
|
|
575
|
+
font-family: "GDS Transport", arial, sans-serif;
|
|
576
|
+
-webkit-font-smoothing: antialiased;
|
|
577
|
+
-moz-osx-font-smoothing: grayscale;
|
|
578
|
+
}
|
|
579
|
+
@media print {
|
|
580
|
+
.hmpps-address-autosuggest__listbox {
|
|
581
|
+
font-family: sans-serif;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
.hmpps-address-autosuggest__listbox {
|
|
585
|
+
font-weight: 400;
|
|
586
|
+
font-size: 1.1875rem;
|
|
587
|
+
line-height: 1.3157894737;
|
|
588
|
+
}
|
|
589
|
+
@media print {
|
|
590
|
+
.hmpps-address-autosuggest__listbox {
|
|
591
|
+
font-size: 14pt;
|
|
592
|
+
line-height: 1.15;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
530
595
|
.hmpps-address-autosuggest__option {
|
|
531
596
|
cursor: pointer;
|
|
532
597
|
margin: 0;
|
|
@@ -620,21 +685,6 @@ a.dps-alert-status--visor:focus {
|
|
|
620
685
|
-webkit-font-smoothing: antialiased;
|
|
621
686
|
-moz-osx-font-smoothing: grayscale;
|
|
622
687
|
}
|
|
623
|
-
/*! Copyright (c) 2011 by Margaret Calvert & Henrik Kubel. All rights reserved. The font has been customised for exclusive use on gov.uk. This cut is not commercially available. */ /* stylelint-disable-line scss/comment-no-loud */
|
|
624
|
-
@font-face {
|
|
625
|
-
font-family: "GDS Transport";
|
|
626
|
-
font-style: normal;
|
|
627
|
-
font-weight: normal;
|
|
628
|
-
font-display: fallback;
|
|
629
|
-
src: url("/assets/fonts/light-94a07e06a1-v2.woff2") format("woff2"), url("/assets/fonts/light-f591b13f7d-v2.woff") format("woff");
|
|
630
|
-
}
|
|
631
|
-
@font-face {
|
|
632
|
-
font-family: "GDS Transport";
|
|
633
|
-
font-style: normal;
|
|
634
|
-
font-weight: bold;
|
|
635
|
-
font-display: fallback;
|
|
636
|
-
src: url("/assets/fonts/bold-b542beb274-v2.woff2") format("woff2"), url("/assets/fonts/bold-affa96571d-v2.woff") format("woff");
|
|
637
|
-
}
|
|
638
688
|
@media print {
|
|
639
689
|
.hmpps-modal__dialogue-box header h1 {
|
|
640
690
|
font-family: sans-serif;
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,15 @@ interface OsAddress {
|
|
|
19
19
|
uprn?: number;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** The JSON payload expected by the Address Autosuggest component when loading suggestions */
|
|
23
|
+
type AddressAutosuggestResponse = {
|
|
24
|
+
status: number;
|
|
25
|
+
results: OsAddress[];
|
|
26
|
+
} | {
|
|
27
|
+
status: number;
|
|
28
|
+
error: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
22
31
|
interface OsPlacesQueryResponse {
|
|
23
32
|
header: OsPlacesResponseHeader;
|
|
24
33
|
results: OsPlacesQueryResult[];
|
|
@@ -279,4 +288,4 @@ declare const alertFlagLabels: AlertFlagLabel[];
|
|
|
279
288
|
declare function getAlertFlagLabelsForAlerts(prisonerAlerts: Alert[]): AlertFlagLabel[];
|
|
280
289
|
|
|
281
290
|
export { AlertType, OsPlacesAddressService, OsPlacesApiClient, alertFlagLabels, getAlertFlagCssClasses, getAlertFlagLabelsForAlerts, getAlertTypeForCode };
|
|
282
|
-
export type { Alert, AlertFlagLabel, AlertsServiceAlert, BasicAlert, ConnectDpsComponentLogger, OsAddress, OsPlacesDeliveryPointAddress, OsPlacesLandPropertyIdentifier, OsPlacesQueryResponse, OsPlacesQueryResult, OsPlacesResponseHeader, PrisonApiAlert };
|
|
291
|
+
export type { AddressAutosuggestResponse, Alert, AlertFlagLabel, AlertsServiceAlert, BasicAlert, ConnectDpsComponentLogger, OsAddress, OsPlacesDeliveryPointAddress, OsPlacesLandPropertyIdentifier, OsPlacesQueryResponse, OsPlacesQueryResult, OsPlacesResponseHeader, PrisonApiAlert };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OsAddress } from './osAddress';
|
|
2
|
+
/** The JSON payload expected by the Address Autosuggest component when loading suggestions */
|
|
3
|
+
export type AddressAutosuggestResponse = {
|
|
4
|
+
status: number;
|
|
5
|
+
results: OsAddress[];
|
|
6
|
+
} | {
|
|
7
|
+
status: number;
|
|
8
|
+
error: string;
|
|
9
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ministryofjustice/hmpps-connect-dps-shared-items",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "A package to share Connect DPS functionality across applications",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"precommit:lint": "lint-staged",
|
|
27
27
|
"precommit:verify": "npm run typecheck && npm test",
|
|
28
28
|
"setup": "npm ci && hmpps-npm-script-run-allowlist",
|
|
29
|
-
"start": "node --experimental-strip-types preview/
|
|
29
|
+
"start": "node --experimental-strip-types preview/server.mts"
|
|
30
30
|
},
|
|
31
31
|
"lint-staged": {
|
|
32
32
|
"*.{ts,css}": [
|
|
@@ -67,11 +67,11 @@
|
|
|
67
67
|
"lint-staged": "^17.2.0",
|
|
68
68
|
"nock": "14.0.17",
|
|
69
69
|
"nunjucks": "3.2.4",
|
|
70
|
-
"rollup": "4.62.
|
|
70
|
+
"rollup": "4.62.5",
|
|
71
71
|
"rollup-plugin-copy": "3.5.0",
|
|
72
72
|
"rollup-plugin-dts": "6.5.1",
|
|
73
73
|
"rollup-plugin-scss": "4.0.1",
|
|
74
|
-
"sass": "1.
|
|
74
|
+
"sass": "1.103.1",
|
|
75
75
|
"ts-jest": "29.4.12",
|
|
76
76
|
"tslib": "^2.8.1",
|
|
77
77
|
"typescript": "6.0.3"
|