@kenyaemr/esm-patient-flags-app 5.4.4-pre.96 → 5.4.5-pre.16

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 (192) hide show
  1. package/package.json +3 -3
  2. package/src/hooks/useDefaultFacility.ts +17 -8
  3. package/src/navbar/nav-utils.component.tsx +17 -3
  4. package/src/navbar/navbar-action-button.component.tsx +4 -2
  5. package/src/navbar/navbar-action-button.scss +9 -0
  6. package/src/navbar/navbar-link.component.tsx +60 -26
  7. package/src/navbar/navbar-link.scss +38 -3
  8. package/src/navbar/navbar-overlay.component.tsx +44 -11
  9. package/src/patient-diagnosis/patient-diagnosis.component.tsx +2 -2
  10. package/src/routes.json +5 -0
  11. package/translations/am.json +6 -1
  12. package/translations/en.json +6 -1
  13. package/translations/fr.json +32 -39
  14. package/translations/sw.json +6 -1
  15. package/.turbo/turbo-build.log +0 -6
  16. package/dist/1074.js +0 -1
  17. package/dist/1074.js.map +0 -1
  18. package/dist/12.js +0 -17
  19. package/dist/12.js.map +0 -1
  20. package/dist/1311.js +0 -1
  21. package/dist/1311.js.map +0 -1
  22. package/dist/1469.js +0 -1
  23. package/dist/1469.js.map +0 -1
  24. package/dist/1506.js +0 -13
  25. package/dist/1506.js.map +0 -1
  26. package/dist/1718.js +0 -1
  27. package/dist/1718.js.map +0 -1
  28. package/dist/1772.js +0 -1
  29. package/dist/1772.js.map +0 -1
  30. package/dist/1889.js +0 -1
  31. package/dist/1889.js.map +0 -1
  32. package/dist/1990.js +0 -1
  33. package/dist/1990.js.map +0 -1
  34. package/dist/2153.js +0 -1
  35. package/dist/2153.js.map +0 -1
  36. package/dist/216.js +0 -1
  37. package/dist/216.js.map +0 -1
  38. package/dist/2270.js +0 -1
  39. package/dist/2270.js.map +0 -1
  40. package/dist/2294.js +0 -1
  41. package/dist/2294.js.map +0 -1
  42. package/dist/2345.js +0 -1
  43. package/dist/2345.js.map +0 -1
  44. package/dist/2500.js +0 -1
  45. package/dist/2500.js.map +0 -1
  46. package/dist/251.js +0 -1
  47. package/dist/251.js.map +0 -1
  48. package/dist/2566.js +0 -1
  49. package/dist/257.js +0 -1
  50. package/dist/257.js.map +0 -1
  51. package/dist/2586.js +0 -1
  52. package/dist/2586.js.map +0 -1
  53. package/dist/2625.js +0 -1
  54. package/dist/2625.js.map +0 -1
  55. package/dist/2652.js +0 -1
  56. package/dist/2652.js.map +0 -1
  57. package/dist/2685.js +0 -1
  58. package/dist/2685.js.map +0 -1
  59. package/dist/2799.js +0 -1
  60. package/dist/2799.js.map +0 -1
  61. package/dist/2826.js +0 -1
  62. package/dist/2826.js.map +0 -1
  63. package/dist/2948.js +0 -1
  64. package/dist/2948.js.map +0 -1
  65. package/dist/3089.js +0 -1
  66. package/dist/3089.js.map +0 -1
  67. package/dist/3190.js +0 -1
  68. package/dist/3190.js.map +0 -1
  69. package/dist/3548.js +0 -1
  70. package/dist/3548.js.map +0 -1
  71. package/dist/3816.js +0 -1
  72. package/dist/3816.js.map +0 -1
  73. package/dist/3906.js +0 -1
  74. package/dist/3906.js.map +0 -1
  75. package/dist/3963.js +0 -1
  76. package/dist/3963.js.map +0 -1
  77. package/dist/405.js +0 -1
  78. package/dist/405.js.map +0 -1
  79. package/dist/4296.js +0 -1
  80. package/dist/4296.js.map +0 -1
  81. package/dist/4537.js +0 -1
  82. package/dist/4537.js.map +0 -1
  83. package/dist/4613.js +0 -1
  84. package/dist/4613.js.map +0 -1
  85. package/dist/4735.js +0 -1
  86. package/dist/4735.js.map +0 -1
  87. package/dist/4744.js +0 -1
  88. package/dist/4744.js.map +0 -1
  89. package/dist/4813.js +0 -2
  90. package/dist/4813.js.map +0 -1
  91. package/dist/4818.js +0 -1
  92. package/dist/4818.js.map +0 -1
  93. package/dist/4858.js +0 -1
  94. package/dist/4858.js.map +0 -1
  95. package/dist/487.js +0 -1
  96. package/dist/487.js.map +0 -1
  97. package/dist/5202.js +0 -1
  98. package/dist/5202.js.map +0 -1
  99. package/dist/552.js +0 -1
  100. package/dist/552.js.map +0 -1
  101. package/dist/5592.js +0 -1
  102. package/dist/5592.js.map +0 -1
  103. package/dist/5669.js +0 -1
  104. package/dist/5669.js.map +0 -1
  105. package/dist/6092.js +0 -1
  106. package/dist/6092.js.map +0 -1
  107. package/dist/6178.js +0 -1
  108. package/dist/6178.js.map +0 -1
  109. package/dist/6456.js +0 -1
  110. package/dist/6466.js +0 -3
  111. package/dist/6466.js.map +0 -1
  112. package/dist/6492.js +0 -1
  113. package/dist/6492.js.map +0 -1
  114. package/dist/6495.js +0 -1
  115. package/dist/6495.js.map +0 -1
  116. package/dist/6800.js +0 -1
  117. package/dist/6800.js.map +0 -1
  118. package/dist/7005.js +0 -1
  119. package/dist/7005.js.map +0 -1
  120. package/dist/7201.js +0 -1
  121. package/dist/7201.js.map +0 -1
  122. package/dist/7210.js +0 -1
  123. package/dist/7210.js.map +0 -1
  124. package/dist/7234.js +0 -1
  125. package/dist/7234.js.map +0 -1
  126. package/dist/7261.js +0 -1
  127. package/dist/7261.js.map +0 -1
  128. package/dist/7326.js +0 -1
  129. package/dist/7463.js +0 -1
  130. package/dist/7463.js.map +0 -1
  131. package/dist/7591.js +0 -1
  132. package/dist/7591.js.map +0 -1
  133. package/dist/7607.js +0 -1
  134. package/dist/7701.js +0 -1
  135. package/dist/7701.js.map +0 -1
  136. package/dist/7717.js +0 -1
  137. package/dist/7717.js.map +0 -1
  138. package/dist/7739.js +0 -1
  139. package/dist/7739.js.map +0 -1
  140. package/dist/7765.js +0 -1
  141. package/dist/7765.js.map +0 -1
  142. package/dist/7820.js +0 -1
  143. package/dist/7820.js.map +0 -1
  144. package/dist/7971.js +0 -1
  145. package/dist/7971.js.map +0 -1
  146. package/dist/7995.js +0 -1
  147. package/dist/7995.js.map +0 -1
  148. package/dist/8159.js +0 -7
  149. package/dist/8159.js.map +0 -1
  150. package/dist/8177.js +0 -1
  151. package/dist/8177.js.map +0 -1
  152. package/dist/8244.js +0 -1
  153. package/dist/8244.js.map +0 -1
  154. package/dist/845.js +0 -1
  155. package/dist/845.js.map +0 -1
  156. package/dist/8524.js +0 -1
  157. package/dist/8524.js.map +0 -1
  158. package/dist/8570.js +0 -1
  159. package/dist/8570.js.map +0 -1
  160. package/dist/87.js +0 -1
  161. package/dist/87.js.map +0 -1
  162. package/dist/8727.js +0 -1
  163. package/dist/906.js +0 -1
  164. package/dist/9124.js +0 -1
  165. package/dist/9124.js.map +0 -1
  166. package/dist/9182.js +0 -1
  167. package/dist/921.js +0 -1
  168. package/dist/921.js.map +0 -1
  169. package/dist/9404.js +0 -1
  170. package/dist/9404.js.map +0 -1
  171. package/dist/9406.js +0 -1
  172. package/dist/9406.js.map +0 -1
  173. package/dist/9446.js +0 -1
  174. package/dist/9446.js.map +0 -1
  175. package/dist/9449.js +0 -1
  176. package/dist/9449.js.map +0 -1
  177. package/dist/9566.js +0 -5
  178. package/dist/9566.js.map +0 -1
  179. package/dist/9641.js +0 -1
  180. package/dist/9641.js.map +0 -1
  181. package/dist/9801.js +0 -1
  182. package/dist/9801.js.map +0 -1
  183. package/dist/9835.js +0 -11
  184. package/dist/9835.js.map +0 -1
  185. package/dist/9900.js +0 -1
  186. package/dist/9900.js.map +0 -1
  187. package/dist/main.js +0 -5
  188. package/dist/main.js.map +0 -1
  189. package/dist/openmrs-esm-patient-flags-app.js +0 -5
  190. package/dist/openmrs-esm-patient-flags-app.js.buildmanifest.json +0 -2480
  191. package/dist/openmrs-esm-patient-flags-app.js.map +0 -1
  192. package/dist/routes.json +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-patient-flags-app",
3
- "version": "5.4.4-pre.96",
3
+ "version": "5.4.5-pre.16",
4
4
  "description": "Patient flags microfrontend for the OpenMRS SPA",
5
5
  "keywords": [
6
6
  "openmrs"
@@ -22,7 +22,7 @@
22
22
  "build": "rspack --mode=production",
23
23
  "coverage": "echo \"Jest has been removed; no unit test runner is configured\" && exit 0",
24
24
  "debug": "npm run serve",
25
- "extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js",
25
+ "extract-translations": "i18next 'src/**/*.{ts,tsx}' --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",
@@ -44,5 +44,5 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "stableVersion": "5.4.3"
47
+ "stableVersion": "5.4.4"
48
48
  }
@@ -1,18 +1,27 @@
1
1
  import { FetchResponse, openmrsFetch, restBaseUrl, useSession } from '@openmrs/esm-framework';
2
2
  import useSWR from 'swr';
3
- import { DefaultFacility } from '../types';
4
3
 
5
- export function useDefaultFacility() {
4
+ type FacilityRegistryStatus = {
5
+ sha_operational_status?: string;
6
+ regulatory_operational_status?: string;
7
+ };
8
+
9
+ export const useFacilityRegistry = () => {
6
10
  const { authenticated } = useSession();
7
- const url = `${restBaseUrl}/kenyaemr/default-facility`;
8
- const { data, isLoading, error } = useSWR<FetchResponse<DefaultFacility>>(
11
+ const url = `${restBaseUrl}/virtualclaims/facility-registry`;
12
+ const { data, isLoading, error, mutate } = useSWR<FetchResponse<FacilityRegistryStatus>>(
9
13
  authenticated ? url : null,
10
14
  openmrsFetch,
11
- {},
15
+ { revalidateOnFocus: false },
12
16
  );
17
+
18
+ const notYetSynced = (error as any)?.response?.status === 404;
19
+
13
20
  return {
14
21
  isLoading,
15
- defaultFacility: data?.data,
16
- error,
22
+ facility: data?.data,
23
+ error: notYetSynced ? null : error,
24
+ notYetSynced,
25
+ mutate,
17
26
  };
18
- }
27
+ };
@@ -10,9 +10,11 @@ import {
10
10
  Receipt,
11
11
  Renew,
12
12
  Report,
13
+ Review,
13
14
  User,
14
15
  VolumeFileStorage,
15
16
  WatsonHealthCrossReference,
17
+ WorkflowAutomation,
16
18
  } from '@carbon/react/icons';
17
19
  import { CalendarIcon, useConfig } from '@openmrs/esm-framework';
18
20
  import React from 'react';
@@ -26,7 +28,7 @@ const handleClearCache = async () => {
26
28
  });
27
29
  localStorage.clear();
28
30
  sessionStorage.clear();
29
- window.location.reload();
31
+ globalThis.location.reload();
30
32
  };
31
33
 
32
34
  export const useModuleLinks = () => {
@@ -117,7 +119,7 @@ export const useModuleLinks = () => {
117
119
  },
118
120
  {
119
121
  label: t('reports', 'Reports'),
120
- url: `/openmrs/kenyaemr/reports/reportsHome.page`,
122
+ url: `${openmrsSpaBase}reporting`,
121
123
  icon: <Report size={24} />,
122
124
  privilege: 'o3: View Reports',
123
125
  },
@@ -157,7 +159,19 @@ export const useModuleLinks = () => {
157
159
  icon: <IbmCloudGateKeeper size={24} />,
158
160
  privilege: 'o3: View Queue Screen Dashboard',
159
161
  },
162
+ {
163
+ label: t('serviceAvailabilityAdmin', 'Service Availability Admin'),
164
+ url: `${openmrsSpaBase}service-available-admin`,
165
+ icon: <Review size={24} />,
166
+ privilege: 'o3: View Service Availability Admin Dashboard',
167
+ },
168
+ {
169
+ label: t('claimsAdmin', 'Claims Admin'),
170
+ url: `${openmrsSpaBase}claims-admin`,
171
+ icon: <Review size={24} />,
172
+ privilege: 'o3: View Claims Admin Dashboard',
173
+ },
160
174
  ];
161
175
 
162
- return moduleLinks.filter((link) => !excludeLinks.some((excludeLink) => excludeLink === link.label));
176
+ return moduleLinks.filter((link) => !excludeLinks.includes(link.label));
163
177
  };
@@ -14,11 +14,13 @@ const DEBOUNCE_TIME = 500;
14
14
  const NavbarActionButton: React.FC<NavbarActionButtonProps> = () => {
15
15
  const { t } = useTranslation();
16
16
  const moduleLinks = useModuleLinks();
17
+ const sortedModuleLinks = [...moduleLinks].sort((a, b) => a.label.localeCompare(b.label));
17
18
  const { instanceName } = useConfig<ConfigObject>();
18
19
  const [showOverlay, setShowOverlay] = React.useState(false);
19
20
  const [searchTerm, setSearchTerm] = useState('');
20
21
  const title = t('instanceModules', '{{instanceName}}Modules', { instanceName });
21
22
  const toggleOverlay = () => {
23
+ setSearchTerm('');
22
24
  setShowOverlay((prevState) => !prevState);
23
25
  };
24
26
  const ref = useOnClickOutside<HTMLDivElement>(toggleOverlay, showOverlay);
@@ -26,8 +28,8 @@ const NavbarActionButton: React.FC<NavbarActionButtonProps> = () => {
26
28
  const debounceSearchTerm = useDebounce(searchTerm, DEBOUNCE_TIME);
27
29
  const searchResults =
28
30
  debounceSearchTerm === ''
29
- ? moduleLinks
30
- : moduleLinks.filter((item) => item.label.toLowerCase().includes(searchTerm.toLowerCase()));
31
+ ? sortedModuleLinks
32
+ : sortedModuleLinks.filter((item) => item.label.toLowerCase().includes(searchTerm.toLowerCase()));
31
33
 
32
34
  return (
33
35
  <div id="module" ref={ref}>
@@ -22,6 +22,7 @@
22
22
  display: grid;
23
23
  grid-template-rows: auto 1fr auto;
24
24
  z-index: 999;
25
+ overflow-y: auto;
25
26
  }
26
27
 
27
28
  :global(.omrs-breakpoint-lt-small-desktop) .overlay {
@@ -54,6 +55,7 @@
54
55
  column-gap: 0.5rem;
55
56
  row-gap: 1rem;
56
57
  padding: 0 1rem 1rem 1rem;
58
+ overflow-y: auto;
57
59
  }
58
60
 
59
61
  .navLinkItem {
@@ -100,3 +102,10 @@
100
102
  .illo {
101
103
  margin-top: layout.$spacing-05;
102
104
  }
105
+
106
+ .extensionSlot {
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ gap: layout.$spacing-03;
111
+ }
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
+ import { Warning, CheckmarkFilled } from '@carbon/react/icons';
3
+ import { Tooltip } from '@carbon/react';
2
4
  import { navigate } from '@openmrs/esm-framework';
5
+ import { useTranslation } from 'react-i18next';
3
6
  import styles from './navbar-link.scss';
4
- import { useDefaultFacility } from '../hooks/useDefaultFacility';
5
- import dayjs from 'dayjs';
6
- import { Warning } from '@carbon/react/icons';
7
+ import { useFacilityRegistry } from '../hooks/useDefaultFacility';
7
8
 
8
9
  type NavBarLinkItemProps = {
9
10
  icon: React.ReactNode;
@@ -14,41 +15,74 @@ type NavBarLinkItemProps = {
14
15
  };
15
16
 
16
17
  const NavBarLink: React.FC<NavBarLinkItemProps> = ({ icon, label, url, hideOverlay, onClick }) => {
17
- const { defaultFacility } = useDefaultFacility();
18
-
19
- const itemHasError = () => {
20
- if (label === 'System Info') {
21
- // Enable once the date is availed
22
- /* if (!dayjs(defaultFacility?.shaFacilityExpiryDate).isValid()) {
23
- return true;
24
- } else {
25
- return dayjs(defaultFacility?.shaFacilityExpiryDate).isBefore(dayjs());
26
- }
27
- */
28
- return defaultFacility?.operationalStatus !== 'Operational';
18
+ const { t } = useTranslation();
19
+ const { facility, notYetSynced } = useFacilityRegistry();
20
+
21
+ const normalize = (val?: string | null) => val?.toString().trim().toUpperCase() ?? '';
22
+
23
+ const isStatusItem = label === 'System Info';
24
+ const hasFacilityData = !notYetSynced && !!facility;
25
+
26
+ const getFacilityIssues = (): string[] => {
27
+ if (!isStatusItem || !hasFacilityData) {
28
+ return [];
29
+ }
30
+
31
+ const issues: string[] = [];
32
+ const shaOperational = normalize(facility!.sha_operational_status);
33
+ const regulatoryOperational = normalize(facility!.regulatory_operational_status);
34
+
35
+ if (shaOperational && shaOperational !== 'ACTIVE') {
36
+ issues.push(t('shaOperationalNotActive', 'SHA operational status is not active'));
29
37
  }
30
- return false;
38
+
39
+ if (regulatoryOperational && regulatoryOperational !== 'ACTIVE') {
40
+ issues.push(t('regulatoryNotActive', 'Regulatory operational status is not active'));
41
+ }
42
+
43
+ return issues;
31
44
  };
32
45
 
33
- const hasError = itemHasError();
46
+ const issues = getFacilityIssues();
47
+ const hasError = issues.length > 0;
48
+ const isHealthy = isStatusItem && hasFacilityData && !hasError;
34
49
 
35
- const handleClick = (url) => {
50
+ const handleClick = (url?: string) => {
36
51
  hideOverlay(false);
37
52
  if (!url) {
38
- return onClick && onClick();
53
+ return onClick?.();
39
54
  }
40
55
  navigate({ to: url });
41
56
  };
57
+
58
+ const tooltipLabel = issues.length === 1 ? issues[0] : issues.map((issue) => `• ${issue}`).join('\n');
59
+
60
+ const buttonClass = [styles.navLinkItem, hasError && styles.warning, isHealthy && styles.healthy]
61
+ .filter(Boolean)
62
+ .join(' ');
63
+
42
64
  return (
43
- <div
44
- role="button"
45
- tabIndex={0}
46
- onClick={() => handleClick(url)}
47
- className={`${styles.navLinkItem} ${hasError ? styles.warning : ''}`}>
48
- {hasError && <Warning className={styles.navError} />}
65
+ <button type="button" onClick={() => handleClick(url)} className={buttonClass}>
66
+ {hasError && (
67
+ <Tooltip label={tooltipLabel} align="bottom" className={styles.navErrorTooltip}>
68
+ <span className={styles.navErrorWrapper}>
69
+ <Warning className={styles.navError} />
70
+ </span>
71
+ </Tooltip>
72
+ )}
73
+ {isHealthy && (
74
+ <Tooltip
75
+ label={t('facilityActive', 'Facility is active and operational')}
76
+ align="bottom"
77
+ className={styles.navHealthyTooltip}>
78
+ <span className={styles.navHealthyWrapper}>
79
+ <CheckmarkFilled className={styles.navHealthy} />
80
+ </span>
81
+ </Tooltip>
82
+ )}
49
83
  {icon}
50
84
  <span>{label}</span>
51
- </div>
85
+ </button>
52
86
  );
53
87
  };
54
88
 
@@ -6,19 +6,53 @@
6
6
  background-color: colors.$red-30 !important;
7
7
  }
8
8
 
9
- .navError {
9
+ .healthy {
10
+ background-color: colors.$green-20 !important;
11
+
12
+ &:hover {
13
+ background-color: colors.$green-30 !important;
14
+ }
15
+ }
16
+
17
+ .navErrorTooltip {
18
+ position: absolute;
19
+ top: layout.$spacing-01;
20
+ right: layout.$spacing-01;
21
+ z-index: 1;
22
+ }
23
+
24
+ .navHealthyTooltip {
10
25
  position: absolute;
11
- color: colors.$red-70;
12
26
  top: layout.$spacing-01;
13
27
  right: layout.$spacing-01;
28
+ z-index: 1;
29
+ }
30
+
31
+ .navErrorWrapper,
32
+ .navHealthyWrapper {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ cursor: help;
37
+ }
38
+
39
+ .navError {
40
+ color: colors.$red-70;
41
+ }
42
+
43
+ .navHealthy {
44
+ color: colors.$green-70;
14
45
  }
15
46
 
16
47
  .navLinkItem {
48
+ border: none;
17
49
  display: flex;
18
50
  flex-direction: column;
19
- align-items: center;
20
51
  min-height: layout.$spacing-12;
21
52
  min-width: 8.5rem;
53
+ max-width: 8.5rem;
54
+ padding: 0 layout.$spacing-02;
55
+ align-items: center;
22
56
  height: 7rem;
23
57
  justify-content: center;
24
58
  background-color: colors.$cool-gray-10;
@@ -28,6 +62,7 @@
28
62
 
29
63
  & > span {
30
64
  @include type.type-style('body-01');
65
+ text-align: center;
31
66
  }
32
67
 
33
68
  &:hover {
@@ -2,7 +2,7 @@ import React, { useCallback, useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { Button, Layer, Search, Tile } from '@carbon/react';
4
4
  import { EmptyDataIllustration } from '@openmrs/esm-patient-common-lib';
5
- import { UserHasAccess } from '@openmrs/esm-framework';
5
+ import { Extension, ExtensionSlot, useExtensionSlotMeta, UserHasAccess } from '@openmrs/esm-framework';
6
6
  import NavBarLink from './navbar-link.component';
7
7
  import styles from './navbar-action-button.scss';
8
8
 
@@ -23,7 +23,26 @@ interface NavBarOverlayProps {
23
23
 
24
24
  const NavBarOverlay: React.FC<NavBarOverlayProps> = ({ setSearchTerm, modules, searchTerm, hideOverlay }) => {
25
25
  const { t } = useTranslation();
26
-
26
+ /*
27
+ Note: Extract meta from extensions and looks for search string array which helps resolve the seach on extension links
28
+ All the link extension should be decleared with meta with search array e.g
29
+ {
30
+ "name": "tnt-module-link",
31
+ "slot": "navbar-items-slot",
32
+ "component": "tntNavLink",
33
+ "meta": {
34
+ "search": ["tnt", "Track", "trace"]
35
+ }
36
+ }
37
+ */
38
+ const meta = useExtensionSlotMeta('navbar-items-slot');
39
+ const { hasCandidateMatchingSearchTerm } = useMemo(() => {
40
+ const slotMeta = Object.entries(meta);
41
+ const allSearchCandidates = slotMeta.flatMap(([slotMeta, meta]) => (meta?.search ?? []) as Array<string>);
42
+ const hasCandidateMatchingSearchTerm =
43
+ allSearchCandidates.findIndex((s) => t(s, s).toLowerCase().includes(searchTerm.toLowerCase())) !== -1;
44
+ return { hasCandidateMatchingSearchTerm, allSearchCandidates };
45
+ }, [meta, searchTerm, t]);
27
46
  const handleClearSearch = useCallback(
28
47
  (event: React.MouseEvent) => {
29
48
  event.stopPropagation();
@@ -41,15 +60,17 @@ const NavBarOverlay: React.FC<NavBarOverlayProps> = ({ setSearchTerm, modules, s
41
60
  // Add logic to render module links based on user privileges
42
61
  const renderModuleLinks = useMemo(
43
62
  () =>
44
- modules.map((item, index) =>
45
- item?.privilege ? (
46
- <UserHasAccess key={index} privilege={item.privilege}>
47
- <NavBarLink key={index} {...item} hideOverlay={hideOverlay} />
63
+ modules.map((item) => {
64
+ const key = item.url ?? item.label;
65
+
66
+ return item?.privilege ? (
67
+ <UserHasAccess key={key} privilege={item.privilege}>
68
+ <NavBarLink {...item} hideOverlay={hideOverlay} />
48
69
  </UserHasAccess>
49
70
  ) : (
50
- <NavBarLink key={index} {...item} hideOverlay={hideOverlay} />
51
- ),
52
- ),
71
+ <NavBarLink key={key} {...item} hideOverlay={hideOverlay} />
72
+ );
73
+ }),
53
74
  [modules, hideOverlay],
54
75
  );
55
76
 
@@ -84,8 +105,20 @@ const NavBarOverlay: React.FC<NavBarOverlayProps> = ({ setSearchTerm, modules, s
84
105
  onChange={handleSearchChange}
85
106
  />
86
107
 
87
- {modules.length === 0 && renderEmptyState()}
88
- {modules.length > 0 && <div className={styles.navLinks}>{renderModuleLinks}</div>}
108
+ {modules.length === 0 && !hasCandidateMatchingSearchTerm && renderEmptyState()}
109
+ <div className={styles.navLinks}>
110
+ {renderModuleLinks}
111
+ <ExtensionSlot className={styles.extensionSlot} name="navbar-items-slot">
112
+ {(ext) => {
113
+ const search = (ext.meta?.search ?? []) as Array<string>;
114
+ const show = search.findIndex((s) => t(s, s).toLowerCase().includes(searchTerm.toLowerCase())) !== -1;
115
+ if (show) {
116
+ return <Extension state={{ hideOverlay }} />;
117
+ }
118
+ return <React.Fragment />;
119
+ }}
120
+ </ExtensionSlot>
121
+ </div>
89
122
  </div>
90
123
  </div>
91
124
  );
@@ -61,8 +61,8 @@ const PatientDiagnosisContent: React.FC<PatientDiagnosisContentProps> = ({ patie
61
61
  lowContrast={true}
62
62
  statusIconDescription="notification"
63
63
  subtitle={t(
64
- 'noMainDiagnosisSubtitle',
65
- 'Main diagnosis is required for claim processing, please add main diagnosis to the clinical encounter form',
64
+ 'noMainDiagnosisSubtitlecWarning',
65
+ 'Main diagnosis is required, please add main diagnosis to the clinical encounter form',
66
66
  )}
67
67
  title={t('noMainDiagnosis', 'Main diagnosis required')}
68
68
  hideCloseButton={true}
package/src/routes.json CHANGED
@@ -4,6 +4,11 @@
4
4
  "kenyaemr": "^19.0.0"
5
5
  },
6
6
  "pages": [],
7
+ "extensionSlots": {
8
+ "navbar-items-slot": {
9
+ "add": []
10
+ }
11
+ },
7
12
  "extensions": [
8
13
  {
9
14
  "name": "patient-flag",
@@ -5,12 +5,14 @@
5
5
  "bedManagement": "የአልጋ አስተዳደር",
6
6
  "billingAdmin": "Billing Admin",
7
7
  "caseManagement": "Case Management",
8
+ "claimsAdmin": "Claims Admin",
8
9
  "clearCache": "መሸጎጫ አጽዳ",
9
10
  "clearSearch": "ፍለጋ አጽዳ",
10
11
  "crossBorder": "ድንበር ተሻጋሪ",
11
12
  "dispensingApp": "የመድኃኒት ማከፋፈያ መተግበሪያ",
12
13
  "emptyLinkSearchText": "የፍለጋ መስፈርቶቹን የሚያሟሉ ምንም አገናኞች የሉም",
13
14
  "errorPatientFlags": "የታካሚ ባንዲራዎችን በመጫን ላይ ስህተት",
15
+ "facilityActive": "Facility is active and operational",
14
16
  "facilityDashboard": "የተቋም ዳሽቦርድ",
15
17
  "formBuilder": "የቅጽ ገንቢ",
16
18
  "instanceHomeLink": "{{instanceName}}Home",
@@ -20,12 +22,15 @@
20
22
  "legacyAdmin": "Legacy Admin",
21
23
  "manageStocks": "አክሲዮኖችን አስተዳድር",
22
24
  "noMainDiagnosis": "Main diagnosis required",
23
- "noMainDiagnosisSubtitle": "Main diagnosis is required for claim processing",
25
+ "noMainDiagnosisSubtitlecWarning": "Main diagnosis is required, please add main diagnosis to the clinical encounter form",
24
26
  "queueScreen": "Queue Screen",
25
27
  "referrals": "ሪፈራሎች",
28
+ "regulatoryNotActive": "Regulatory operational status is not active",
26
29
  "reports": "ሪፖርቶች",
27
30
  "search": "ሞጁል ፈልግ",
31
+ "serviceAvailabilityAdmin": "Service Availability Admin",
28
32
  "serviceQueuesAdmin": "የመምሪያ ዘዴዎች አስተዳደር",
33
+ "shaOperationalNotActive": "SHA operational status is not active",
29
34
  "suppliesDispensing": "አቅርቦቶች ማከፋፈል",
30
35
  "systemInfo": "የስርዓት መረጃ"
31
36
  }
@@ -5,12 +5,14 @@
5
5
  "bedManagement": "Bed Management",
6
6
  "billingAdmin": "Billing Admin",
7
7
  "caseManagement": "Case Management",
8
+ "claimsAdmin": "Claims Admin",
8
9
  "clearCache": "Clear Cache",
9
10
  "clearSearch": "Clear search",
10
11
  "crossBorder": "Cross Border",
11
12
  "dispensingApp": "Dispensing App",
12
13
  "emptyLinkSearchText": "There are no links to display that match the search criteria",
13
14
  "errorPatientFlags": "Error loading patient flags",
15
+ "facilityActive": "Facility is active and operational",
14
16
  "facilityDashboard": "Facility Dashboard",
15
17
  "formBuilder": "Form Builder",
16
18
  "instanceHomeLink": "{{instanceName}}Home",
@@ -20,12 +22,15 @@
20
22
  "legacyAdmin": "Legacy Admin",
21
23
  "manageStocks": "Manage Stocks",
22
24
  "noMainDiagnosis": "Main diagnosis required",
23
- "noMainDiagnosisSubtitle": "Main diagnosis is required for claim processing",
25
+ "noMainDiagnosisSubtitlecWarning": "Main diagnosis is required, please add main diagnosis to the clinical encounter form",
24
26
  "queueScreen": "Queue Screen",
25
27
  "referrals": "Referrals",
28
+ "regulatoryNotActive": "Regulatory operational status is not active",
26
29
  "reports": "Reports",
27
30
  "search": "Search for a module",
31
+ "serviceAvailabilityAdmin": "Service Availability Admin",
28
32
  "serviceQueuesAdmin": "Service Queues Admin",
33
+ "shaOperationalNotActive": "SHA operational status is not active",
29
34
  "suppliesDispensing": "Supplies Dispensing",
30
35
  "systemInfo": "System Info"
31
36
  }
@@ -1,43 +1,36 @@
1
1
  {
2
- "actions": "Actions",
3
- "address": "Adresse",
4
- "age": "Age",
5
- "any": "N'importe quel",
6
- "apply": "Appliquer",
7
- "clear": "Effacer",
2
+ "administration": "Administration",
3
+ "adrAssessment": "Évaluation des effets indésirables",
4
+ "appointments": "Rendez-vous",
5
+ "bedManagement": "Gestion des lits",
6
+ "billingAdmin": "Services facturables",
7
+ "caseManagement": "Gestion des cas",
8
+ "claimsAdmin": "Administration des sinistres",
9
+ "clearCache": "Vider le cache",
8
10
  "clearSearch": "Effacer",
9
- "contactDetails": "Informations de contact",
10
- "countOfFiltersApplied": "Filtres appliqués",
11
- "day": "Jour",
12
- "error": "Erreur",
13
- "errorCopy": "Désolé, une erreur s'est produite. Vous pouvez tenter de rafraîchir la page, ou bien contacter l'administrateur du site et transmettre le message d'erreur ci-dessus.",
14
- "female": "Femme",
15
- "filtersAppliedText": "Rechercher les requêtes ajoutées",
16
- "male": "Homme",
17
- "month": "Mois",
18
- "nextPage": "Page suivante",
19
- "noPatientChartsFoundMessage": "Désolé, aucun dossier de patient n'a été trouvé",
20
- "orPatientName": "OU le(s) nom(s) du patient",
21
- "other": "Autre",
22
- "phoneNumber": "Numéro de téléphone",
23
- "postcode": "Code postal",
24
- "previousPage": "Page précédente",
25
- "refineSearch": "Affiner la recherche",
26
- "refineSearchHeaderText": "Ajouter un critère de recherche supplémentaire",
27
- "refineSearchTabletBannerText": "Vous ne trouvez pas la personne recherchée?",
28
- "relationships": "Liens de parenté",
29
- "resetFields": "Réinitialisation des champs",
30
- "seachResultsSmall": "Résultats de recherche",
11
+ "crossBorder": "Transfrontalier",
12
+ "dispensingApp": "Dispensation",
13
+ "emptyLinkSearchText": "Aucun lien à afficher correspondant aux critères de recherche",
14
+ "errorPatientFlags": "Erreur lors du chargement des indicateurs du patient",
15
+ "facilityActive": "L’établissement est actif et opérationnel",
16
+ "facilityDashboard": "Tableau de bord",
17
+ "formBuilder": "Gestion des formulaires",
18
+ "instanceHomeLink": "{{instanceName}}Accueil",
19
+ "instanceModules": "{{instanceName}}Modules",
20
+ "kenyaEMRHome": "Accueil EMR",
21
+ "labManifestApp": "Application de manifeste de laboratoire",
22
+ "legacyAdmin": "Administration héritée",
23
+ "manageStocks": "Gestion des stocks",
24
+ "noMainDiagnosis": "Diagnostic principal requis",
25
+ "noMainDiagnosisSubtitlecWarning": "Le diagnostic principal est requis, veuillez ajouter le diagnostic principal au formulaire de consultation clinique",
26
+ "queueScreen": "Écran de file d’attente",
27
+ "referrals": "Références",
28
+ "regulatoryNotActive": "Regulatory operational status is not active",
29
+ "reports": "Rapports",
31
30
  "search": "Recherche",
32
- "searchForPatient": "Trouver un patient par nom ou identifiant",
33
- "searchingText": "Recherche",
34
- "searchPatient": "Rechercher un patient",
35
- "searchResults": "Résultats de recherche",
36
- "searchResultsText": "résultats de recherche",
37
- "sex": "Sexe",
38
- "showAllDetails": "Afficher toutes les informations",
39
- "showLess": "Afficher moins",
40
- "trySearchWithPatientUniqueID": "Essayez de chercher par l'identifiant unique du patient",
41
- "unknown": "Inconnu",
42
- "year": "Année"
31
+ "serviceAvailabilityAdmin": "Administration de la disponibilité des services",
32
+ "serviceQueuesAdmin": "Gestion des files d’attente",
33
+ "shaOperationalNotActive": "SHA operational status is not active",
34
+ "suppliesDispensing": "Dispensation des fournitures",
35
+ "systemInfo": "Informations système"
43
36
  }
@@ -5,12 +5,14 @@
5
5
  "bedManagement": "Bed Management",
6
6
  "billingAdmin": "Billing Admin",
7
7
  "caseManagement": "Case Management",
8
+ "claimsAdmin": "Claims Admin",
8
9
  "clearCache": "Clear Cache",
9
10
  "clearSearch": "Clear search",
10
11
  "crossBorder": "Cross Border",
11
12
  "dispensingApp": "Dispensing App",
12
13
  "emptyLinkSearchText": "There are no links to display that match the search criteria",
13
14
  "errorPatientFlags": "Error loading patient flags",
15
+ "facilityActive": "Facility is active and operational",
14
16
  "facilityDashboard": "Facility Dashboard",
15
17
  "formBuilder": "Form Builder",
16
18
  "instanceHomeLink": "{{instanceName}}Home",
@@ -20,12 +22,15 @@
20
22
  "legacyAdmin": "Legacy Admin",
21
23
  "manageStocks": "Manage Stocks",
22
24
  "noMainDiagnosis": "Main diagnosis required",
23
- "noMainDiagnosisSubtitle": "Main diagnosis is required for claim processing",
25
+ "noMainDiagnosisSubtitlecWarning": "Main diagnosis is required, please add main diagnosis to the clinical encounter form",
24
26
  "queueScreen": "Queue Screen",
25
27
  "referrals": "Referrals",
28
+ "regulatoryNotActive": "Regulatory operational status is not active",
26
29
  "reports": "Reports",
27
30
  "search": "Search for a module",
31
+ "serviceAvailabilityAdmin": "Service Availability Admin",
28
32
  "serviceQueuesAdmin": "Service Queues Admin",
33
+ "shaOperationalNotActive": "SHA operational status is not active",
29
34
  "suppliesDispensing": "Supplies Dispensing",
30
35
  "systemInfo": "System Info"
31
36
  }
@@ -1,6 +0,0 @@
1
- WARNING in ⚠ asset size limit: The following asset(s) exceed the recommended size limit (244.141 KiB). This can impact web performance.
2
- │ Assets:
3
- │ 2625.js (258.661 KiB)
4
- 
5
-
6
- Rspack compiled with 1 warning in 33.59 s