@openmrs/esm-appointments-app 10.0.2 → 10.0.3-pre.2

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.
Files changed (392) hide show
  1. package/.turbo/turbo-build.log +6 -5
  2. package/dist/1339.js +1 -0
  3. package/dist/1339.js.map +1 -0
  4. package/dist/1465.js +1 -0
  5. package/dist/1465.js.map +1 -0
  6. package/dist/1480.js +1 -0
  7. package/dist/1480.js.map +1 -0
  8. package/dist/1646.js +1 -0
  9. package/dist/1646.js.map +1 -0
  10. package/dist/1789.js +1 -0
  11. package/dist/1789.js.map +1 -0
  12. package/dist/1869.js +1 -0
  13. package/dist/1869.js.map +1 -0
  14. package/dist/1877.js +1 -0
  15. package/dist/1877.js.map +1 -0
  16. package/dist/1884.js +1 -0
  17. package/dist/1884.js.map +1 -0
  18. package/dist/1962.js +1 -0
  19. package/dist/1962.js.map +1 -0
  20. package/dist/2317.js +1 -0
  21. package/dist/2317.js.map +1 -0
  22. package/dist/2416.js +1 -0
  23. package/dist/2416.js.map +1 -0
  24. package/dist/2495.js +1 -0
  25. package/dist/2495.js.map +1 -0
  26. package/dist/2539.js +1 -0
  27. package/dist/2539.js.map +1 -0
  28. package/dist/2620.js +1 -0
  29. package/dist/2620.js.map +1 -0
  30. package/dist/2717.js +1 -0
  31. package/dist/2717.js.map +1 -0
  32. package/dist/282.js +1 -0
  33. package/dist/282.js.map +1 -0
  34. package/dist/2881.js +1 -0
  35. package/dist/2881.js.map +1 -0
  36. package/dist/3198.js +11 -0
  37. package/dist/3198.js.map +1 -0
  38. package/dist/3220.js +1 -0
  39. package/dist/3220.js.map +1 -0
  40. package/dist/3378.js +1 -0
  41. package/dist/3378.js.map +1 -0
  42. package/dist/3720.js +1 -0
  43. package/dist/3720.js.map +1 -0
  44. package/dist/3930.js +1 -0
  45. package/dist/3930.js.map +1 -0
  46. package/dist/3963.js +1 -0
  47. package/dist/3963.js.map +1 -0
  48. package/dist/3989.js +1 -0
  49. package/dist/3989.js.map +1 -0
  50. package/dist/4106.js +1 -0
  51. package/dist/4106.js.map +1 -0
  52. package/dist/4111.js +1 -0
  53. package/dist/4111.js.map +1 -0
  54. package/dist/4307.js +1 -0
  55. package/dist/4307.js.map +1 -0
  56. package/dist/434.js +1 -0
  57. package/dist/434.js.map +1 -0
  58. package/dist/4348.js +1 -0
  59. package/dist/4348.js.map +1 -0
  60. package/dist/4383.js +1 -0
  61. package/dist/4383.js.map +1 -0
  62. package/dist/4658.js +1 -0
  63. package/dist/4658.js.map +1 -0
  64. package/dist/466.js +1 -0
  65. package/dist/466.js.map +1 -0
  66. package/dist/4928.js +1 -0
  67. package/dist/4928.js.map +1 -0
  68. package/dist/5117.js +1 -0
  69. package/dist/5117.js.map +1 -0
  70. package/dist/5132.js +1 -0
  71. package/dist/5132.js.map +1 -0
  72. package/dist/5145.js +1 -0
  73. package/dist/5145.js.map +1 -0
  74. package/dist/5503.js +1 -0
  75. package/dist/5503.js.map +1 -0
  76. package/dist/556.js +1 -0
  77. package/dist/556.js.map +1 -0
  78. package/dist/5640.js +1 -0
  79. package/dist/5640.js.map +1 -0
  80. package/dist/5644.js +1 -0
  81. package/dist/5644.js.map +1 -0
  82. package/dist/5940.js +1 -0
  83. package/dist/5940.js.map +1 -0
  84. package/dist/6047.js +1 -0
  85. package/dist/6047.js.map +1 -0
  86. package/dist/6098.js +38 -0
  87. package/dist/6098.js.map +1 -0
  88. package/dist/6236.js +1 -0
  89. package/dist/6236.js.map +1 -0
  90. package/dist/635.js +1 -0
  91. package/dist/635.js.map +1 -0
  92. package/dist/6371.js +1 -0
  93. package/dist/6371.js.map +1 -0
  94. package/dist/6377.js +1 -0
  95. package/dist/6377.js.map +1 -0
  96. package/dist/6444.js +1 -0
  97. package/dist/6444.js.map +1 -0
  98. package/dist/6508.js +1 -0
  99. package/dist/6508.js.map +1 -0
  100. package/dist/6724.js +1 -0
  101. package/dist/6724.js.map +1 -0
  102. package/dist/6789.js +1 -0
  103. package/dist/6789.js.map +1 -0
  104. package/dist/689.js +1 -0
  105. package/dist/689.js.map +1 -0
  106. package/dist/6904.js +1 -0
  107. package/dist/6904.js.map +1 -0
  108. package/dist/7045.js +1 -0
  109. package/dist/7045.js.map +1 -0
  110. package/dist/7138.js +1 -0
  111. package/dist/7138.js.map +1 -0
  112. package/dist/7159.js +1 -0
  113. package/dist/7159.js.map +1 -0
  114. package/dist/7175.js +1 -0
  115. package/dist/7175.js.map +1 -0
  116. package/dist/7182.js +1 -0
  117. package/dist/7182.js.map +1 -0
  118. package/dist/7357.js +1 -0
  119. package/dist/7357.js.map +1 -0
  120. package/dist/7609.js +1 -0
  121. package/dist/7609.js.map +1 -0
  122. package/dist/7654.js +1 -0
  123. package/dist/7654.js.map +1 -0
  124. package/dist/7742.js +1 -0
  125. package/dist/7742.js.map +1 -0
  126. package/dist/7912.js +1 -0
  127. package/dist/7912.js.map +1 -0
  128. package/dist/8063.js +1 -0
  129. package/dist/8063.js.map +1 -0
  130. package/dist/8346.js +1 -0
  131. package/dist/8346.js.map +1 -0
  132. package/dist/8358.js +1 -0
  133. package/dist/8358.js.map +1 -0
  134. package/dist/8359.js +1 -0
  135. package/dist/8359.js.map +1 -0
  136. package/dist/8695.js +1 -0
  137. package/dist/8695.js.map +1 -0
  138. package/dist/8937.js +1 -0
  139. package/dist/8937.js.map +1 -0
  140. package/dist/8981.js +1 -0
  141. package/dist/8981.js.map +1 -0
  142. package/dist/903.js +1 -0
  143. package/dist/903.js.map +1 -0
  144. package/dist/9061.js +1 -0
  145. package/dist/9061.js.map +1 -0
  146. package/dist/9072.js +1 -0
  147. package/dist/9072.js.map +1 -0
  148. package/dist/9282.js +1 -0
  149. package/dist/9282.js.map +1 -0
  150. package/dist/9399.js +1 -0
  151. package/dist/9399.js.map +1 -0
  152. package/dist/9443.js +1 -0
  153. package/dist/9443.js.map +1 -0
  154. package/dist/9581.js +1 -0
  155. package/dist/9581.js.map +1 -0
  156. package/dist/9712.js +1 -0
  157. package/dist/9712.js.map +1 -0
  158. package/dist/9771.js +1 -0
  159. package/dist/9771.js.map +1 -0
  160. package/dist/9806.js +1 -0
  161. package/dist/9806.js.map +1 -0
  162. package/dist/main.js +6 -5
  163. package/dist/main.js.map +1 -1
  164. package/dist/openmrs-esm-appointments-app.js +6 -5
  165. package/dist/openmrs-esm-appointments-app.js.buildmanifest.json +625 -620
  166. package/dist/openmrs-esm-appointments-app.js.map +1 -1
  167. package/dist/routes.json +1 -1
  168. package/package.json +3 -2
  169. package/src/appointments/appointment-tabs.component.tsx +38 -16
  170. package/src/appointments/common-components/appointments-actions.component.tsx +39 -47
  171. package/src/appointments/common-components/appointments-actions.test.tsx +52 -99
  172. package/src/appointments/common-components/appointments-table.component.tsx +109 -135
  173. package/src/appointments/common-components/appointments-table.scss +10 -6
  174. package/src/appointments/common-components/appointments-table.test.tsx +2 -9
  175. package/src/appointments/common-components/batch-change-appointment-statuses.modal.tsx +1 -1
  176. package/src/appointments/common-components/batch-change-appointment-statuses.test.tsx +8 -6
  177. package/src/appointments/common-components/checkin-button.component.tsx +60 -29
  178. package/src/appointments/common-components/end-appointment.modal.tsx +1 -1
  179. package/src/appointments/common-components/end-appointment.test.tsx +1 -1
  180. package/src/appointments/scheduled/early-appointments.component.tsx +6 -7
  181. package/src/appointments/scheduled/scheduled-appointments.component.tsx +26 -206
  182. package/src/appointments/utils.tsx +29 -16
  183. package/src/appointments.component.tsx +5 -13
  184. package/src/appointments.test.tsx +16 -4
  185. package/src/calendar/appointments-calendar-view.component.tsx +3 -12
  186. package/src/calendar/appointments-calendar-view.test.tsx +6 -1
  187. package/src/calendar/header/calendar-header.component.tsx +2 -2
  188. package/src/calendar/monthly/monthly-calendar-view.component.tsx +2 -2
  189. package/src/calendar/monthly/monthly-header.component.tsx +9 -8
  190. package/src/calendar/monthly/monthly-workload-view.component.tsx +2 -2
  191. package/src/config-schema.ts +17 -9
  192. package/src/constants.ts +12 -1
  193. package/src/dashboard.meta.ts +1 -1
  194. package/src/form/appointments-form.resource.ts +1 -120
  195. package/src/form/appointments-form.workspace.tsx +15 -18
  196. package/src/header/appointments-header.component.tsx +27 -9
  197. package/src/helpers/functions.ts +1 -50
  198. package/src/home/home-appointments.component.tsx +17 -4
  199. package/src/hooks/useActiveVisits.ts +14 -0
  200. package/src/hooks/useAppointmentList.ts +12 -29
  201. package/src/hooks/useAppointmentService.ts +6 -1
  202. package/src/hooks/useAppointmentsAppContext.ts +19 -0
  203. package/src/hooks/useAppointmentsCalendar.ts +2 -1
  204. package/src/hooks/useMutateAppointments.ts +24 -0
  205. package/src/hooks/usePatientAppointmentHistory.ts +3 -2
  206. package/src/hooks/useSelectedDate.ts +24 -0
  207. package/src/hooks/useUnscheduledAppointments.ts +5 -1
  208. package/src/index.ts +0 -21
  209. package/src/metrics/metrics-cards/highest-volume-service.extension.tsx +27 -6
  210. package/src/metrics/metrics-cards/metrics-card.component.tsx +2 -1
  211. package/src/metrics/metrics-cards/providers-booked.extension.tsx +14 -6
  212. package/src/metrics/metrics-cards/scheduled-appointments.extension.tsx +20 -16
  213. package/src/metrics/metrics-container.component.tsx +1 -5
  214. package/src/metrics/metrics-header.component.tsx +2 -2
  215. package/src/patient-appointments/patient-appointments-detailed-summary.extension.tsx +1 -1
  216. package/src/patient-appointments/patient-upcoming-appointments-card.component.tsx +3 -4
  217. package/src/routes.json +3 -27
  218. package/src/store.ts +24 -41
  219. package/src/types/index.ts +7 -0
  220. package/src/workload/monthly-view-workload/monthly-view.component.tsx +2 -2
  221. package/src/workload/workload.component.tsx +3 -3
  222. package/src/workload/workload.resource.ts +1 -1
  223. package/translations/am.json +15 -6
  224. package/translations/ar.json +15 -6
  225. package/translations/ar_SY.json +15 -6
  226. package/translations/bn.json +15 -6
  227. package/translations/cs.json +15 -6
  228. package/translations/de.json +177 -168
  229. package/translations/en.json +15 -6
  230. package/translations/en_US.json +15 -6
  231. package/translations/es.json +15 -6
  232. package/translations/es_MX.json +15 -6
  233. package/translations/fr.json +15 -6
  234. package/translations/he.json +15 -6
  235. package/translations/hi.json +15 -6
  236. package/translations/hi_IN.json +15 -6
  237. package/translations/id.json +15 -6
  238. package/translations/it.json +15 -6
  239. package/translations/ka.json +15 -6
  240. package/translations/km.json +15 -6
  241. package/translations/ku.json +15 -6
  242. package/translations/ky.json +15 -6
  243. package/translations/lg.json +15 -6
  244. package/translations/ne.json +15 -6
  245. package/translations/pl.json +15 -6
  246. package/translations/pt.json +15 -6
  247. package/translations/pt_BR.json +15 -6
  248. package/translations/qu.json +15 -6
  249. package/translations/ro_RO.json +15 -6
  250. package/translations/ru_RU.json +15 -6
  251. package/translations/si.json +15 -6
  252. package/translations/sq.json +15 -6
  253. package/translations/sw.json +15 -6
  254. package/translations/sw_KE.json +15 -6
  255. package/translations/tr.json +15 -6
  256. package/translations/tr_TR.json +15 -6
  257. package/translations/uk.json +15 -6
  258. package/translations/uz.json +15 -6
  259. package/translations/uz@Latn.json +15 -6
  260. package/translations/uz_UZ.json +15 -6
  261. package/translations/vi.json +15 -6
  262. package/translations/zh.json +63 -54
  263. package/translations/zh_CN.json +19 -10
  264. package/translations/zh_TW.json +15 -6
  265. package/dist/1187.js +0 -1
  266. package/dist/1187.js.map +0 -1
  267. package/dist/126.js +0 -1
  268. package/dist/1499.js +0 -1
  269. package/dist/1499.js.map +0 -1
  270. package/dist/15.js +0 -1
  271. package/dist/1522.js +0 -1
  272. package/dist/1522.js.map +0 -1
  273. package/dist/1564.js +0 -1
  274. package/dist/1567.js +0 -1
  275. package/dist/1777.js +0 -1
  276. package/dist/1777.js.map +0 -1
  277. package/dist/1845.js +0 -1
  278. package/dist/1899.js +0 -1
  279. package/dist/1899.js.map +0 -1
  280. package/dist/1953.js +0 -1
  281. package/dist/2056.js +0 -11
  282. package/dist/2056.js.map +0 -1
  283. package/dist/2104.js +0 -1
  284. package/dist/2104.js.map +0 -1
  285. package/dist/215.js +0 -1
  286. package/dist/2178.js +0 -1
  287. package/dist/2417.js +0 -1
  288. package/dist/2417.js.map +0 -1
  289. package/dist/2566.js +0 -1
  290. package/dist/2586.js +0 -1
  291. package/dist/2586.js.map +0 -1
  292. package/dist/2759.js +0 -1
  293. package/dist/276.js +0 -1
  294. package/dist/276.js.map +0 -1
  295. package/dist/3089.js +0 -1
  296. package/dist/3089.js.map +0 -1
  297. package/dist/3127.js +0 -1
  298. package/dist/3127.js.map +0 -1
  299. package/dist/3230.js +0 -1
  300. package/dist/3277.js +0 -1
  301. package/dist/3277.js.map +0 -1
  302. package/dist/3441.js +0 -1
  303. package/dist/3565.js +0 -1
  304. package/dist/3571.js +0 -1
  305. package/dist/3571.js.map +0 -1
  306. package/dist/3746.js +0 -1
  307. package/dist/3925.js +0 -1
  308. package/dist/3946.js +0 -1
  309. package/dist/4085.js +0 -1
  310. package/dist/4085.js.map +0 -1
  311. package/dist/4108.js +0 -1
  312. package/dist/4108.js.map +0 -1
  313. package/dist/4448.js +0 -1
  314. package/dist/4448.js.map +0 -1
  315. package/dist/4744.js +0 -1
  316. package/dist/4744.js.map +0 -1
  317. package/dist/4809.js +0 -1
  318. package/dist/486.js +0 -1
  319. package/dist/486.js.map +0 -1
  320. package/dist/4894.js +0 -1
  321. package/dist/4970.js +0 -1
  322. package/dist/4970.js.map +0 -1
  323. package/dist/5130.js +0 -1
  324. package/dist/5187.js +0 -1
  325. package/dist/5218.js +0 -1
  326. package/dist/5218.js.map +0 -1
  327. package/dist/5327.js +0 -1
  328. package/dist/5327.js.map +0 -1
  329. package/dist/5388.js +0 -1
  330. package/dist/5388.js.map +0 -1
  331. package/dist/5491.js +0 -1
  332. package/dist/5491.js.map +0 -1
  333. package/dist/5595.js +0 -1
  334. package/dist/5657.js +0 -38
  335. package/dist/5657.js.map +0 -1
  336. package/dist/5961.js +0 -1
  337. package/dist/6133.js +0 -1
  338. package/dist/634.js +0 -1
  339. package/dist/634.js.map +0 -1
  340. package/dist/6456.js +0 -1
  341. package/dist/6466.js +0 -1
  342. package/dist/6613.js +0 -1
  343. package/dist/6783.js +0 -1
  344. package/dist/703.js +0 -1
  345. package/dist/703.js.map +0 -1
  346. package/dist/7251.js +0 -1
  347. package/dist/7251.js.map +0 -1
  348. package/dist/7348.js +0 -1
  349. package/dist/7433.js +0 -1
  350. package/dist/7433.js.map +0 -1
  351. package/dist/7513.js +0 -1
  352. package/dist/7513.js.map +0 -1
  353. package/dist/7543.js +0 -1
  354. package/dist/7607.js +0 -1
  355. package/dist/772.js +0 -1
  356. package/dist/8139.js +0 -1
  357. package/dist/8139.js.map +0 -1
  358. package/dist/8456.js +0 -1
  359. package/dist/8456.js.map +0 -1
  360. package/dist/8588.js +0 -1
  361. package/dist/8588.js.map +0 -1
  362. package/dist/8599.js +0 -1
  363. package/dist/8727.js +0 -1
  364. package/dist/8847.js +0 -1
  365. package/dist/8919.js +0 -1
  366. package/dist/8919.js.map +0 -1
  367. package/dist/9015.js +0 -1
  368. package/dist/9051.js +0 -1
  369. package/dist/9051.js.map +0 -1
  370. package/dist/906.js +0 -1
  371. package/dist/9065.js +0 -1
  372. package/dist/9182.js +0 -1
  373. package/dist/9260.js +0 -1
  374. package/dist/9260.js.map +0 -1
  375. package/dist/9327.js +0 -1
  376. package/dist/9327.js.map +0 -1
  377. package/dist/9339.js +0 -1
  378. package/dist/9453.js +0 -1
  379. package/dist/9589.js +0 -1
  380. package/dist/9589.js.map +0 -1
  381. package/dist/9650.js +0 -1
  382. package/dist/9650.js.map +0 -1
  383. package/dist/9833.js +0 -1
  384. package/dist/9833.js.map +0 -1
  385. package/dist/9920.js +0 -1
  386. package/dist/9938.js +0 -1
  387. package/dist/9943.js +0 -1
  388. package/dist/9943.js.map +0 -1
  389. package/src/appointments/scheduled/appointments-list.component.tsx +0 -51
  390. package/src/hooks/useClinicalMetrics.ts +0 -94
  391. package/src/hooks/useTodaysVisits.ts +0 -19
  392. package/src/scheduled-appointments-config-schema.ts +0 -177
@@ -1,17 +1,38 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
+ import { formatDate, parseDate } from '@openmrs/esm-framework';
3
4
  import MetricsCard from './metrics-card.component';
4
5
  import MetricsErrorCard from './metrics-error-card.component';
5
- import { useClinicalMetrics } from '../../hooks/useClinicalMetrics';
6
- import { formatDate, parseDate } from '@openmrs/esm-framework';
7
- import { useAppointmentsStore } from '../../store';
6
+ import { useAppointmentsAppContext } from '../../hooks/useAppointmentsAppContext';
7
+ import { useSelectedDate } from '../../hooks/useSelectedDate';
8
8
 
9
9
  export default function HighestVolumeServiceExtension() {
10
10
  const { t } = useTranslation();
11
- const { highestServiceLoad, error } = useClinicalMetrics();
12
- const { selectedDate } = useAppointmentsStore();
11
+ const { appointmentForSelectedDateFilteredByServiceTypes, error } = useAppointmentsAppContext();
12
+ const selectedDate = useSelectedDate();
13
13
  const formattedStartDate = formatDate(parseDate(selectedDate), { mode: 'standard', time: false });
14
14
 
15
+ const highestServiceLoad = useMemo(() => {
16
+ const serviceVolumeMap = new Map<string, number>();
17
+ const serviceNameMap = new Map<string, string>();
18
+ for (const appointment of appointmentForSelectedDateFilteredByServiceTypes) {
19
+ const serviceUuid = appointment.service?.uuid;
20
+ const serviceName = appointment.service?.name;
21
+ if (serviceUuid && serviceName) {
22
+ serviceVolumeMap.set(serviceUuid, (serviceVolumeMap.get(serviceUuid) ?? 0) + 1);
23
+ serviceNameMap.set(serviceUuid, serviceName);
24
+ }
25
+ }
26
+
27
+ let highestServiceLoad: { serviceUuid: string; serviceName: string; count: number } | null = null;
28
+ for (const [serviceUuid, count] of serviceVolumeMap.entries()) {
29
+ if (!highestServiceLoad || count > highestServiceLoad.count) {
30
+ highestServiceLoad = { serviceUuid, serviceName: serviceNameMap.get(serviceUuid) ?? '', count };
31
+ }
32
+ }
33
+ return highestServiceLoad;
34
+ }, [appointmentForSelectedDateFilteredByServiceTypes]);
35
+
15
36
  if (error) {
16
37
  return <MetricsErrorCard headerLabel={t('highestServiceVolumeCardTitle', 'Highest volume service')} />;
17
38
  }
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
5
5
  import { isEmpty } from 'lodash-es';
6
6
  import { useAppointmentsStore } from '../../store';
7
7
  import styles from './metrics-card.scss';
8
+ import { useSelectedDate } from '../../hooks/useSelectedDate';
8
9
  dayjs.extend(isSameOrBefore);
9
10
 
10
11
  interface MetricsCardProps {
@@ -16,7 +17,7 @@ interface MetricsCardProps {
16
17
 
17
18
  const MetricsCard: React.FC<MetricsCardProps> = ({ label, value, headerLabel, count }) => {
18
19
  const { t } = useTranslation();
19
- const { selectedDate } = useAppointmentsStore();
20
+ const selectedDate = useSelectedDate();
20
21
  const isSelectedDateInPast = useMemo(() => dayjs(selectedDate).isBefore(dayjs(), 'date'), [selectedDate]);
21
22
 
22
23
  return (
@@ -1,14 +1,22 @@
1
- import React from 'react';
2
- import MetricsCard from './metrics-card.component';
1
+ import React, { useMemo } from 'react';
3
2
  import { useTranslation } from 'react-i18next';
4
- import { useAllAppointmentsByDate } from '../../hooks/useClinicalMetrics';
5
3
  import { formatDate, parseDate } from '@openmrs/esm-framework';
6
- import { useAppointmentsStore } from '../../store';
4
+ import MetricsCard from './metrics-card.component';
5
+ import { useAppointmentsAppContext } from '../../hooks/useAppointmentsAppContext';
6
+ import { useSelectedDate } from '../../hooks/useSelectedDate';
7
7
 
8
8
  export default function ProvidersBookedExtension() {
9
9
  const { t } = useTranslation();
10
- const { totalProviders } = useAllAppointmentsByDate();
11
- const { selectedDate } = useAppointmentsStore();
10
+ const selectedDate = useSelectedDate();
11
+ const { appointmentForSelectedDateFilteredByServiceTypes } = useAppointmentsAppContext();
12
+
13
+ const totalProviders = useMemo(() => {
14
+ return appointmentForSelectedDateFilteredByServiceTypes.reduce((providersSet, appointment) => {
15
+ appointment.providers?.forEach((provider) => providersSet.add(provider.uuid));
16
+ return providersSet;
17
+ }, new Set<string>()).size;
18
+ }, [appointmentForSelectedDateFilteredByServiceTypes]);
19
+
12
20
  const formattedStartDate = formatDate(parseDate(selectedDate), { mode: 'standard', time: false });
13
21
 
14
22
  return (
@@ -1,30 +1,34 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import MetricsCard from './metrics-card.component';
4
- import { useScheduledAppointments } from '../../hooks/useClinicalMetrics';
5
- import { useAppointmentsStore } from '../../store';
6
- import { useAppointmentList } from '../../hooks/useAppointmentList';
4
+ import { useAppointmentsAppContext } from '../../hooks/useAppointmentsAppContext';
7
5
 
6
+ /**
7
+ * This extension shows the metrics of the number of scheduled appointments for the selected date and services,
8
+ * showing the total number of appointments (across all status), the number of checked in ones (status == CheckedIn),
9
+ * and number of not arrived (status == Scheduled).
10
+ *
11
+ */
8
12
  export default function ScheduledAppointmentsExtension() {
9
13
  const { t } = useTranslation();
10
- const { appointmentServiceTypes } = useAppointmentsStore();
14
+ const { appointmentForSelectedDateFilteredByServiceTypes } = useAppointmentsAppContext();
11
15
 
12
- const { appointmentList: arrivedAppointments } = useAppointmentList('CheckedIn');
13
- const { appointmentList: pendingAppointments } = useAppointmentList('Scheduled');
16
+ const totalScheduledAppointments = appointmentForSelectedDateFilteredByServiceTypes.length;
14
17
 
15
- const { totalScheduledAppointments } = useScheduledAppointments(appointmentServiceTypes);
18
+ const count = useMemo(() => {
19
+ const arrivedAppointments = appointmentForSelectedDateFilteredByServiceTypes.filter(
20
+ ({ status }) => status === 'CheckedIn',
21
+ );
22
+ const pendingAppointments = appointmentForSelectedDateFilteredByServiceTypes.filter(
23
+ ({ status }) => status === 'Scheduled',
24
+ );
16
25
 
17
- const filteredArrivedAppointments = appointmentServiceTypes
18
- ? arrivedAppointments.filter(({ service }) => appointmentServiceTypes.includes(service.uuid))
19
- : arrivedAppointments;
20
-
21
- const filteredPendingAppointments = appointmentServiceTypes
22
- ? pendingAppointments.filter(({ service }) => appointmentServiceTypes.includes(service.uuid))
23
- : pendingAppointments;
26
+ return { pendingAppointments, arrivedAppointments };
27
+ }, [appointmentForSelectedDateFilteredByServiceTypes]);
24
28
 
25
29
  return (
26
30
  <MetricsCard
27
- count={{ pendingAppointments: filteredPendingAppointments, arrivedAppointments: filteredArrivedAppointments }}
31
+ count={count}
28
32
  headerLabel={t('scheduledAppointments', 'Scheduled appointments')}
29
33
  label={t('appointments', 'Appointments')}
30
34
  value={totalScheduledAppointments}
@@ -3,11 +3,7 @@ import { ExtensionSlot } from '@openmrs/esm-framework';
3
3
  import MetricsHeader from './metrics-header.component';
4
4
  import styles from './metrics-container.scss';
5
5
 
6
- interface AppointmentMetricsProps {
7
- appointmentServiceTypes: Array<string>;
8
- }
9
-
10
- const AppointmentsMetrics: React.FC<AppointmentMetricsProps> = ({ appointmentServiceTypes }) => {
6
+ const AppointmentsMetrics: React.FC<{}> = () => {
11
7
  return (
12
8
  <>
13
9
  <MetricsHeader />
@@ -6,15 +6,15 @@ import { Calendar, Hospital } from '@carbon/react/icons';
6
6
  import { Button } from '@carbon/react';
7
7
  import { isDesktop, navigate, useLayoutType } from '@openmrs/esm-framework';
8
8
  import { spaHomePage } from '../constants';
9
- import { useAppointmentsStore } from '../store';
10
9
  import styles from './metrics-header.scss';
11
10
  import { launchCreateAppointmentForm } from '../helpers';
11
+ import { useSelectedDate } from '../hooks/useSelectedDate';
12
12
 
13
13
  dayjs.extend(isToday);
14
14
 
15
15
  const MetricsHeader: React.FC = () => {
16
16
  const { t } = useTranslation();
17
- const { selectedDate } = useAppointmentsStore();
17
+ const selectedDate = useSelectedDate();
18
18
  const layout = useLayoutType();
19
19
  const responsiveSize = isDesktop(layout) ? 'sm' : 'md';
20
20
 
@@ -100,7 +100,7 @@ const PatientAppointmentsDetailedSummary: React.FC<PatientAppointmentsDetailProp
100
100
  <Button
101
101
  kind="ghost"
102
102
  renderIcon={(props) => <AddIcon size={16} {...props} />}
103
- iconDescription="Add Appointments"
103
+ iconDescription={t('addAppointments', 'Add Appointments')}
104
104
  onClick={() => handleLaunchAppointmentForm(patientUuid)}>
105
105
  {t('add', 'Add')}
106
106
  </Button>
@@ -14,7 +14,7 @@ import {
14
14
  import { ErrorCard, formatDate, parseDate, showSnackbar, type Visit } from '@openmrs/esm-framework';
15
15
  import { changeAppointmentStatus, usePatientAppointments } from './patient-appointments.resource';
16
16
  import { type Appointment } from '../types';
17
- import { useMutateAppointments } from '../form/appointments-form.resource';
17
+ import { useMutateAppointments } from '../hooks/useMutateAppointments';
18
18
  import styles from './patient-upcoming-appointments-card.scss';
19
19
 
20
20
  interface VisitFormCallbacks {
@@ -47,7 +47,6 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
47
47
  const headerTitle = t('upcomingAppointments', 'Upcoming appointments');
48
48
  const [selectedAppointment, setSelectedAppointment] = useState<Appointment>(null);
49
49
  const { mutateAppointments } = useMutateAppointments();
50
- const memoMutateAppointments = useMemo(() => mutateAppointments, [mutateAppointments]);
51
50
 
52
51
  const ac = useMemo<AbortController>(() => new AbortController(), []);
53
52
  useEffect(() => () => ac.abort(), [ac]);
@@ -59,7 +58,7 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
59
58
  if (selectedAppointment) {
60
59
  return changeAppointmentStatus('CheckedIn', selectedAppointment.uuid)
61
60
  .then(() => {
62
- memoMutateAppointments();
61
+ mutateAppointments();
63
62
  showSnackbar({
64
63
  isLowContrast: true,
65
64
  kind: 'success',
@@ -80,7 +79,7 @@ const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps
80
79
  }
81
80
  },
82
81
  }),
83
- [selectedAppointment, memoMutateAppointments, t],
82
+ [selectedAppointment, mutateAppointments, t],
84
83
  );
85
84
 
86
85
  useEffect(() => {
package/src/routes.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "$schema": "https://json.openmrs.org/routes.schema.json",
3
3
  "backendDependencies": {
4
- "webservices.rest": ">=2.2.0"
4
+ "webservices.rest": ">=2.2.0",
5
+ "appointments": ">=2.0.0"
5
6
  },
6
7
  "extensions": [
7
8
  {
@@ -41,31 +42,6 @@
41
42
  "slot": "todays-appointment-slot",
42
43
  "component": "homeAppointments"
43
44
  },
44
- {
45
- "name": "expected-appointments-panel",
46
- "slot": "scheduled-appointments-panels-slot",
47
- "component": "appointmentsList"
48
- },
49
- {
50
- "name": "checked-in-appointments-panel",
51
- "slot": "scheduled-appointments-panels-slot",
52
- "component": "appointmentsList"
53
- },
54
- {
55
- "name": "completed-appointments-panel",
56
- "slot": "scheduled-appointments-panels-slot",
57
- "component": "appointmentsList"
58
- },
59
- {
60
- "name": "missed-appointments-panel",
61
- "slot": "scheduled-appointments-panels-slot",
62
- "component": "appointmentsList"
63
- },
64
- {
65
- "name": "cancelled-appointments-panel",
66
- "slot": "scheduled-appointments-panels-slot",
67
- "component": "appointmentsList"
68
- },
69
45
  {
70
46
  "name": "early-appointments-panel",
71
47
  "component": "earlyAppointments"
@@ -79,7 +55,7 @@
79
55
  "columns": 1,
80
56
  "columnSpan": 1,
81
57
  "hideDashboardTitle": true,
82
- "path": "Appointments",
58
+ "path": "appointments",
83
59
  "slot": "patient-chart-appointments-dashboard-slot",
84
60
  "title": "Appointments"
85
61
  }
package/src/store.ts CHANGED
@@ -1,46 +1,29 @@
1
- import { createGlobalStore, isOmrsDateStrict, useStore } from '@openmrs/esm-framework';
2
- import dayjs from 'dayjs';
3
- import { omrsDateFormat } from './constants';
1
+ import { type Actions, createGlobalStore, useStoreWithActions } from '@openmrs/esm-framework';
2
+ import { type AppointmentStatus } from './types';
4
3
 
5
- export const appointmentsStore = createGlobalStore('appointments-app', {
6
- appointmentServiceTypes: getFromLocalStorage('openmrs:appointments:serviceTypes') || [],
7
- selectedDate: dayjs().startOf('day').format(omrsDateFormat),
8
- });
9
-
10
- export function useAppointmentsStore() {
11
- return useStore(appointmentsStore);
12
- }
13
-
14
- export function setAppointmentServiceTypes(serviceTypes: Array<string>) {
15
- appointmentsStore.setState({ appointmentServiceTypes: serviceTypes });
16
- }
17
-
18
- export function setSelectedDate(date: string) {
19
- if (!isOmrsDateStrict(date)) {
20
- console.warn(
21
- 'esm-appointments-app: setSelectedDate called with incorrectly formatted date. Should be omrsDateFormat string. Received:',
22
- date,
23
- );
24
- }
25
- appointmentsStore.setState({ selectedDate: date });
4
+ interface AppointmentsStore {
5
+ appointmentServiceTypes: Array<string>;
6
+ selectedAppointmentStatuses: Array<AppointmentStatus>;
26
7
  }
27
8
 
28
- /* Set up localStorage serialization */
9
+ export const appointmentsStore = createGlobalStore<AppointmentsStore>(
10
+ 'appointments-app',
11
+ {
12
+ appointmentServiceTypes: [],
13
+ selectedAppointmentStatuses: [],
14
+ },
15
+ 'sessionStorage',
16
+ );
17
+
18
+ export const storeActions = {
19
+ setAppointmentServiceTypes(_, appointmentServiceTypes: Array<string>) {
20
+ return { appointmentServiceTypes };
21
+ },
22
+ setSelectedAppointmentStatuses(_, selectedAppointmentStatuses: Array<AppointmentStatus>) {
23
+ return { selectedAppointmentStatuses };
24
+ },
25
+ } satisfies Actions<AppointmentsStore>;
29
26
 
30
- let lastValueOfAppointmentServiceTypes = getFromLocalStorage('openmrs:appointments:serviceTypes');
31
-
32
- function getFromLocalStorage(key: string) {
33
- const value = localStorage.getItem(key);
34
- return value ? JSON.parse(value) : undefined;
35
- }
36
-
37
- function setInLocalStorage(key: string, value: any) {
38
- localStorage.setItem(key, JSON.stringify(value));
27
+ export function useAppointmentsStore() {
28
+ return useStoreWithActions(appointmentsStore, storeActions);
39
29
  }
40
-
41
- appointmentsStore.subscribe(({ appointmentServiceTypes }) => {
42
- if (lastValueOfAppointmentServiceTypes !== appointmentServiceTypes) {
43
- setInLocalStorage('openmrs:appointments:serviceTypes', appointmentServiceTypes);
44
- lastValueOfAppointmentServiceTypes = appointmentServiceTypes;
45
- }
46
- });
@@ -14,6 +14,7 @@ export interface AppointmentLocation {
14
14
  }
15
15
 
16
16
  // note that the API supports two other statuses that we are not currently supporting: "Requested" and "WaitList"
17
+ // Translation keys for these enum values are in src/constants.ts (scanned by extract-translations)
17
18
  export enum AppointmentStatus {
18
19
  SCHEDULED = 'Scheduled',
19
20
  CANCELLED = 'Cancelled',
@@ -184,3 +185,9 @@ export interface RecurringAppointmentsPayload {
184
185
  export interface PatientDetails {
185
186
  dateOfBirth: string;
186
187
  }
188
+
189
+ export interface AppointmentsAppContext {
190
+ appointmentForSelectedDateFilteredByServiceTypes: Array<Appointment>;
191
+ isLoading: boolean;
192
+ error: any;
193
+ }
@@ -3,10 +3,10 @@ import dayjs from 'dayjs';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { formatDate } from '@openmrs/esm-framework';
5
5
  import { monthDays } from '../../helpers';
6
- import { useAppointmentsStore } from '../../store';
7
6
  import DaysOfWeekCard from '../../calendar/monthly/days-of-week.component';
8
7
  import MonthlyWorkloadCard from './monthlyWorkCard';
9
8
  import styles from './monthly-workload.scss';
9
+ import { useSelectedDate } from '../../hooks/useSelectedDate';
10
10
 
11
11
  interface MonthlyCalendarViewProps {
12
12
  calendarWorkload: Array<{ count: number; date: string }>;
@@ -20,7 +20,7 @@ const MonthlyCalendarView: React.FC<MonthlyCalendarViewProps> = ({
20
20
  onDateClick,
21
21
  }) => {
22
22
  const { t } = useTranslation();
23
- const { selectedDate } = useAppointmentsStore();
23
+ const selectedDate = useSelectedDate();
24
24
  const daysInWeek = ['SUN', 'MON', 'TUE', 'WED', 'THUR', 'FRI', 'SAT'];
25
25
  const monthViewDate = dateToDisplay === '' ? selectedDate : dateToDisplay;
26
26
  const daysInWeeks = daysInWeek.map((day) => t(day));
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { useAppointmentService } from '../form/appointments-form.resource';
2
+ import { useAppointmentServices } from '../hooks/useAppointmentService';
3
3
  import { useCalendarDistribution, useMonthlyCalendarDistribution } from './workload.resource';
4
4
  import MonthlyCalendarView from './monthly-view-workload/monthly-view.component';
5
5
  import styles from './workload.scss';
@@ -11,8 +11,8 @@ interface WorkloadProps {
11
11
  }
12
12
 
13
13
  const Workload: React.FC<WorkloadProps> = ({ selectedService, appointmentDate, onWorkloadDateChange }) => {
14
- const { data: services } = useAppointmentService();
15
- const serviceUuid = services?.find((service) => service.name === selectedService)?.uuid;
14
+ const { serviceTypes } = useAppointmentServices();
15
+ const serviceUuid = serviceTypes?.find((service) => service.name === selectedService)?.uuid;
16
16
 
17
17
  const [selectedTab, setSelectedTab] = useState(0);
18
18
 
@@ -15,7 +15,7 @@ export const getMonthlyCalendarDistribution = (startDate: Date, appointmentCount
15
15
  for (let i = 0; i <= 35; i++) {
16
16
  distributionHashTable.set(dayjs(startDate).add(i, 'day').format('YYYY-MM-DD'), 0);
17
17
  }
18
- appointmentCount.map(({ date, count }) => {
18
+ appointmentCount.forEach(({ date, count }) => {
19
19
  if (distributionHashTable.has(date)) {
20
20
  distributionHashTable.set(date, count);
21
21
  }
@@ -2,6 +2,7 @@
2
2
  "action": "Action",
3
3
  "actions": "Actions",
4
4
  "add": "Add",
5
+ "addAppointments": "Add Appointments",
5
6
  "age": "Age",
6
7
  "allDay": "All day",
7
8
  "appointment": "Appointment",
@@ -9,6 +10,8 @@
9
10
  "appointmentCancelled": "Appointment Cancelled",
10
11
  "appointmentCancelledSuccessfully": "Appointment cancelled successfully",
11
12
  "appointmentCheckedIn": "Appointment Checked In",
13
+ "appointmentCheckedInWithExistingVisit": "Appointment checked in using existing active visit",
14
+ "appointmentCheckInFailed": "An error occurred while checking in the appointment",
12
15
  "appointmentConflict": "Appointment conflict",
13
16
  "appointmentDate": "Appointment date",
14
17
  "appointmentDisplay": "<0>{{patientName}}</0> - {{serviceName}} - {{currentStatus}}",
@@ -31,7 +34,7 @@
31
34
  "appointments_lower": "appointments",
32
35
  "appointmentsCalendar": "Appointments calendar",
33
36
  "appointmentScheduled": "Appointment scheduled",
34
- "appointmentsScheduledForToday": "appointments scheduled for today",
37
+ "appointmentsForDate": "Appointments for: {{date}}",
35
38
  "appointmentsTable": "Appointments table",
36
39
  "appointmentStatus": "Appointment status",
37
40
  "appointmentsUpdated": "Appointments updated",
@@ -48,19 +51,22 @@
48
51
  "cancelAppointment": "Cancel Appointment",
49
52
  "cancelAppointmentModalConfirmationText": "Are you sure you want to cancel this appointment?",
50
53
  "cancelled": "Cancelled",
54
+ "Cancelled": "Cancelled",
51
55
  "changeAppointmentsStatus": "Change appointments status",
52
56
  "changeStatus": "Change status",
53
57
  "changeStatusForSelectedAppointments": "Change the status for the following appointments.",
54
58
  "checkedIn": "Checked in",
55
- "checkedOut": "Checked out",
59
+ "CheckedIn": "Checked in",
56
60
  "checkFilters": "Check the filters above",
57
61
  "checkIn": "Check In",
62
+ "checkInFailed": "Check-in failed",
58
63
  "checkOut": "Check out",
59
64
  "chooseAppointmentType": "Choose appointment type",
60
65
  "chooseLocation": "Choose a location",
61
66
  "chooseProvider": "Choose a provider",
62
67
  "chooseService": "Select service",
63
68
  "completed": "Completed",
69
+ "Completed": "Completed",
64
70
  "Contact": "Contact {{index}}",
65
71
  "countMore_one": "{{count}} more",
66
72
  "countMore_other": "{{count}} more",
@@ -71,24 +77,25 @@
71
77
  "dateAppointmentScheduled": "Date appointment scheduled",
72
78
  "dateOfBirth": "Date of birth",
73
79
  "dateRange": "Set date range",
74
- "dateTime": "Date & Time",
80
+ "dateTime": "Appointment time",
75
81
  "day": "Day",
76
82
  "daysOfWeek": "Days of the week",
77
83
  "discard": "Discard",
78
84
  "download": "Download",
79
85
  "durationErrorMessage": "Duration should be greater than zero",
80
86
  "durationInMinutes": "Duration (minutes)",
87
+ "early": "Early",
81
88
  "edit": "Edit",
82
89
  "editAppointment": "Edit appointment",
83
90
  "endAppointmentAndVisitConfirmationMessage": "Checking the patient out will mark the appointment as complete, and close out the active visit for this patient.",
84
91
  "endAppointmentConfirmation": "Are you sure you want to check the patient out for this appointment?",
85
92
  "endAppointmentConfirmationMessage": "Checking the patient out will mark the appointment as complete.",
86
- "expected": "Expected",
87
93
  "failedToEndActiveVisit": "Failed to end active visit for {{patient}}",
88
94
  "failedToLoadMetrics": "Failed to load",
89
95
  "failedToUpdateVisit": "Failed to update visit",
90
96
  "filterAppointments": "Filter appointments",
91
97
  "filterAppointmentsByServiceType": "Filter appointments by service type",
98
+ "filterAppointmentsByStatus": "Filter appointments by status",
92
99
  "filterTable": "Filter table",
93
100
  "FRI": "FRI",
94
101
  "gender": "Gender",
@@ -104,6 +111,7 @@
104
111
  "markAppointmentAsCompletedMessage": "Marking appointment as completed will end the active visit of the patient",
105
112
  "metricLoadErrorMessage": "Please contact your system administrator if the problem persists.",
106
113
  "missed": "Missed",
114
+ "Missed": "Missed",
107
115
  "MON": "MON",
108
116
  "next": "Next",
109
117
  "nextMonth": "Next month",
@@ -112,7 +120,6 @@
112
120
  "noAppointmentsToDisplay": "No appointments to display",
113
121
  "noContent": "No Content",
114
122
  "noCurrentAppointments": "There are no appointments scheduled for today to display for this patient",
115
- "noMatchingAppointments": "No matching appointments found",
116
123
  "noPastAppointments": "There are no past appointments to display for this patient",
117
124
  "notArrived": "Not arrived",
118
125
  "note": "Note",
@@ -139,6 +146,7 @@
139
146
  "saveAndClose": "Save and close",
140
147
  "saving": "Saving",
141
148
  "scheduled": "Scheduled",
149
+ "Scheduled": "Scheduled",
142
150
  "scheduledAppointments": "Scheduled appointments",
143
151
  "scheduledForToday": "Scheduled For Today",
144
152
  "selectALocation": "Select a location",
@@ -157,7 +165,7 @@
157
165
  "THUR": "THUR",
158
166
  "time": "Time",
159
167
  "today": "Today",
160
- "todays": "Today's",
168
+ "todaysAppointment": "Today's Appointments",
161
169
  "TUE": "TUE",
162
170
  "type": "Type",
163
171
  "unknownError": "An unknown error occurred",
@@ -167,6 +175,7 @@
167
175
  "upcoming": "Upcoming",
168
176
  "upcomingAppointments": "Upcoming appointments",
169
177
  "updateError": "Error updating upcoming appointment",
178
+ "visitStartTime": "Visit start time",
170
179
  "WED": "WED",
171
180
  "week": "Week",
172
181
  "yes": "Yes"
@@ -2,6 +2,7 @@
2
2
  "action": "الإجراء",
3
3
  "actions": "الإجراءات",
4
4
  "add": "إضافة",
5
+ "addAppointments": "Add Appointments",
5
6
  "age": "العمر",
6
7
  "allDay": "كل اليوم",
7
8
  "appointment": "Appointment",
@@ -9,6 +10,8 @@
9
10
  "appointmentCancelled": "تم إلغاء الموعد",
10
11
  "appointmentCancelledSuccessfully": "تم إلغاء الموعد بنجاح",
11
12
  "appointmentCheckedIn": "Appointment Checked In",
13
+ "appointmentCheckedInWithExistingVisit": "Appointment checked in using existing active visit",
14
+ "appointmentCheckInFailed": "An error occurred while checking in the appointment",
12
15
  "appointmentConflict": "تعارض بالمواعيد",
13
16
  "appointmentDate": "Appointment date",
14
17
  "appointmentDisplay": "<0>{{patientName}}</0> - {{serviceName}} - {{currentStatus}}",
@@ -31,7 +34,7 @@
31
34
  "appointments_lower": "مواعيد",
32
35
  "appointmentsCalendar": "جدول المواعيد",
33
36
  "appointmentScheduled": "تم جدولة الموعد",
34
- "appointmentsScheduledForToday": "المواعيد المقررة لهذا اليوم",
37
+ "appointmentsForDate": "Appointments for: {{date}}",
35
38
  "appointmentsTable": "جدول المواعيد",
36
39
  "appointmentStatus": "Appointment status",
37
40
  "appointmentsUpdated": "Appointments updated",
@@ -48,19 +51,22 @@
48
51
  "cancelAppointment": "إلغاء الموعد",
49
52
  "cancelAppointmentModalConfirmationText": "هل أنت متأكد أنك تريد إلغاء هذا الموعد؟",
50
53
  "cancelled": "تم الإلغاء",
54
+ "Cancelled": "Cancelled",
51
55
  "changeAppointmentsStatus": "Change appointments status",
52
56
  "changeStatus": "Change status",
53
57
  "changeStatusForSelectedAppointments": "Change the status for the following appointments.",
54
58
  "checkedIn": "تم تسجيل الوصول",
55
- "checkedOut": "تم تسجيل الخروج",
59
+ "CheckedIn": "Checked in",
56
60
  "checkFilters": "Check the filters above",
57
61
  "checkIn": "تسجيل الوصول",
62
+ "checkInFailed": "Check-in failed",
58
63
  "checkOut": "تسجيل الخروج",
59
64
  "chooseAppointmentType": "Choose appointment type",
60
65
  "chooseLocation": "Choose a location",
61
66
  "chooseProvider": "Choose a provider",
62
67
  "chooseService": "اختر الخدمة",
63
68
  "completed": "مكتمل",
69
+ "Completed": "Completed",
64
70
  "Contact": "Contact {{index}}",
65
71
  "countMore_one": "{{count}} more",
66
72
  "countMore_other": "{{count}} more",
@@ -71,24 +77,25 @@
71
77
  "dateAppointmentScheduled": "Date appointment scheduled",
72
78
  "dateOfBirth": "تاريخ الميلاد",
73
79
  "dateRange": "Set date range",
74
- "dateTime": "Date & Time",
80
+ "dateTime": "Appointment time",
75
81
  "day": "Day",
76
82
  "daysOfWeek": "Days of the week",
77
83
  "discard": "تجاهل",
78
84
  "download": "تحميل",
79
85
  "durationErrorMessage": "Duration should be greater than zero",
80
86
  "durationInMinutes": "Duration (minutes)",
87
+ "early": "Early",
81
88
  "edit": "Edit",
82
89
  "editAppointment": "Edit appointment",
83
90
  "endAppointmentAndVisitConfirmationMessage": "Checking the patient out will mark the appointment as complete, and close out the active visit for this patient.",
84
91
  "endAppointmentConfirmation": "Are you sure you want to check the patient out for this appointment?",
85
92
  "endAppointmentConfirmationMessage": "Checking the patient out will mark the appointment as complete.",
86
- "expected": "Expected",
87
93
  "failedToEndActiveVisit": "Failed to end active visit for {{patient}}",
88
94
  "failedToLoadMetrics": "Failed to load",
89
95
  "failedToUpdateVisit": "Failed to update visit",
90
96
  "filterAppointments": "Filter appointments",
91
97
  "filterAppointmentsByServiceType": "Filter appointments by service type",
98
+ "filterAppointmentsByStatus": "Filter appointments by status",
92
99
  "filterTable": "Filter table",
93
100
  "FRI": "FRI",
94
101
  "gender": "الجنس",
@@ -104,6 +111,7 @@
104
111
  "markAppointmentAsCompletedMessage": "Marking appointment as completed will end the active visit of the patient",
105
112
  "metricLoadErrorMessage": "Please contact your system administrator if the problem persists.",
106
113
  "missed": "فائت",
114
+ "Missed": "Missed",
107
115
  "MON": "MON",
108
116
  "next": "Next",
109
117
  "nextMonth": "Next month",
@@ -112,7 +120,6 @@
112
120
  "noAppointmentsToDisplay": "لا توجد مواعيد لعرضها",
113
121
  "noContent": "No Content",
114
122
  "noCurrentAppointments": "لا توجد مواعيد مجدولة لهذا المريض اليوم",
115
- "noMatchingAppointments": "No matching appointments found",
116
123
  "noPastAppointments": "لا توجد مواعيد سابقة لعرضها لهذا المريض\"",
117
124
  "notArrived": "لم يصل",
118
125
  "note": "Note",
@@ -139,6 +146,7 @@
139
146
  "saveAndClose": "حفظ وإغلاق",
140
147
  "saving": "Saving",
141
148
  "scheduled": "مجدول",
149
+ "Scheduled": "Scheduled",
142
150
  "scheduledAppointments": "المواعيد المجدولة",
143
151
  "scheduledForToday": "مجدول لليوم",
144
152
  "selectALocation": "Select a location",
@@ -157,7 +165,7 @@
157
165
  "THUR": "THUR",
158
166
  "time": "الوقت",
159
167
  "today": "اليوم",
160
- "todays": "Today's",
168
+ "todaysAppointment": "Today's Appointments",
161
169
  "TUE": "TUE",
162
170
  "type": "Type",
163
171
  "unknownError": "An unknown error occurred",
@@ -167,6 +175,7 @@
167
175
  "upcoming": "القادمة",
168
176
  "upcomingAppointments": "المواعيد القادمة",
169
177
  "updateError": "Error updating upcoming appointment",
178
+ "visitStartTime": "Visit start time",
170
179
  "WED": "WED",
171
180
  "week": "Week",
172
181
  "yes": "نعم"