@kenyaemr/esm-admin-app 5.4.3 → 5.4.4-pre.100

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 (296) hide show
  1. package/.turbo/turbo-build.log +5 -12
  2. package/dist/1074.js +1 -0
  3. package/dist/1074.js.map +1 -0
  4. package/dist/12.js +17 -0
  5. package/dist/12.js.map +1 -0
  6. package/dist/1201.js +1 -0
  7. package/dist/1201.js.map +1 -0
  8. package/dist/1242.js +1 -0
  9. package/dist/1242.js.map +1 -0
  10. package/dist/1311.js +1 -0
  11. package/dist/1311.js.map +1 -0
  12. package/dist/1462.js +1 -0
  13. package/dist/1462.js.map +1 -0
  14. package/dist/1469.js +1 -0
  15. package/dist/1469.js.map +1 -0
  16. package/dist/1506.js +13 -0
  17. package/dist/1506.js.map +1 -0
  18. package/dist/1718.js +1 -0
  19. package/dist/1718.js.map +1 -0
  20. package/dist/1722.js +1 -0
  21. package/dist/1722.js.map +1 -0
  22. package/dist/1772.js +1 -0
  23. package/dist/1772.js.map +1 -0
  24. package/dist/1889.js +1 -0
  25. package/dist/1889.js.map +1 -0
  26. package/dist/1972.js +1 -0
  27. package/dist/1972.js.map +1 -0
  28. package/dist/1990.js +1 -0
  29. package/dist/1990.js.map +1 -0
  30. package/dist/2016.js +1 -0
  31. package/dist/2016.js.map +1 -0
  32. package/dist/2080.js +1 -0
  33. package/dist/2080.js.map +1 -0
  34. package/dist/2096.js +1 -0
  35. package/dist/2096.js.map +1 -0
  36. package/dist/2153.js +1 -0
  37. package/dist/2153.js.map +1 -0
  38. package/dist/216.js +1 -0
  39. package/dist/216.js.map +1 -0
  40. package/dist/2270.js +1 -0
  41. package/dist/2270.js.map +1 -0
  42. package/dist/2294.js +1 -0
  43. package/dist/2294.js.map +1 -0
  44. package/dist/2345.js +1 -0
  45. package/dist/2345.js.map +1 -0
  46. package/dist/2402.js +1 -0
  47. package/dist/2402.js.map +1 -0
  48. package/dist/2500.js +1 -0
  49. package/dist/2500.js.map +1 -0
  50. package/dist/251.js +1 -0
  51. package/dist/251.js.map +1 -0
  52. package/dist/257.js +1 -0
  53. package/dist/257.js.map +1 -0
  54. package/dist/2586.js +1 -0
  55. package/dist/2586.js.map +1 -0
  56. package/dist/2625.js +1 -0
  57. package/dist/2625.js.map +1 -0
  58. package/dist/2652.js +1 -0
  59. package/dist/2652.js.map +1 -0
  60. package/dist/2685.js +1 -0
  61. package/dist/2685.js.map +1 -0
  62. package/dist/2948.js +1 -0
  63. package/dist/2948.js.map +1 -0
  64. package/dist/3089.js +1 -0
  65. package/dist/3089.js.map +1 -0
  66. package/dist/3190.js +1 -0
  67. package/dist/3190.js.map +1 -0
  68. package/dist/3224.js +1 -0
  69. package/dist/3224.js.map +1 -0
  70. package/dist/3366.js +1 -0
  71. package/dist/3366.js.map +1 -0
  72. package/dist/349.js +1 -0
  73. package/dist/349.js.map +1 -0
  74. package/dist/3548.js +1 -0
  75. package/dist/3548.js.map +1 -0
  76. package/dist/3571.js +1 -0
  77. package/dist/3571.js.map +1 -0
  78. package/dist/3691.js +1 -0
  79. package/dist/3691.js.map +1 -0
  80. package/dist/3775.js +1 -0
  81. package/dist/3775.js.map +1 -0
  82. package/dist/3816.js +1 -0
  83. package/dist/3816.js.map +1 -0
  84. package/dist/3852.js +1 -0
  85. package/dist/3852.js.map +1 -0
  86. package/dist/3906.js +1 -0
  87. package/dist/3906.js.map +1 -0
  88. package/dist/3963.js +1 -0
  89. package/dist/3963.js.map +1 -0
  90. package/dist/405.js +1 -0
  91. package/dist/405.js.map +1 -0
  92. package/dist/4296.js +1 -0
  93. package/dist/4296.js.map +1 -0
  94. package/dist/4337.js +1 -0
  95. package/dist/4337.js.map +1 -0
  96. package/dist/4735.js +1 -0
  97. package/dist/4735.js.map +1 -0
  98. package/dist/4744.js +1 -0
  99. package/dist/4744.js.map +1 -0
  100. package/dist/4813.js +2 -0
  101. package/dist/4813.js.map +1 -0
  102. package/dist/4858.js +1 -0
  103. package/dist/4858.js.map +1 -0
  104. package/dist/487.js +1 -0
  105. package/dist/487.js.map +1 -0
  106. package/dist/4970.js +1 -0
  107. package/dist/4970.js.map +1 -0
  108. package/dist/5202.js +1 -0
  109. package/dist/5202.js.map +1 -0
  110. package/dist/5294.js +1 -0
  111. package/dist/5294.js.map +1 -0
  112. package/dist/545.js +1 -0
  113. package/dist/545.js.map +1 -0
  114. package/dist/552.js +1 -0
  115. package/dist/552.js.map +1 -0
  116. package/dist/5592.js +1 -0
  117. package/dist/5592.js.map +1 -0
  118. package/dist/5669.js +1 -0
  119. package/dist/5669.js.map +1 -0
  120. package/dist/5884.js +1 -0
  121. package/dist/5884.js.map +1 -0
  122. package/dist/5940.js +1 -0
  123. package/dist/5940.js.map +1 -0
  124. package/dist/6092.js +1 -0
  125. package/dist/6092.js.map +1 -0
  126. package/dist/6155.js +1 -0
  127. package/dist/6155.js.map +1 -0
  128. package/dist/6178.js +1 -0
  129. package/dist/6178.js.map +1 -0
  130. package/dist/6399.js +1 -0
  131. package/dist/6399.js.map +1 -0
  132. package/dist/6456.js +1 -0
  133. package/dist/6466.js +3 -0
  134. package/dist/6466.js.map +1 -0
  135. package/dist/6492.js +1 -0
  136. package/dist/6492.js.map +1 -0
  137. package/dist/6676.js +1 -0
  138. package/dist/6676.js.map +1 -0
  139. package/dist/6800.js +1 -0
  140. package/dist/6800.js.map +1 -0
  141. package/dist/6976.js +1 -0
  142. package/dist/6976.js.map +1 -0
  143. package/dist/7005.js +1 -0
  144. package/dist/7005.js.map +1 -0
  145. package/dist/7201.js +1 -0
  146. package/dist/7201.js.map +1 -0
  147. package/dist/7210.js +1 -0
  148. package/dist/7210.js.map +1 -0
  149. package/dist/7234.js +1 -0
  150. package/dist/7234.js.map +1 -0
  151. package/dist/7261.js +1 -0
  152. package/dist/7261.js.map +1 -0
  153. package/dist/7326.js +1 -0
  154. package/dist/7463.js +1 -0
  155. package/dist/7463.js.map +1 -0
  156. package/dist/7528.js +1 -0
  157. package/dist/7528.js.map +1 -0
  158. package/dist/7584.js +1 -0
  159. package/dist/7584.js.map +1 -0
  160. package/dist/7607.js +1 -0
  161. package/dist/7717.js +1 -0
  162. package/dist/7717.js.map +1 -0
  163. package/dist/7737.js +1 -0
  164. package/dist/7737.js.map +1 -0
  165. package/dist/7739.js +1 -0
  166. package/dist/7739.js.map +1 -0
  167. package/dist/7765.js +1 -0
  168. package/dist/7765.js.map +1 -0
  169. package/dist/7820.js +1 -0
  170. package/dist/7820.js.map +1 -0
  171. package/dist/7844.js +1 -0
  172. package/dist/7844.js.map +1 -0
  173. package/dist/7866.js +1 -0
  174. package/dist/7866.js.map +1 -0
  175. package/dist/7916.js +1 -0
  176. package/dist/7916.js.map +1 -0
  177. package/dist/7971.js +1 -0
  178. package/dist/7971.js.map +1 -0
  179. package/dist/8159.js +7 -0
  180. package/dist/8159.js.map +1 -0
  181. package/dist/8244.js +1 -0
  182. package/dist/8244.js.map +1 -0
  183. package/dist/8262.js +1 -0
  184. package/dist/8262.js.map +1 -0
  185. package/dist/834.js +1 -0
  186. package/dist/834.js.map +1 -0
  187. package/dist/8376.js +1 -0
  188. package/dist/8376.js.map +1 -0
  189. package/dist/845.js +1 -0
  190. package/dist/845.js.map +1 -0
  191. package/dist/8546.js +1 -0
  192. package/dist/8546.js.map +1 -0
  193. package/dist/8570.js +1 -0
  194. package/dist/8570.js.map +1 -0
  195. package/dist/87.js +1 -0
  196. package/dist/87.js.map +1 -0
  197. package/dist/8727.js +1 -0
  198. package/dist/8828.js +1 -0
  199. package/dist/8828.js.map +1 -0
  200. package/dist/8860.js +1 -0
  201. package/dist/8860.js.map +1 -0
  202. package/dist/9036.js +1 -0
  203. package/dist/9036.js.map +1 -0
  204. package/dist/9124.js +1 -0
  205. package/dist/9124.js.map +1 -0
  206. package/dist/9182.js +1 -0
  207. package/dist/921.js +1 -0
  208. package/dist/921.js.map +1 -0
  209. package/dist/9404.js +1 -0
  210. package/dist/9404.js.map +1 -0
  211. package/dist/9406.js +1 -0
  212. package/dist/9406.js.map +1 -0
  213. package/dist/9446.js +1 -0
  214. package/dist/9446.js.map +1 -0
  215. package/dist/9449.js +1 -0
  216. package/dist/9449.js.map +1 -0
  217. package/dist/9566.js +5 -0
  218. package/dist/9566.js.map +1 -0
  219. package/dist/9641.js +1 -0
  220. package/dist/9641.js.map +1 -0
  221. package/dist/9711.js +1 -0
  222. package/dist/9711.js.map +1 -0
  223. package/dist/9801.js +1 -0
  224. package/dist/9801.js.map +1 -0
  225. package/dist/9835.js +11 -0
  226. package/dist/9835.js.map +1 -0
  227. package/dist/kenyaemr-esm-admin-app.js +5 -5
  228. package/dist/kenyaemr-esm-admin-app.js.buildmanifest.json +2704 -155
  229. package/dist/kenyaemr-esm-admin-app.js.map +1 -1
  230. package/dist/main.js +5 -31
  231. package/dist/main.js.map +1 -1
  232. package/dist/routes.json +1 -1
  233. package/package.json +6 -7
  234. package/rspack.config.js +1 -1
  235. package/src/components/facility-setup/facility-info.component.tsx +163 -94
  236. package/src/components/facility-setup/facility-info.scss +98 -55
  237. package/src/components/facility-setup/header/header.component.tsx +4 -10
  238. package/src/components/facility-setup/header/header.scss +3 -9
  239. package/src/components/facility-setup/shared/custom-info.component.tsx +9 -0
  240. package/src/components/facility-setup/shared/custom-section-card.component.tsx +10 -0
  241. package/src/components/facility-setup/shared/custom-status-tag.component.tsx +22 -0
  242. package/src/components/locations/forms/add-location/add-location.workspace.tsx +96 -95
  243. package/src/components/locations/forms/search-location/search-location.workspace.tsx +90 -85
  244. package/src/components/locations/tables/locations-table.component.tsx +117 -121
  245. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-workspace/user-role-scope.workspace.tsx +15 -15
  246. package/src/components/users/manage-users/user-list/user-list.component.tsx +22 -9
  247. package/src/components/users/manage-users/user-management.workspace.tsx +538 -531
  248. package/src/index.ts +51 -28
  249. package/src/root.component.tsx +11 -13
  250. package/src/routes.json +40 -40
  251. package/src/types/index.ts +29 -1
  252. package/src/user-management.resources.ts +5 -11
  253. package/translations/am.json +26 -8
  254. package/translations/en.json +26 -8
  255. package/translations/sw.json +26 -8
  256. package/tsconfig.json +1 -1
  257. package/dist/127.js +0 -1
  258. package/dist/267.js +0 -1
  259. package/dist/267.js.map +0 -1
  260. package/dist/281.js +0 -15
  261. package/dist/281.js.map +0 -1
  262. package/dist/329.js +0 -1
  263. package/dist/329.js.map +0 -1
  264. package/dist/40.js +0 -1
  265. package/dist/466.js +0 -1
  266. package/dist/466.js.map +0 -1
  267. package/dist/472.js +0 -1
  268. package/dist/472.js.map +0 -1
  269. package/dist/478.js +0 -1
  270. package/dist/478.js.map +0 -1
  271. package/dist/585.js +0 -1
  272. package/dist/585.js.map +0 -1
  273. package/dist/630.js +0 -1
  274. package/dist/630.js.map +0 -1
  275. package/dist/675.js +0 -1
  276. package/dist/675.js.map +0 -1
  277. package/dist/689.js +0 -1
  278. package/dist/689.js.map +0 -1
  279. package/dist/706.js +0 -27
  280. package/dist/706.js.map +0 -1
  281. package/dist/729.js +0 -17
  282. package/dist/729.js.map +0 -1
  283. package/dist/774.js +0 -1
  284. package/dist/774.js.map +0 -1
  285. package/dist/847.js +0 -1
  286. package/dist/847.js.map +0 -1
  287. package/dist/85.js +0 -1
  288. package/dist/85.js.map +0 -1
  289. package/dist/882.js +0 -1
  290. package/dist/91.js +0 -1
  291. package/dist/91.js.map +0 -1
  292. package/dist/916.js +0 -1
  293. package/dist/998.js +0 -1
  294. package/dist/998.js.map +0 -1
  295. package/jest.config.js +0 -8
  296. package/src/components/facility-setup/card.component.tsx +0 -16
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"locationsLeftPanelLink","name":"locations-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"},{"component":"providerBanner","name":"provider-banner","slot":"provider-banner-info-slot","order":1}],"workspaces":[{"name":"manage-user-workspace","component":"manageUserWorkspace","title":"Manage User Workspace","type":"other-form","canMaximize":true,"width":"extra-wide"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","title":"User Rple Scope Workspace","type":"other-form","canMaximize":true,"width":"extra-wide"},{"name":"add-location-workspace","title":"Add Location","component":"addLocation","type":"workspace"},{"name":"search-location-workspace","title":"Search Location","component":"searchLocationWorkspace","type":"workspace"},{"name":"hwr-sync-workspace","title":"HWR Sync Workspace","component":"hwrSyncWorkspace","type":"other-form"},{"name":"hwr-sync-modal","title":"HWR Sync Modal","component":"hwrSyncModal","type":"modal"}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"},{"component":"hwrConfirmationModal","name":"hwr-confirmation-modal"},{"component":"hwrEmptyModal","name":"hwr-empty-modal"},{"component":"hwrSyncModal","name":"hwr-syncing-modal"}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.3"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemrCharts":"^1.6.7"},"extensions":[{"component":"adminLeftPanelLink","name":"admin-left-panel-link","slot":"admin-left-panel-slot"},{"component":"userManagementLeftPannelLink","name":"user-management-left-panel-link","slot":"admin-left-panel-slot"},{"component":"etlAdministrationLeftPannelLink","name":"etl-administration-left-panel-link","slot":"admin-left-panel-slot"},{"component":"locationsLeftPanelLink","name":"locations-left-panel-link","slot":"admin-left-panel-slot"},{"component":"facilitySetupLeftPanelLink","name":"facility-setup-left-panel-link","slot":"admin-left-panel-slot"},{"component":"providerBanner","name":"provider-banner","slot":"provider-banner-info-slot","order":1}],"modals":[{"component":"operationConfirmationModal","name":"operation-confirmation-modal"},{"component":"hwrConfirmationModal","name":"hwr-confirmation-modal"},{"component":"hwrEmptyModal","name":"hwr-empty-modal"},{"component":"hwrSyncModal","name":"hwr-syncing-modal"}],"workspaces2":[{"name":"manage-user-workspace","component":"manageUserWorkspace","window":"esm-admin-extra-wide-workspace-window"},{"name":"user-role-scope-workspace","component":"userRoleScopeWorkspace","window":"esm-admin-workspace-window"},{"name":"add-location-workspace","component":"addLocation","window":"esm-admin-workspace-window"},{"name":"search-location-workspace","component":"searchLocationWorkspace","window":"esm-admin-workspace-window"}],"workspaceWindows2":[{"name":"esm-admin-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group"},{"name":"esm-admin-extra-wide-workspace-window","canMaximize":true,"group":"esm-admin-workspace-group","width":"extra-wide"}],"workspaceGroups2":[{"name":"esm-admin-workspace-group","scopePattern":"/admin","closeable":true}],"pages":[{"component":"root","route":"admin"}],"version":"5.4.4-pre.100"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-admin-app",
3
- "version": "5.4.3",
3
+ "version": "5.4.4-pre.100",
4
4
  "description": "Facilitates the management of ETL tables",
5
5
  "keywords": [
6
6
  "openmrs"
@@ -18,16 +18,14 @@
18
18
  "source": true,
19
19
  "browser": "dist/kenyaemr-esm-admin-app.js",
20
20
  "scripts": {
21
- "analyze": "rspack --mode=production --env analyze=true",
21
+ "analyze": "rspack build --mode=production --analyze",
22
22
  "build": "rspack --mode=production",
23
- "coverage": "yarn test --coverage",
23
+ "coverage": "echo \"Jest has been removed; no unit test runner is configured\" && exit 0",
24
24
  "debug": "npm run serve",
25
25
  "extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js",
26
26
  "lint": "eslint src --ext ts,tsx",
27
27
  "serve": "rspack serve --mode=development",
28
28
  "start": "openmrs develop",
29
- "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
30
- "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
31
29
  "typescript": "tsc"
32
30
  },
33
31
  "browserslist": [
@@ -39,7 +37,7 @@
39
37
  },
40
38
  "peerDependencies": {
41
39
  "@carbon/react": "1.x",
42
- "@openmrs/esm-framework": "8.x",
40
+ "@openmrs/esm-framework": "9.x",
43
41
  "react": "^18.1.0",
44
42
  "react-i18next": "11.x",
45
43
  "react-router-dom": "6.x",
@@ -47,5 +45,6 @@
47
45
  },
48
46
  "publishConfig": {
49
47
  "access": "public"
50
- }
48
+ },
49
+ "stableVersion": "5.4.3"
51
50
  }
package/rspack.config.js CHANGED
@@ -1 +1 @@
1
- module.exports = require('openmrs/default-rspack-config');
1
+ module.exports = require('../../tools/rs-pack-code-spliting');
@@ -1,78 +1,53 @@
1
- import { Button, Column, Grid, InlineLoading, Layer, Tile } from '@carbon/react';
1
+ import { Button, Column, Grid, InlineLoading, Layer, Tag, Tile } from '@carbon/react';
2
2
  import { formatDate, parseDate, showSnackbar } from '@openmrs/esm-framework';
3
3
  import React, { useCallback, useMemo, useState } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { useLocalFacilityInfo, useShaFacilityInfo } from '../hook/useFacilityInfo';
6
6
  import styles from './facility-info.scss';
7
- import Card from './card.component';
8
- import dayjs from 'dayjs';
9
7
  import { syncPackagesAndInterventions } from './facility-setup.resource';
8
+ import { Renew, Phone, Email } from '@carbon/react/icons';
9
+ import { SectionCard } from './shared/custom-section-card.component';
10
+ import { InfoRow } from './shared/custom-info.component';
11
+ import { StatusTag } from './shared/custom-status-tag.component';
10
12
 
11
13
  const FacilityInfo: React.FC = () => {
12
14
  const { t } = useTranslation();
13
- const [shouldSynchronize, setshouldSynchronize] = useState<boolean>(false);
15
+ const [shouldSynchronize, setShouldSynchronize] = useState(false);
16
+
14
17
  const {
15
18
  shaFacility,
16
- isLoading: isShaFacilityLoading,
17
- error: shaFacilityError,
18
- mutate: mutateShafacility,
19
+ isLoading: isShaLoading,
20
+ error: shaError,
21
+ mutate: mutateSha,
19
22
  } = useShaFacilityInfo(shouldSynchronize);
20
- const {
21
- localFacility,
22
- isLoading: isLocalFacilityLoading,
23
- mutate: mutateLocalFacility,
24
- error: localFacilityError,
25
- } = useLocalFacilityInfo();
23
+ const { localFacility, isLoading: isLocalLoading, mutate: mutateLocal } = useLocalFacilityInfo();
24
+
26
25
  const mutateFacility = useCallback(async () => {
27
- const defaultFacility = await mutateLocalFacility();
28
- const shaFacility = await mutateShafacility();
29
- return {
30
- shaFacility,
31
- defaultFacility,
32
- };
33
- }, [mutateLocalFacility, mutateShafacility]);
34
- const shaStatus = useMemo(
35
- () =>
36
- shaFacility?.operationalStatus
37
- ? `${shaFacility.operationalStatus.at(0).toUpperCase()}${shaFacility.operationalStatus
38
- .slice(1)
39
- ?.toLocaleLowerCase()}`
40
- : undefined,
41
- [shaFacility],
42
- );
43
- const shaExpiry = useMemo(
44
- () =>
45
- shaFacility?.shaFacilityExpiryDate && dayjs(shaFacility.shaFacilityExpiryDate).isValid()
46
- ? formatDate(parseDate(shaFacility.shaFacilityExpiryDate))
47
- : undefined,
48
- [shaFacility],
49
- );
26
+ const [defaultFacility, sha] = await Promise.all([mutateLocal(), mutateSha()]);
27
+ return { shaFacility: sha, defaultFacility };
28
+ }, [mutateLocal, mutateSha]);
29
+
30
+ const isLoading = isShaLoading || isLocalLoading;
50
31
 
51
32
  const synchronizeFacilityData = useCallback(async () => {
52
33
  try {
53
- setshouldSynchronize(true);
54
- const { shaFacility } = await mutateFacility();
55
- showSnackbar({
56
- title: t('syncingHieSuccess', 'Synchronization Complete'),
57
- kind: 'success',
58
- isLowContrast: true,
59
- });
60
- if (shaFacility.data?.source != 'HIE') {
34
+ setShouldSynchronize(true);
35
+ const { shaFacility: synced } = await mutateFacility();
36
+ showSnackbar({ title: t('syncingHieSuccess', 'Synchronization complete'), kind: 'success', isLowContrast: true });
37
+ if (synced?.data?.source !== 'HIE') {
61
38
  showSnackbar({
62
39
  kind: 'warning',
63
- title: 'HIE Sync Failed. Pulling local info.',
40
+ title: t('hieSyncFailed', 'HIE sync failed. Pulling local info.'),
64
41
  isLowContrast: true,
65
42
  });
66
43
  }
67
- // sync packages and intervensions
68
44
  await syncPackagesAndInterventions();
69
45
  } catch (error) {
70
- const errorMessage =
71
- error?.responseBody?.error?.message ??
72
- t('hieSynchronizationError', 'An error occurred while synchronizing with HIE');
73
46
  showSnackbar({
74
- title: t('syncingHieError', 'Syncing with HIE Failed'),
75
- subtitle: errorMessage,
47
+ title: t('syncingHieError', 'Syncing with HIE failed'),
48
+ subtitle:
49
+ error?.responseBody?.error?.message ??
50
+ t('hieSynchronizationError', 'An error occurred while synchronizing with HIE'),
76
51
  kind: 'error',
77
52
  isLowContrast: true,
78
53
  });
@@ -80,59 +55,153 @@ const FacilityInfo: React.FC = () => {
80
55
  }, [mutateFacility, t]);
81
56
 
82
57
  return (
83
- <div className={styles.facilityInfoContainer}>
84
- <div>
85
- <Layer className={styles.btnLayer}>
86
- {isShaFacilityLoading || isLocalFacilityLoading ? (
87
- <InlineLoading
88
- description={t('synchronizingFacilityData', 'Please wait, Synchronizing Info.')}
89
- className={styles.loading}
90
- />
58
+ <div className={styles.root}>
59
+ <div className={styles.pageHeader}>
60
+ <div className={styles.pageActions}>
61
+ {isLoading ? (
62
+ <InlineLoading description={t('synchronizing', 'Synchronizing...')} />
91
63
  ) : (
92
- <Button kind="primary" onClick={synchronizeFacilityData}>
93
- {t('synchronizeWithHie', 'Synchronize with HIE')}
64
+ <Button kind="secondary" size="sm" renderIcon={Renew} onClick={synchronizeFacilityData}>
65
+ {t('syncWithHie', 'Sync with HIE')}
94
66
  </Button>
95
67
  )}
96
- </Layer>
68
+ </div>
97
69
  </div>
70
+ <Grid narrow className={styles.grid}>
71
+ <Column sm={4} md={4} lg={8}>
72
+ <SectionCard title={t('generalInformation', 'General information')}>
73
+ <InfoRow label={t('facilityName', 'Facility name')} value={localFacility?.display} />
74
+ <InfoRow label={t('registrationNumber', 'Registration no.')} value={shaFacility?.registrationNumber} />
75
+ <InfoRow label={t('fidCode', 'FID code')} value={shaFacility?.fidCode} />
76
+ <InfoRow label={t('facilityRegistryCode', 'Registry code')} value={shaFacility?.facilityRegistryCode} />
77
+ <InfoRow
78
+ label={t('mflCode', 'MFL code')}
79
+ value={shaFacility?.mflCode !== '--' ? shaFacility?.mflCode : localFacility?.locationId}
80
+ />
81
+ <InfoRow label={t('kephLevel', 'KEPH level')} value={shaFacility?.kephLevel} />
82
+ <InfoRow label={t('facilityType', 'Facility type')} value={shaFacility?.facilityType} />
83
+ <InfoRow label={t('facilityOwnership', 'Ownership')} value={shaFacility?.facilityOwnership} />
84
+ <InfoRow
85
+ label={t('hubFacility', 'Hub facility')}
86
+ value={
87
+ <Tag type={shaFacility?.isHub === 'true' ? 'blue' : 'gray'} size="sm">
88
+ {shaFacility?.isHub === 'true' ? 'Yes' : 'No'}
89
+ </Tag>
90
+ }
91
+ />
92
+ </SectionCard>
93
+ </Column>
98
94
 
99
- <Grid narrow>
100
- {/* General Info Column */}
101
95
  <Column sm={4} md={4} lg={8}>
102
- <Tile className={styles.card}>
103
- <h3 className={styles.cardTitle}>{t('generalInformation', 'General Information')}</h3>
104
- <hr className={styles.cardDivider} />
105
- <div className={styles.cardContent}>
106
- <Card label={t('facilityName', 'Facility Name')} value={localFacility?.display} />
107
- <Card label={t('facilityCode', 'Facility KMHFR Code')} value={shaFacility?.mflCode} />
108
- <Card label={t('kephLevel', 'Keph Level')} value={shaFacility?.kephLevel} />
109
- <br />
110
- <br />
111
- </div>
112
- </Tile>
96
+ <SectionCard title={t('licenseAndShaStatus', 'License & SHA status')}>
97
+ <InfoRow label={t('licenseNumber', 'License no.')} value={shaFacility?.shaFacilityLicenseNumber} />
98
+ <InfoRow label={t('regulatoryBody', 'Regulatory body')} value={shaFacility?.regulatoryBody} />
99
+ <InfoRow
100
+ label={t('licenseStatus', 'License status')}
101
+ value={<StatusTag value={shaFacility?.facilityLicenseStatus} />}
102
+ />
103
+ <InfoRow
104
+ label={t('licenseStart', 'License start')}
105
+ value={formatDate(parseDate(shaFacility?.facilityLicenseStartDate)) ?? '—'}
106
+ />
107
+ <InfoRow
108
+ label={t('licenseExpiry', 'License expiry')}
109
+ value={formatDate(parseDate(shaFacility?.shaFacilityExpiryDate)) ?? '—'}
110
+ />
111
+ <InfoRow
112
+ label={t('operationalStatus', 'Operational status')}
113
+ value={<StatusTag value={shaFacility?.operationalStatus} />}
114
+ />
115
+ <InfoRow
116
+ label={t('shaContractStatus', 'SHA contract')}
117
+ value={
118
+ shaFacility?.shaContractStatus &&
119
+ shaFacility.shaContractStatus !== '--' &&
120
+ shaFacility.shaContractStatus !== '' ? (
121
+ <StatusTag value={shaFacility.shaContractStatus} />
122
+ ) : (
123
+ <Tag type="gray" size="sm">
124
+ Not contracted
125
+ </Tag>
126
+ )
127
+ }
128
+ />
129
+ <InfoRow label={t('totalBeds', 'Total beds')} value={shaFacility?.totalBeds} />
130
+ </SectionCard>
113
131
  </Column>
114
132
 
115
- {/* SHA Info Column */}
116
133
  <Column sm={4} md={4} lg={8}>
117
- <Layer>
118
- <Tile className={styles.card}>
119
- <h3 className={styles.cardTitle}>{t('facilityInformation', 'Facility Information')}</h3>
120
- <hr className={styles.cardDivider} />
121
- <div className={styles.cardContent}>
122
- <Card
123
- label={t('facilityRegistryCode', 'Facility Registry Code')}
124
- value={shaFacility?.facilityRegistryCode}
125
- />
126
- <Card
127
- label={t('shalicenceNumber', 'SHA License Number')}
128
- value={shaFacility?.shaFacilityLicenseNumber}
129
- />
130
- <Card label={t('shaStatus', 'SHA Status')} value={shaStatus} />
131
- <Card label={t('shaContracted', 'SHA Contracted')} value={shaFacility?.approved} />
132
- <Card label={t('shaContractExpiry', 'SHA Contract Expiry Date')} value={shaExpiry} />
134
+ <SectionCard title={t('location', 'Location')}>
135
+ <InfoRow label={t('county', 'County')} value={shaFacility?.county} />
136
+ <InfoRow label={t('subCounty', 'Sub-county')} value={shaFacility?.subCounty} />
137
+ <InfoRow label={t('town', 'Town')} value={shaFacility?.town} />
138
+ <InfoRow label={t('physicalLocation', 'Physical location')} value={shaFacility?.physicalLocation} />
139
+ <InfoRow label={t('postalAddress', 'Postal address')} value={shaFacility?.postalAddress} />
140
+ </SectionCard>
141
+ </Column>
142
+
143
+ <Column sm={4} md={4} lg={8}>
144
+ <SectionCard title={t('contactAndAdministrator', 'Contact & administrator')}>
145
+ <InfoRow
146
+ label={t('facilityPhone', 'Phone')}
147
+ value={
148
+ shaFacility?.facilityPhoneNumber && shaFacility.facilityPhoneNumber !== '--' ? (
149
+ <span className={styles.contactValue}>
150
+ <Phone size={14} />
151
+ {shaFacility.facilityPhoneNumber}
152
+ </span>
153
+ ) : undefined
154
+ }
155
+ />
156
+ <InfoRow
157
+ label={t('facilityEmail', 'Email')}
158
+ value={
159
+ shaFacility?.facilityEmail && shaFacility.facilityEmail !== '--' ? (
160
+ <span className={styles.contactValue}>
161
+ <Email size={14} />
162
+ {shaFacility.facilityEmail}
163
+ </span>
164
+ ) : undefined
165
+ }
166
+ />
167
+ {shaFacility?.facilityAdministratorName && shaFacility.facilityAdministratorName !== '--' && (
168
+ <div className={styles.adminCard}>
169
+ <div>
170
+ <p className={styles.adminName}>{shaFacility.facilityAdministratorName}</p>
171
+ <p className={styles.adminDetail}>{shaFacility.facilityAdministratorPhone}</p>
172
+ <p className={styles.adminDetail}>{shaFacility.facilityAdministratorEmail}</p>
173
+ </div>
133
174
  </div>
134
- </Tile>
135
- </Layer>
175
+ )}
176
+ </SectionCard>
177
+ </Column>
178
+
179
+ <Column sm={4} md={8} lg={16}>
180
+ <SectionCard title={t('shaContractedServices', 'SHA contracted services')}>
181
+ {(() => {
182
+ try {
183
+ const services = JSON.parse(shaFacility?.shaContractedServices ?? '[]');
184
+ if (services.length === 0) {
185
+ return (
186
+ <p className={styles.emptyState}>
187
+ {t('noContractedServices', 'No contracted services on record for this facility.')}
188
+ </p>
189
+ );
190
+ }
191
+ return (
192
+ <div className={styles.serviceList}>
193
+ {services.map((svc: any, idx: number) => (
194
+ <Tag key={idx} type="teal" size="sm">
195
+ {svc.name ?? svc}
196
+ </Tag>
197
+ ))}
198
+ </div>
199
+ );
200
+ } catch {
201
+ return <p className={styles.emptyState}>—</p>;
202
+ }
203
+ })()}
204
+ </SectionCard>
136
205
  </Column>
137
206
  </Grid>
138
207
  </div>
@@ -2,86 +2,129 @@
2
2
  @use '@carbon/type';
3
3
  @use '@carbon/colors';
4
4
 
5
- .omrs-main-content {
6
- background-color: colors.$white;
5
+ .root {
6
+ padding: layout.$spacing-05;
7
7
  }
8
8
 
9
- .bottomBorder {
9
+ .pageHeader {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: space-between;
10
13
  margin-bottom: layout.$spacing-05;
11
14
  }
12
15
 
13
- .btnLayer {
16
+ .pageTitle {
17
+ @include type.type-style('heading-03');
18
+ color: colors.$gray-100;
19
+ margin: 0;
20
+ }
21
+
22
+ .pageActions {
14
23
  display: flex;
15
- padding-top: layout.$spacing-05;
16
- padding-right: layout.$spacing-05;
17
- padding-bottom: layout.$spacing-05;
18
- margin-top: layout.$spacing-05;
19
- flex-direction: row;
20
- justify-content: flex-end;
21
- background-color: white;
22
- width: 100%;
24
+ align-items: center;
25
+ gap: layout.$spacing-03;
26
+ margin-left: auto;
27
+ margin-right: layout.$spacing-09;
28
+ }
29
+ .grid {
30
+ margin-top: 0;
23
31
  }
24
32
 
25
- .tableLayer {
26
- padding-left: layout.$spacing-05;
27
- padding-right: layout.$spacing-05;
28
- background: white;
29
- padding-top: layout.$spacing-01;
33
+ .sectionCard {
34
+ padding: layout.$spacing-05 !important;
35
+ background: white !important;
36
+ border: 1px solid colors.$gray-20 !important;
37
+ border-radius: 8px !important;
38
+ margin-bottom: layout.$spacing-05;
39
+ box-shadow: none !important;
30
40
  }
31
41
 
32
- .loading {
42
+ .sectionTitle {
43
+ @include type.type-style('label-01');
44
+ font-weight: 600;
45
+ color: colors.$gray-60;
46
+ text-transform: uppercase;
47
+ letter-spacing: 0.06em;
48
+ margin: 0 0 layout.$spacing-04;
49
+ padding-bottom: layout.$spacing-03;
50
+ border-bottom: 1px solid colors.$gray-20;
51
+ }
52
+
53
+ .sectionBody {
33
54
  display: flex;
34
- padding-top: layout.$spacing-05;
35
- padding-right: layout.$spacing-05;
36
- padding-bottom: layout.$spacing-05;
37
- margin-top: layout.$spacing-05;
38
- flex-direction: row;
39
- justify-content: flex-end;
40
- background-color: white;
41
- width: 100%;
55
+ flex-direction: column;
42
56
  }
43
57
 
44
- .facilityInfoContainer {
45
- margin: layout.$spacing-05;
58
+ /* ── Info rows ── */
59
+ .infoRow {
60
+ display: flex;
61
+ justify-content: space-between;
62
+ align-items: baseline;
63
+ padding: layout.$spacing-02 0;
64
+ border-bottom: 1px solid colors.$gray-10;
65
+
66
+ &:last-child {
67
+ border-bottom: none;
68
+ }
46
69
  }
47
70
 
48
- .card {
49
- padding: 1rem;
50
- background-color: colors.$gray-10;
51
- border: 1px solid #e0e0e0;
52
- border-radius: 2px;
53
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
71
+ .infoLabel {
72
+ @include type.type-style('body-01');
73
+ color: colors.$gray-60;
74
+ flex-shrink: 0;
75
+ margin-right: layout.$spacing-05;
54
76
  }
55
77
 
56
- .cardTitle {
57
- margin-bottom: 1rem;
58
- font-size: 1.25rem;
59
- font-weight: 600;
78
+ .infoValue {
79
+ @include type.type-style('body-01');
80
+ font-weight: 500;
81
+ color: colors.$gray-100;
82
+ text-align: right;
83
+ word-break: break-word;
60
84
  }
61
85
 
62
- .cardDivider {
63
- border: none;
64
- border-top: 1px solid #e0e0e0;
65
- margin: 0.5rem 0;
86
+ .emptyValue {
87
+ color: colors.$gray-40;
88
+ font-weight: 400;
66
89
  }
67
- .cardContent {
68
- font-size: 1rem;
69
- line-height: 1.8;
90
+
91
+ .contactValue {
92
+ display: flex;
93
+ align-items: center;
94
+ gap: layout.$spacing-02;
70
95
  }
71
96
 
72
- .cardContent p {
97
+ .adminCard {
73
98
  display: flex;
74
- justify-content: space-between;
75
- margin-bottom: 0.5rem;
99
+ align-items: flex-start;
100
+ gap: layout.$spacing-04;
101
+ margin-top: layout.$spacing-04;
102
+ padding-top: layout.$spacing-04;
103
+ border-top: 1px solid colors.$gray-10;
76
104
  }
77
- .cardContent br {
105
+ .adminName {
106
+ @include type.type-style('body-01');
107
+ font-weight: 500;
108
+ color: colors.$gray-100;
109
+ margin: 0 0 layout.$spacing-01;
110
+ text-transform: capitalize;
111
+ }
112
+
113
+ .adminDetail {
114
+ @include type.type-style('label-01');
115
+ color: colors.$gray-60;
116
+ margin: 0;
117
+ }
118
+
119
+ .serviceList {
78
120
  display: flex;
79
- justify-content: space-between;
80
- margin-bottom: 0.5rem;
121
+ flex-wrap: wrap;
122
+ gap: layout.$spacing-02;
81
123
  }
82
124
 
83
- .cardContent strong {
84
- min-width: 150px;
85
- display: inline-block;
86
- color: #393939;
125
+ .emptyState {
126
+ @include type.type-style('body-01');
127
+ color: colors.$gray-40;
128
+ font-style: italic;
129
+ margin: 0;
87
130
  }
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
- import { useTranslation } from 'react-i18next';
3
- import { Development } from '@carbon/react/icons';
4
- import { useSession, PageHeader } from '@openmrs/esm-framework';
2
+ import { PageHeader, PageHeaderContent, HomePictogram } from '@openmrs/esm-framework';
5
3
  import styles from './header.scss';
6
4
 
7
5
  interface HeaderProps {
@@ -9,14 +7,10 @@ interface HeaderProps {
9
7
  }
10
8
 
11
9
  const Header: React.FC<HeaderProps> = ({ title }) => {
12
- const { t } = useTranslation();
13
- const session = useSession();
14
- const location = session?.sessionLocation?.display;
15
-
16
10
  return (
17
- <div className={styles.header}>
18
- <PageHeader title={title} illustration={<Development size={32} />} className={styles.header} />
19
- </div>
11
+ <PageHeader className={styles.pageHeader}>
12
+ <PageHeaderContent title={title} illustration={<HomePictogram />} />
13
+ </PageHeader>
20
14
  );
21
15
  };
22
16
 
@@ -2,18 +2,12 @@
2
2
  @use '@carbon/type';
3
3
  @use '@carbon/colors';
4
4
 
5
- .header {
5
+ .pageHeader {
6
6
  @include type.type-style('body-compact-02');
7
7
  height: layout.$spacing-12;
8
8
  display: flex;
9
9
  justify-content: space-between;
10
10
  padding: layout.$spacing-05;
11
- background: white;
12
- border: 1px solid colors.$gray-20;
13
- }
14
- .svgContainer svg {
15
- width: layout.$spacing-10;
16
- height: layout.$spacing-10;
17
- margin-right: layout.$spacing-06;
18
- fill: var(--brand-03);
11
+ background: colors.$white-0;
12
+ border-bottom: 1px solid colors.$gray-20;
19
13
  }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import styles from '../facility-info.scss';
3
+
4
+ export const InfoRow: React.FC<{ label: string; value?: React.ReactNode }> = ({ label, value }) => (
5
+ <div className={styles.infoRow}>
6
+ <span className={styles.infoLabel}>{label}</span>
7
+ <span className={styles.infoValue}>{value ?? <span className={styles.emptyValue}>—</span>}</span>
8
+ </div>
9
+ );
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { Tile } from '@carbon/react';
3
+ import styles from '../facility-info.scss';
4
+
5
+ export const SectionCard: React.FC<{ title: string; children: React.ReactNode }> = ({ title, children }) => (
6
+ <Tile className={styles.sectionCard}>
7
+ <p className={styles.sectionTitle}>{title}</p>
8
+ <div className={styles.sectionBody}>{children}</div>
9
+ </Tile>
10
+ );
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { Tag } from '@carbon/react';
3
+ import styles from '../facility-info.scss';
4
+
5
+ export const StatusTag: React.FC<{ value?: string }> = ({ value }) => {
6
+ if (!value || value === '--' || value.trim() === '') {
7
+ return <span className={styles.emptyValue}>—</span>;
8
+ }
9
+ const upper = value.toUpperCase();
10
+ const type =
11
+ upper === 'ACTIVE' || upper === 'LICENSED'
12
+ ? 'green'
13
+ : upper === 'INACTIVE' || upper === 'SUSPENDED'
14
+ ? 'red'
15
+ : 'gray';
16
+ const label = `${value.charAt(0).toUpperCase()}${value.slice(1).toLowerCase()}`;
17
+ return (
18
+ <Tag type={type} size="sm">
19
+ {label}
20
+ </Tag>
21
+ );
22
+ };