@kenyaemr/esm-express-workflow-app 5.4.2-pre.2425 → 5.4.2-pre.2430

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/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"pages":[{"component":"root","route":"express-workflow"}],"extensions":[{"component":"accountingLeftPanelLink","name":"accounting-dashboard-link","slot":"express-workflow-left-panel-slot","order":10,"meta":{"name":"accounting","slot":"accounting-dashboard-slot","title":"Accounting"}},{"component":"accountingDashboard","name":"accounting-dashboard","slot":"accounting-dashboard-slot"},{"component":"admissionsLeftPanelLink","name":"admissions-dashboard-link","slot":"express-workflow-left-panel-slot","order":9,"meta":{"name":"admissions","slot":"admissions-dashboard-slot","title":"Admissions"}},{"component":"admissionsDashboard","name":"admissions-dashboard","slot":"admissions-dashboard-slot"},{"component":"consultationLeftPanelLink","name":"consultation-dashboard-link","slot":"express-workflow-left-panel-slot","order":3,"meta":{"name":"consultation","slot":"consultation-dashboard-slot","title":"Consultation"}},{"component":"consultationDashboard","name":"consultation-dashboard","slot":"consultation-dashboard-slot"},{"component":"facilityLeftPanelLink","name":"facility-dashboard-link","slot":"express-workflow-left-panel-slot","order":0,"meta":{"name":"dashboard","slot":"facility-dashboard-slot","title":"Dashboard"}},{"component":"facilityDashboard","name":"facility-dashboard","slot":"facility-dashboard-slot"},{"component":"laboratoryLeftPanelLink","name":"lab-dashboard-link","slot":"express-workflow-left-panel-slot","order":5,"meta":{"name":"lab","slot":"lab-dashboard-slot","title":"Lab"}},{"component":"labDashboard","name":"lab-dashboard","slot":"lab-dashboard-slot"},{"component":"mchLeftPanelLink","name":"mch-dashboard-link","slot":"express-workflow-left-panel-slot","order":4,"meta":{"name":"mch","slot":"mch-dashboard-slot","title":"MCH"}},{"component":"mchDashboard","name":"mch-dashboard","slot":"mch-dashboard-slot"},{"component":"pharmacyLeftPanelLink","name":"pharmacy-dashboard-link","slot":"express-workflow-left-panel-slot","order":7,"meta":{"name":"pharmacy","slot":"pharmacy-dashboard-slot","title":"Pharmacy"}},{"component":"pharmacyDashboard","name":"pharmacy-dashboard","slot":"pharmacy-dashboard-slot"},{"component":"proceduresLeftPanelLink","name":"procedures-dashboard-link","slot":"express-workflow-left-panel-slot","order":8,"meta":{"name":"procedures","slot":"procedures-dashboard-slot","title":"Procedures"}},{"component":"proceduresDashboard","name":"procedures-dashboard","slot":"procedures-dashboard-slot"},{"component":"radiologyLeftPanelLink","name":"radiology-dashboard-link","slot":"express-workflow-left-panel-slot","order":6,"meta":{"name":"radiology","slot":"radiology-dashboard-slot","title":"Radiology"}},{"component":"radiologyDashboard","name":"radiology-dashboard","slot":"radiology-dashboard-slot"},{"component":"registrationLeftPanelLink","name":"registration-dashboard-link","slot":"express-workflow-left-panel-slot","order":1,"meta":{"name":"registration","slot":"registration-dashboard-slot","title":"Registration"}},{"component":"registrationDashboard","name":"registration-dashboard","slot":"registration-dashboard-slot"},{"component":"reportsLeftPanelLink","name":"reports-dashboard-link","slot":"express-workflow-left-panel-slot","order":11,"meta":{"name":"reports","slot":"reports-dashboard-slot","title":"Reports"}},{"component":"reportsDashboard","name":"reports-dashboard","slot":"reports-dashboard-slot"},{"component":"triageLeftPanelLink","name":"triage-dashboard-link","slot":"express-workflow-left-panel-slot","order":2,"meta":{"name":"triage","slot":"triage-dashboard-slot","title":"Triage"}},{"component":"triageDashboard","name":"triage-dashboard","slot":"triage-dashboard-slot"},{"component":"visitFormBanner","name":"visit-form-banner","slot":"visit-form-header-slot","order":0}],"workspaces":[{"name":"express-workflow-workspace","component":"expressWorkflowWorkspace","title":"Express Workflow Workspace","type":"workspace","canMaximize":true,"canHide":true}],"modals":[],"workspaceGroups":[{"name":"express-workflow","members":["add-drug-order","order-basket","add-lab-order","express-workflow-workspace"]}],"version":"5.4.2-pre.2425"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"pages":[{"component":"root","route":"express-workflow"}],"extensions":[{"component":"accountingLeftPanelLink","name":"accounting-dashboard-link","slot":"express-workflow-left-panel-slot","order":10,"meta":{"name":"accounting","slot":"accounting-dashboard-slot","title":"Accounting"}},{"component":"accountingDashboard","name":"accounting-dashboard","slot":"accounting-dashboard-slot"},{"component":"admissionsLeftPanelLink","name":"admissions-dashboard-link","slot":"express-workflow-left-panel-slot","order":9,"meta":{"name":"admissions","slot":"admissions-dashboard-slot","title":"Admissions"}},{"component":"admissionsDashboard","name":"admissions-dashboard","slot":"admissions-dashboard-slot"},{"component":"consultationLeftPanelLink","name":"consultation-dashboard-link","slot":"express-workflow-left-panel-slot","order":3,"meta":{"name":"consultation","slot":"consultation-dashboard-slot","title":"Consultation"}},{"component":"consultationDashboard","name":"consultation-dashboard","slot":"consultation-dashboard-slot"},{"component":"facilityLeftPanelLink","name":"facility-dashboard-link","slot":"express-workflow-left-panel-slot","order":0,"meta":{"name":"dashboard","slot":"facility-dashboard-slot","title":"Dashboard"}},{"component":"facilityDashboard","name":"facility-dashboard","slot":"facility-dashboard-slot"},{"component":"laboratoryLeftPanelLink","name":"lab-dashboard-link","slot":"express-workflow-left-panel-slot","order":5,"meta":{"name":"laboratory","slot":"laboratory-dashboard-slot","title":"Lab"}},{"component":"laboratoryDashboard","name":"lab-dashboard","slot":"laboratory-dashboard-slot"},{"component":"mchLeftPanelLink","name":"mch-dashboard-link","slot":"express-workflow-left-panel-slot","order":4,"meta":{"name":"mch","slot":"mch-dashboard-slot","title":"MCH"}},{"component":"mchDashboard","name":"mch-dashboard","slot":"mch-dashboard-slot"},{"component":"pharmacyLeftPanelLink","name":"pharmacy-dashboard-link","slot":"express-workflow-left-panel-slot","order":7,"meta":{"name":"pharmacy","slot":"pharmacy-dashboard-slot","title":"Pharmacy"}},{"component":"pharmacyDashboard","name":"pharmacy-dashboard","slot":"pharmacy-dashboard-slot"},{"component":"proceduresLeftPanelLink","name":"procedures-dashboard-link","slot":"express-workflow-left-panel-slot","order":8,"meta":{"name":"procedures","slot":"procedures-dashboard-slot","title":"Procedures"}},{"component":"proceduresDashboard","name":"procedures-dashboard","slot":"procedures-dashboard-slot"},{"component":"radiologyLeftPanelLink","name":"radiology-dashboard-link","slot":"express-workflow-left-panel-slot","order":6,"meta":{"name":"radiology","slot":"radiology-dashboard-slot","title":"Radiology"}},{"component":"radiologyDashboard","name":"radiology-dashboard","slot":"radiology-dashboard-slot"},{"component":"registrationLeftPanelLink","name":"registration-dashboard-link","slot":"express-workflow-left-panel-slot","order":1,"meta":{"name":"registration","slot":"registration-dashboard-slot","title":"Registration"}},{"component":"registrationDashboard","name":"registration-dashboard","slot":"registration-dashboard-slot"},{"component":"reportsLeftPanelLink","name":"reports-dashboard-link","slot":"express-workflow-left-panel-slot","order":11,"meta":{"name":"reports","slot":"reports-dashboard-slot","title":"Reports"}},{"component":"reportsDashboard","name":"reports-dashboard","slot":"reports-dashboard-slot"},{"component":"triageLeftPanelLink","name":"triage-dashboard-link","slot":"express-workflow-left-panel-slot","order":2,"meta":{"name":"triage","slot":"triage-dashboard-slot","title":"Triage"}},{"component":"triageDashboard","name":"triage-dashboard","slot":"triage-dashboard-slot"},{"component":"visitFormBanner","name":"visit-form-banner","slot":"visit-form-header-slot","order":0}],"workspaces":[{"name":"express-workflow-workspace","component":"expressWorkflowWorkspace","title":"Express Workflow Workspace","type":"workspace","canMaximize":true,"canHide":true}],"modals":[{"component":"otpVerificationModal","name":"otp-verification-modal"}],"workspaceGroups":[{"name":"express-workflow","members":["add-drug-order","order-basket","add-lab-order","express-workflow-workspace"]}],"version":"5.4.2-pre.2430"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-express-workflow-app",
3
- "version": "5.4.2-pre.2425",
3
+ "version": "5.4.2-pre.2430",
4
4
  "description": "Express workflow app for OpenMRS 3",
5
5
  "browser": "dist/kenyaemr-esm-express-workflow-app.js",
6
6
  "main": "src/index.ts",
@@ -43,6 +43,7 @@
43
43
  "classnames": "^2.3.2",
44
44
  "lodash-es": "^4.17.15",
45
45
  "react-hook-form": "^7.54.0",
46
+ "react-otp-input": "^3.1.1",
46
47
  "zod": "^3.24.1"
47
48
  },
48
49
  "peerDependencies": {
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export * from './components/reports';
29
29
  export * from './shared/express-workflow-workspace';
30
30
 
31
31
  export const root = getAsyncLifecycle(() => import('./root.component'), options);
32
+ export const otpVerificationModal = getAsyncLifecycle(() => import('./shared-components/otp-verification'), options);
32
33
 
33
34
  // t('visitFormBanner', 'Visit Form Banner')
34
35
  export const visitFormBanner = getAsyncLifecycle(
package/src/routes.json CHANGED
@@ -81,15 +81,15 @@
81
81
  "slot": "express-workflow-left-panel-slot",
82
82
  "order": 5,
83
83
  "meta": {
84
- "name": "lab",
85
- "slot": "lab-dashboard-slot",
84
+ "name": "laboratory",
85
+ "slot": "laboratory-dashboard-slot",
86
86
  "title": "Lab"
87
87
  }
88
88
  },
89
89
  {
90
- "component": "labDashboard",
90
+ "component": "laboratoryDashboard",
91
91
  "name": "lab-dashboard",
92
- "slot": "lab-dashboard-slot"
92
+ "slot": "laboratory-dashboard-slot"
93
93
  },
94
94
  {
95
95
  "component": "mchLeftPanelLink",
@@ -220,7 +220,12 @@
220
220
  "canHide": true
221
221
  }
222
222
  ],
223
- "modals": [],
223
+ "modals": [
224
+ {
225
+ "component": "otpVerificationModal",
226
+ "name": "otp-verification-modal"
227
+ }
228
+ ],
224
229
  "workspaceGroups": [
225
230
  {
226
231
  "name": "express-workflow",
@@ -0,0 +1,65 @@
1
+ import { showModal } from '@openmrs/esm-framework';
2
+ import { default as otpverificationModal } from './otp-verification.modal';
3
+ /**
4
+ * Options for configuring the OTP Verification modal.
5
+ *
6
+ * @property {number} [otpLength] - The number of digits required for the OTP. Defaults to implementation-specific value.
7
+ * @property {(otp: string) => Promise<void>} [onVerify] - Callback invoked when the user submits the OTP. Should return a promise that resolves on successful verification.
8
+ * @property {boolean} [obsecureText] - If true, the OTP input will be obscured (e.g., password-style input).
9
+ * @property {boolean} [centerBoxes] - If true, OTP input boxes will be centered in the modal.
10
+ * @property {string} phoneNumber - The phone number to which the OTP will be sent.
11
+ * @property {(phoneNumber: string) => React.ReactNode} renderOtpTrigger - Function to render a custom component for triggering OTP requests.
12
+ * @property {(phoneNumber: string) => Promise<void>} [onRequestOtp] - Callback invoked to request a new OTP for the given phone number. Should return a promise.
13
+ * @property {() => void} [onVerificationSuccess] - Callback invoked when OTP verification succeeds.
14
+ *
15
+ * @example
16
+ * <Button
17
+ * onClick={() =>
18
+ * lauchOtpVerificationModal({
19
+ * otpLength: 4,
20
+ * obsecureText: false,
21
+ * phoneNumber: '254700000000',
22
+ * renderOtpTrigger: (p) => (
23
+ * <>
24
+ * <p>Any customcomponents here {p}</p>
25
+ * </>
26
+ * ),
27
+ * onRequestOtp: (phone) =>
28
+ * new Promise((resolve, reject) => {
29
+ * const success = false;
30
+ * setTimeout(() => (success ? resolve() : reject(new Error('Some error'))), 3000);
31
+ * }),
32
+ * onVerify: async (otp) =>
33
+ * new Promise((resolve, reject) => {
34
+ * const success = false;
35
+ * setTimeout(() => (success ? resolve() : reject(new Error('Some error'))), 3000);
36
+ * }),
37
+ * })
38
+ * }
39
+ * >
40
+ * Launch Otp verification Modal
41
+ * </Button>
42
+ */
43
+ export type OTPVerificationmodalOptions = {
44
+ otpLength?: number;
45
+ onVerify?: (otp: string) => Promise<void>;
46
+ obsecureText?: boolean;
47
+ centerBoxes?: boolean;
48
+ phoneNumber: string;
49
+ renderOtpTrigger: (phoneNumber: string) => React.ReactNode;
50
+ onRequestOtp?: (phoneNumber: string) => Promise<void>;
51
+ onVerificationSuccess?: () => void;
52
+ };
53
+
54
+ /**
55
+ *
56
+ *
57
+ */
58
+ export const lauchOtpVerificationModal = (props: OTPVerificationmodalOptions) => {
59
+ const dispose = showModal('otp-verification-modal', {
60
+ onClose: () => dispose(),
61
+ size: 'xs',
62
+ ...props,
63
+ });
64
+ };
65
+ export default otpverificationModal;
@@ -0,0 +1,163 @@
1
+ import {
2
+ Button,
3
+ ButtonSet,
4
+ InlineLoading,
5
+ InlineNotification,
6
+ ModalBody,
7
+ ModalFooter,
8
+ ModalHeader,
9
+ Tabs,
10
+ TextInput,
11
+ Tile,
12
+ } from '@carbon/react';
13
+ import React, { FC, useState } from 'react';
14
+ import { useTranslation } from 'react-i18next';
15
+ import styles from './otp-verification.scss';
16
+ import PinPut from '../pin-put/pinput.component';
17
+ import { Phone } from '@carbon/react/icons';
18
+ export const PHONE_NUMBER_REGEX = /^(\+?254|0)((7|1)\d{8})$/;
19
+
20
+ type OTPVerificationModalProps = {
21
+ onClose?: () => void;
22
+ otpLength?: number;
23
+ onVerify?: (otp: string) => Promise<void>;
24
+ onVerificationSuccess?: () => void;
25
+ obsecureText?: boolean;
26
+ centerBoxes?: boolean;
27
+ phoneNumber: string;
28
+ renderOtpTrigger: (phoneNumber: string) => React.ReactNode;
29
+ onRequestOtp?: (phoneNumber: string) => Promise<void>;
30
+ };
31
+
32
+ const OTPVerificationModal: FC<OTPVerificationModalProps> = ({
33
+ onClose,
34
+ onVerify,
35
+ otpLength = 5,
36
+ centerBoxes,
37
+ obsecureText,
38
+ phoneNumber,
39
+ renderOtpTrigger,
40
+ onRequestOtp,
41
+ onVerificationSuccess,
42
+ }) => {
43
+ const { t } = useTranslation();
44
+ const [otp, setOtp] = useState('');
45
+ const [newPhoneNumber, setNewPhoneNumber] = useState('');
46
+ const [isLoading, setIsLoading] = useState(false);
47
+ const [error, setError] = useState<{ type: 'request' | 'verification'; error: Error } | null>(null);
48
+ const [mode, setMode] = useState<'landing' | 'verify-otp' | 'change-number'>('landing');
49
+ const [requestingOtp, setRequestingOtp] = useState(false);
50
+ const handleVerify = async () => {
51
+ setError(null);
52
+ try {
53
+ setIsLoading(true);
54
+ await onVerify?.(otp);
55
+ onClose();
56
+ onVerificationSuccess?.();
57
+ } catch (error) {
58
+ setError({ type: 'verification', error });
59
+ } finally {
60
+ setIsLoading(false);
61
+ }
62
+ };
63
+
64
+ const handleRequestingOtp = async (phone: string) => {
65
+ setError(null);
66
+
67
+ try {
68
+ setRequestingOtp(true);
69
+ await onRequestOtp(phone);
70
+ setMode('verify-otp');
71
+ } catch (error) {
72
+ setError({ type: 'request', error });
73
+ } finally {
74
+ setRequestingOtp(false);
75
+ }
76
+ };
77
+ return (
78
+ <React.Fragment>
79
+ <ModalHeader className={styles.sectionHeader} closeModal={onClose}>
80
+ {t('otpVerification', 'OTP Verification')}
81
+ </ModalHeader>
82
+ <ModalBody>
83
+ {requestingOtp && <InlineLoading />}
84
+ {!requestingOtp && (
85
+ <div>
86
+ {error && (
87
+ <>
88
+ <InlineNotification
89
+ lowContrast
90
+ title={
91
+ error?.type === 'request'
92
+ ? t('otpRequestError', 'Error requesting OTP')
93
+ : t('otpVerificationError', 'Error Verifying OTP')
94
+ }
95
+ subtitle={error?.error?.message}
96
+ />
97
+ <br />
98
+ </>
99
+ )}
100
+ {mode === 'landing' ? (
101
+ <Tile role="button" onClick={() => handleRequestingOtp(phoneNumber)}>
102
+ {renderOtpTrigger(phoneNumber)}
103
+ </Tile>
104
+ ) : mode === 'verify-otp' ? (
105
+ <PinPut
106
+ value={otp}
107
+ onChange={setOtp}
108
+ numInputs={otpLength}
109
+ centerBoxes={centerBoxes}
110
+ obsecureText={obsecureText}
111
+ />
112
+ ) : null}
113
+ {mode === 'landing' && (
114
+ <>
115
+ <br />
116
+ <Button
117
+ className={styles.changeNoBtn}
118
+ size="sm"
119
+ onClick={() => setMode('change-number')}
120
+ kind="tertiary"
121
+ renderIcon={Phone}>
122
+ {t('changePhoneNumber', 'Change phone number')}
123
+ </Button>
124
+ </>
125
+ )}
126
+ {mode === 'change-number' && (
127
+ <TextInput
128
+ id={'otp-phone-number'}
129
+ labelText={t('phoneNumber', 'Phone number')}
130
+ value={newPhoneNumber}
131
+ onChange={(ev) => setNewPhoneNumber(ev.target.value)}
132
+ />
133
+ )}
134
+ </div>
135
+ )}
136
+ </ModalBody>
137
+ <ModalFooter>
138
+ <ButtonSet className={styles.buttonSet}>
139
+ <Button kind="secondary" onClick={onClose} className={styles.button}>
140
+ {t('cancel', 'Cancel')}
141
+ </Button>
142
+ {mode !== 'change-number' ? (
143
+ <Button
144
+ disabled={isLoading || otp.length !== otpLength}
145
+ kind="primary"
146
+ onClick={handleVerify}
147
+ className={styles.button}>
148
+ {isLoading ? <InlineLoading title={t('verifyingOtp', 'Verifying OTP')} /> : t('verify', 'Verify')}
149
+ </Button>
150
+ ) : (
151
+ <Button
152
+ disabled={!PHONE_NUMBER_REGEX.test(newPhoneNumber)}
153
+ onClick={() => handleRequestingOtp(newPhoneNumber)}>
154
+ {t('sendOtp', 'Send OTP')}
155
+ </Button>
156
+ )}
157
+ </ButtonSet>
158
+ </ModalFooter>
159
+ </React.Fragment>
160
+ );
161
+ };
162
+
163
+ export default OTPVerificationModal;
@@ -0,0 +1,29 @@
1
+ @use '@carbon/type';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/colors';
4
+
5
+ .button {
6
+ height: layout.$spacing-10;
7
+ display: flex;
8
+ align-content: flex-start;
9
+ align-items: baseline;
10
+ min-width: 20%;
11
+ }
12
+
13
+ .buttonSet {
14
+ padding: 0rem;
15
+ margin-top: layout.$spacing-05;
16
+ display: flex;
17
+ justify-content: space-between;
18
+ width: 100%;
19
+ margin-bottom: layout.$spacing-05;
20
+ }
21
+
22
+ .sectionHeader {
23
+ @include type.type-style('heading-02');
24
+ }
25
+
26
+ .changeNoBtn {
27
+ width: 100%;
28
+ min-height: 100%;
29
+ }
@@ -0,0 +1,31 @@
1
+ import classNames from 'classnames';
2
+ import React from 'react';
3
+ import OtpInput, { OTPInputProps } from 'react-otp-input';
4
+ import styles from './pinput.scss';
5
+
6
+ type Props = Partial<Omit<OTPInputProps, 'inputType' | 'renderInput' | 'containerStyle'>> & {
7
+ obsecureText?: boolean;
8
+ centerBoxes?: boolean;
9
+ label?: string;
10
+ };
11
+
12
+ const PinPut = ({ numInputs = 5, centerBoxes, obsecureText, label, ...props }: Props) => {
13
+ return (
14
+ <div className={styles.container}>
15
+ {label && <p className={styles.label}> {label}</p>}
16
+ <OtpInput
17
+ renderSeparator={<span>-</span>}
18
+ {...props}
19
+ inputType={obsecureText ? 'password' : 'text'}
20
+ numInputs={numInputs}
21
+ renderInput={(props) => <input {...props} className={classNames(props.className, styles.input)} />}
22
+ skipDefaultStyles
23
+ value={props.value ?? ''}
24
+ onChange={props.onChange}
25
+ containerStyle={{ gap: '4px', justifyContent: centerBoxes ? 'center' : undefined }}
26
+ />
27
+ </div>
28
+ );
29
+ };
30
+
31
+ export default PinPut;
@@ -0,0 +1,22 @@
1
+ @use '@carbon/type';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/colors';
4
+
5
+ .input {
6
+ border-radius: layout.$spacing-03;
7
+ padding: layout.$spacing-03;
8
+ width: 40px;
9
+ font-weight: bold;
10
+ text-align: center;
11
+ }
12
+
13
+ .container {
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: layout.$spacing-03;
17
+ }
18
+
19
+ .label {
20
+ @include type.type-style('heading-01');
21
+ font-weight: normal;
22
+ }
@@ -2,22 +2,46 @@
2
2
  "age": "Age",
3
3
  "awaitingConsultation": "Awaiting consultation",
4
4
  "awaitingInvestigation": "Awaiting Investigation",
5
+ "cancel": "Cancel",
6
+ "changePhoneNumber": "Change phone number",
7
+ "chooseIdentifierType": "Choose identifier type",
8
+ "clearAll": "Clear All",
9
+ "clientRegistry": "Client registry verification",
10
+ "emergencyRegistration": "Emergency registration",
11
+ "enterIdentifierNumber": "Enter identifier number",
12
+ "error": "Error",
5
13
  "errorLoadingPatient": "Error loading patient",
6
14
  "gender": "Gender",
15
+ "identificationType": "Identification Type",
7
16
  "identifier": "Identifier",
17
+ "identifierNumber": "Identifier number*",
8
18
  "investigationComplete": "Investigation complete",
9
19
  "loadingPatient": "Loading patient...",
10
20
  "loadingQueues": "Loading queues...",
11
21
  "name": "Name",
12
22
  "nextPage": "Next page",
13
23
  "noQueueEntries": "No queue entries found",
24
+ "otpRequestError": "Error requesting OTP",
25
+ "otpVerification": "OTP Verification",
26
+ "otpVerificationError": "Error Verifying OTP",
14
27
  "patientAttended": "Patient attended",
15
28
  "patientInWaiting": "Patient in waiting",
29
+ "phoneNumber": "Phone number",
16
30
  "previousPage": "Previous page",
17
31
  "priority": "Priority",
18
32
  "programManagement": "Program Management",
33
+ "pullFromHIE": "Pulling from registry...",
19
34
  "queueEntries": "Queue Entries",
35
+ "registration": "Registration",
36
+ "searchFailed": "Failed to search for patient. Please try again.",
37
+ "searchPatients": "Search for Patient(s)",
38
+ "selectIdentifierAndNumber": "Please select an identifier type and enter an identifier number",
39
+ "sendOtp": "Send OTP",
40
+ "validationError": "Validation Error",
41
+ "verify": "Verify",
42
+ "verifyingOtp": "Verifying OTP",
20
43
  "visitComplete": "Visit complete",
44
+ "visitFormBanner": "Visit Form Banner",
21
45
  "visitTime": "Visit Time",
22
46
  "vitalsAndAnthropometrics": "Vitals and Anthropometrics"
23
47
  }
@@ -2,22 +2,46 @@
2
2
  "age": "Age",
3
3
  "awaitingConsultation": "Awaiting consultation",
4
4
  "awaitingInvestigation": "Awaiting Investigation",
5
+ "cancel": "Cancel",
6
+ "changePhoneNumber": "Change phone number",
7
+ "chooseIdentifierType": "Choose identifier type",
8
+ "clearAll": "Clear All",
9
+ "clientRegistry": "Client registry verification",
10
+ "emergencyRegistration": "Emergency registration",
11
+ "enterIdentifierNumber": "Enter identifier number",
12
+ "error": "Error",
5
13
  "errorLoadingPatient": "Error loading patient",
6
14
  "gender": "Gender",
15
+ "identificationType": "Identification Type",
7
16
  "identifier": "Identifier",
17
+ "identifierNumber": "Identifier number*",
8
18
  "investigationComplete": "Investigation complete",
9
19
  "loadingPatient": "Loading patient...",
10
20
  "loadingQueues": "Loading queues...",
11
21
  "name": "Name",
12
22
  "nextPage": "Next page",
13
23
  "noQueueEntries": "No queue entries found",
24
+ "otpRequestError": "Error requesting OTP",
25
+ "otpVerification": "OTP Verification",
26
+ "otpVerificationError": "Error Verifying OTP",
14
27
  "patientAttended": "Patient attended",
15
28
  "patientInWaiting": "Patient in waiting",
29
+ "phoneNumber": "Phone number",
16
30
  "previousPage": "Previous page",
17
31
  "priority": "Priority",
18
32
  "programManagement": "Program Management",
33
+ "pullFromHIE": "Pulling from registry...",
19
34
  "queueEntries": "Queue Entries",
35
+ "registration": "Registration",
36
+ "searchFailed": "Failed to search for patient. Please try again.",
37
+ "searchPatients": "Search for Patient(s)",
38
+ "selectIdentifierAndNumber": "Please select an identifier type and enter an identifier number",
39
+ "sendOtp": "Send OTP",
40
+ "validationError": "Validation Error",
41
+ "verify": "Verify",
42
+ "verifyingOtp": "Verifying OTP",
20
43
  "visitComplete": "Visit complete",
44
+ "visitFormBanner": "Visit Form Banner",
21
45
  "visitTime": "Visit Time",
22
46
  "vitalsAndAnthropometrics": "Vitals and Anthropometrics"
23
47
  }
@@ -2,22 +2,46 @@
2
2
  "age": "Age",
3
3
  "awaitingConsultation": "Awaiting consultation",
4
4
  "awaitingInvestigation": "Awaiting Investigation",
5
+ "cancel": "Cancel",
6
+ "changePhoneNumber": "Change phone number",
7
+ "chooseIdentifierType": "Choose identifier type",
8
+ "clearAll": "Clear All",
9
+ "clientRegistry": "Client registry verification",
10
+ "emergencyRegistration": "Emergency registration",
11
+ "enterIdentifierNumber": "Enter identifier number",
12
+ "error": "Error",
5
13
  "errorLoadingPatient": "Error loading patient",
6
14
  "gender": "Gender",
15
+ "identificationType": "Identification Type",
7
16
  "identifier": "Identifier",
17
+ "identifierNumber": "Identifier number*",
8
18
  "investigationComplete": "Investigation complete",
9
19
  "loadingPatient": "Loading patient...",
10
20
  "loadingQueues": "Loading queues...",
11
21
  "name": "Name",
12
22
  "nextPage": "Next page",
13
23
  "noQueueEntries": "No queue entries found",
24
+ "otpRequestError": "Error requesting OTP",
25
+ "otpVerification": "OTP Verification",
26
+ "otpVerificationError": "Error Verifying OTP",
14
27
  "patientAttended": "Patient attended",
15
28
  "patientInWaiting": "Patient in waiting",
29
+ "phoneNumber": "Phone number",
16
30
  "previousPage": "Previous page",
17
31
  "priority": "Priority",
18
32
  "programManagement": "Program Management",
33
+ "pullFromHIE": "Pulling from registry...",
19
34
  "queueEntries": "Queue Entries",
35
+ "registration": "Registration",
36
+ "searchFailed": "Failed to search for patient. Please try again.",
37
+ "searchPatients": "Search for Patient(s)",
38
+ "selectIdentifierAndNumber": "Please select an identifier type and enter an identifier number",
39
+ "sendOtp": "Send OTP",
40
+ "validationError": "Validation Error",
41
+ "verify": "Verify",
42
+ "verifyingOtp": "Verifying OTP",
20
43
  "visitComplete": "Visit complete",
44
+ "visitFormBanner": "Visit Form Banner",
21
45
  "visitTime": "Visit Time",
22
46
  "vitalsAndAnthropometrics": "Vitals and Anthropometrics"
23
47
  }