@kenyaemr/esm-pharmacy-app 5.2.1-pre.724

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 (85) hide show
  1. package/.turbo/turbo-build.log +32 -0
  2. package/LICENSE.md +401 -0
  3. package/README.md +5 -0
  4. package/dist/102.js +1 -0
  5. package/dist/102.js.map +1 -0
  6. package/dist/130.js +2 -0
  7. package/dist/130.js.LICENSE.txt +3 -0
  8. package/dist/130.js.map +1 -0
  9. package/dist/152.js +1 -0
  10. package/dist/152.js.map +1 -0
  11. package/dist/255.js +2 -0
  12. package/dist/255.js.LICENSE.txt +9 -0
  13. package/dist/255.js.map +1 -0
  14. package/dist/303.js +1 -0
  15. package/dist/303.js.map +1 -0
  16. package/dist/341.js +1 -0
  17. package/dist/341.js.map +1 -0
  18. package/dist/368.js +1 -0
  19. package/dist/368.js.map +1 -0
  20. package/dist/383.js +1 -0
  21. package/dist/383.js.map +1 -0
  22. package/dist/419.js +1 -0
  23. package/dist/419.js.map +1 -0
  24. package/dist/515.js +1 -0
  25. package/dist/515.js.map +1 -0
  26. package/dist/574.js +1 -0
  27. package/dist/591.js +2 -0
  28. package/dist/591.js.LICENSE.txt +32 -0
  29. package/dist/591.js.map +1 -0
  30. package/dist/682.js +2 -0
  31. package/dist/682.js.LICENSE.txt +35 -0
  32. package/dist/682.js.map +1 -0
  33. package/dist/729.js +1 -0
  34. package/dist/729.js.map +1 -0
  35. package/dist/75.js +1 -0
  36. package/dist/75.js.map +1 -0
  37. package/dist/784.js +2 -0
  38. package/dist/784.js.LICENSE.txt +9 -0
  39. package/dist/784.js.map +1 -0
  40. package/dist/883.js +1 -0
  41. package/dist/883.js.map +1 -0
  42. package/dist/kenyaemr-esm-pharmacy-app.js +1 -0
  43. package/dist/kenyaemr-esm-pharmacy-app.js.buildmanifest.json +556 -0
  44. package/dist/kenyaemr-esm-pharmacy-app.js.map +1 -0
  45. package/dist/main.js +1 -0
  46. package/dist/main.js.map +1 -0
  47. package/dist/routes.json +1 -0
  48. package/jest.config.js +8 -0
  49. package/package.json +55 -0
  50. package/src/autosuggest/autosuggest.component.tsx +187 -0
  51. package/src/autosuggest/autosuggest.scss +62 -0
  52. package/src/config-schema.ts +43 -0
  53. package/src/declarations.d.ts +6 -0
  54. package/src/hooks/index.ts +4 -0
  55. package/src/hooks/usePharmacy.ts +17 -0
  56. package/src/hooks/usePharmacyPatients.ts +48 -0
  57. package/src/hooks/usePharmacyUsers.ts +43 -0
  58. package/src/hooks/useUserMappedPharmacies.ts +47 -0
  59. package/src/index.ts +41 -0
  60. package/src/pharamacy-forms/delete-confirm-dialog.modal.tsx +26 -0
  61. package/src/pharamacy-forms/pharamacy-assignment-form.workspace.tsx +121 -0
  62. package/src/pharamacy-forms/pharmacy-assignment-form.scss +125 -0
  63. package/src/pharmacy-component/pharmacy.component.tsx +14 -0
  64. package/src/pharmacy-detail/pharmacy-detail.component.tsx +14 -0
  65. package/src/pharmacy-detail-header/pharmacy-detail-header.component.tsx +41 -0
  66. package/src/pharmacy-header/pharmacy-header.component.tsx +36 -0
  67. package/src/pharmacy-header/pharmacy-header.scss +71 -0
  68. package/src/pharmacy-header/pharmacy-illustration.component.tsx +13 -0
  69. package/src/pharmacy-left-panel/pharmacy-left-panel-link.component.tsx +40 -0
  70. package/src/pharmacy-tables/pharmacy-patients.component.tsx +221 -0
  71. package/src/pharmacy-tables/pharmacy-table.component.tsx +164 -0
  72. package/src/pharmacy-tables/pharmacy-tables.scss +49 -0
  73. package/src/pharmacy-tables/pharmacy-users.component.tsx +197 -0
  74. package/src/pharmacy-tabs/pharmacy-tabs-component.tsx +28 -0
  75. package/src/pharmacy-tabs/pharmacy-tabs.scss +28 -0
  76. package/src/pharmacy.resources.ts +55 -0
  77. package/src/root.component.tsx +19 -0
  78. package/src/root.scss +15 -0
  79. package/src/root.test.tsx +5 -0
  80. package/src/routes.json +38 -0
  81. package/src/setup-tests.ts +1 -0
  82. package/src/types/index.ts +67 -0
  83. package/translations/en.json +27 -0
  84. package/tsconfig.json +5 -0
  85. package/webpack.config.js +1 -0
@@ -0,0 +1,221 @@
1
+ import {
2
+ Button,
3
+ DataTable,
4
+ DataTableSkeleton,
5
+ Layer,
6
+ Pagination,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ Tile,
15
+ } from '@carbon/react';
16
+ import { Add, TrashCan } from '@carbon/react/icons';
17
+ import {
18
+ ErrorState,
19
+ UserHasAccess,
20
+ isDesktop,
21
+ launchWorkspace,
22
+ showModal,
23
+ showSnackbar,
24
+ useLayoutType,
25
+ usePagination,
26
+ } from '@openmrs/esm-framework';
27
+ import { CardHeader, EmptyDataIllustration, usePaginationInfo } from '@openmrs/esm-patient-common-lib';
28
+ import React, { useState } from 'react';
29
+ import { useTranslation } from 'react-i18next';
30
+ import { useParams } from 'react-router-dom';
31
+ import { mutate } from 'swr';
32
+ import { usePharmacyPatients } from '../hooks';
33
+ import { revokePharamacyAssignment } from '../pharmacy.resources';
34
+ import styles from './pharmacy-tables.scss';
35
+
36
+ export const PharmacyPatients: React.FC = () => {
37
+ const { pharmacyUuid } = useParams();
38
+ const { t } = useTranslation();
39
+ const [currentPageSize, setCurrentPageSize] = useState<number>(10);
40
+ const { error, patients, isLoading } = usePharmacyPatients(pharmacyUuid);
41
+ const headerTitle = t('pharmacyPatients', 'Pharmacy Patients');
42
+
43
+ const [pageSize, setPageSize] = useState(10);
44
+
45
+ const { results, totalPages, currentPage, goTo } = usePagination(patients, pageSize);
46
+ const { pageSizes } = usePaginationInfo(pageSize, totalPages, currentPage, results.length);
47
+ const layout = useLayoutType();
48
+
49
+ const launchDeleteModal = (patientUuid: string) => {
50
+ const dispose = showModal('pharmacy-delete-confirm-dialog', {
51
+ onDelete: () => {
52
+ handleRevoke(patientUuid);
53
+ dispose();
54
+ },
55
+ onClose: () => dispose(),
56
+ });
57
+ };
58
+
59
+ const headers = [
60
+ {
61
+ header: t('openmrsId', 'OpenMRS ID'),
62
+ key: 'openmrsId',
63
+ },
64
+ {
65
+ header: t('name', 'Name'),
66
+ key: 'name',
67
+ },
68
+ {
69
+ header: t('age', 'Age'),
70
+ key: 'age',
71
+ },
72
+ {
73
+ header: t('sex', 'Sex'),
74
+ key: 'sex',
75
+ },
76
+ {
77
+ header: t('contact', 'Contact'),
78
+ key: 'contact',
79
+ },
80
+ {
81
+ header: t('dateMapped', 'Date Mapped'),
82
+ key: 'dateMapped',
83
+ },
84
+ {
85
+ header: t('actions', 'Actions'),
86
+ key: 'actions',
87
+ },
88
+ ];
89
+
90
+ const tableRows =
91
+ results?.map((patient) => {
92
+ return {
93
+ id: `${patient.uuid}`,
94
+ openmrsId: patient.openmrsId,
95
+ name: patient.name,
96
+ age: patient.age ?? '--',
97
+ sex: patient.gender ?? '--',
98
+ contact: patient.telephoneContact ?? '--',
99
+ dateMapped: patient.dateMapped,
100
+ actions: (
101
+ <UserHasAccess privilege={'coreapps.systemAdministration'} fallback={`--`}>
102
+ <Button
103
+ kind="tertiary"
104
+ renderIcon={TrashCan}
105
+ onClick={() => {
106
+ launchDeleteModal(patient.uuid);
107
+ }}>
108
+ Revoke
109
+ </Button>
110
+ </UserHasAccess>
111
+ ),
112
+ };
113
+ }) ?? [];
114
+
115
+ const handdleAssignToPharmacy = () => {
116
+ launchWorkspace('pharmacy-assignment-form', {
117
+ workspaceTitle: 'Pharmacy Assignment Form',
118
+ pharmacyUuid,
119
+ type: 'org.openmrs.Patient',
120
+ });
121
+ };
122
+
123
+ const handleRevoke = async (patientUuid: string) => {
124
+ try {
125
+ const results = await revokePharamacyAssignment({
126
+ entityIdentifier: patientUuid,
127
+ basisIdentifier: pharmacyUuid,
128
+ entityType: 'org.openmrs.Patient',
129
+ basisType: 'org.openmrs.Location',
130
+ });
131
+ showSnackbar({ kind: 'success', subtitle: results, title: 'Success' });
132
+
133
+ mutate((key) => {
134
+ return typeof key === 'string' && key.startsWith(`/ws/rest/v1/datafilter/search?type=org.openmrs.Patient`);
135
+ });
136
+ } catch (error) {
137
+ showSnackbar({ kind: 'error', subtitle: error.message, title: 'Failure' });
138
+ }
139
+ };
140
+
141
+ if (isLoading) {
142
+ return <DataTableSkeleton rowCount={5} />;
143
+ }
144
+ if (error) {
145
+ return <ErrorState headerTitle={headerTitle} error={error} />;
146
+ }
147
+
148
+ if (patients.length === 0) {
149
+ return (
150
+ <Layer>
151
+ <Tile className={styles.tile}>
152
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
153
+ <h4>{headerTitle}</h4>
154
+ </div>
155
+ <EmptyDataIllustration />
156
+ <p className={styles.content}>{t('noPharmacyPatients', 'No Pharmacy Patients to list.')}</p>
157
+ <UserHasAccess privilege={'coreapps.systemAdministration'}>
158
+ <Button onClick={handdleAssignToPharmacy} renderIcon={Add} kind="ghost">
159
+ {t('assignPatient', 'Assign Patient')}
160
+ </Button>
161
+ </UserHasAccess>
162
+ </Tile>
163
+ </Layer>
164
+ );
165
+ }
166
+ return (
167
+ <div className={styles.widgetContainer}>
168
+ <CardHeader title={headerTitle}>
169
+ <UserHasAccess privilege={'coreapps.systemAdministration'}>
170
+ <Button onClick={handdleAssignToPharmacy} renderIcon={Add} kind="ghost">
171
+ {t('assignPatient', 'Assign Patient')}
172
+ </Button>
173
+ </UserHasAccess>
174
+ </CardHeader>
175
+ <DataTable
176
+ useZebraStyles
177
+ size="sm"
178
+ rows={tableRows ?? []}
179
+ headers={headers}
180
+ render={({ rows, headers, getHeaderProps, getTableProps, getTableContainerProps }) => (
181
+ <TableContainer {...getTableContainerProps()}>
182
+ <Table {...getTableProps()}>
183
+ <TableHead>
184
+ <TableRow>
185
+ {headers.map((header) => (
186
+ <TableHeader
187
+ {...getHeaderProps({
188
+ header,
189
+ isSortable: header.isSortable,
190
+ })}>
191
+ {header.header?.content ?? header.header}
192
+ </TableHeader>
193
+ ))}
194
+ </TableRow>
195
+ </TableHead>
196
+ <TableBody>
197
+ {rows.map((row) => (
198
+ <TableRow key={row.id}>
199
+ {row.cells.map((cell) => (
200
+ <TableCell key={cell.id}>{cell.value}</TableCell>
201
+ ))}
202
+ </TableRow>
203
+ ))}
204
+ </TableBody>
205
+ </Table>
206
+ </TableContainer>
207
+ )}
208
+ />
209
+ <Pagination
210
+ page={currentPage}
211
+ pageSize={pageSize}
212
+ pageSizes={pageSizes}
213
+ totalItems={patients.length}
214
+ onChange={({ page, pageSize }) => {
215
+ goTo(page);
216
+ setPageSize(pageSize);
217
+ }}
218
+ />
219
+ </div>
220
+ );
221
+ };
@@ -0,0 +1,164 @@
1
+ import {
2
+ Button,
3
+ DataTable,
4
+ DataTableSkeleton,
5
+ Layer,
6
+ Pagination,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ Tile,
15
+ } from '@carbon/react';
16
+ import { Add } from '@carbon/react/icons';
17
+ import {
18
+ ConfigurableLink,
19
+ ErrorState,
20
+ isDesktop,
21
+ useLayoutType,
22
+ usePagination,
23
+ useSession,
24
+ } from '@openmrs/esm-framework';
25
+ import { CardHeader, EmptyDataIllustration, usePaginationInfo } from '@openmrs/esm-patient-common-lib';
26
+ import React, { useState } from 'react';
27
+ import { useTranslation } from 'react-i18next';
28
+ import { useUserMappedPharmacies } from '../hooks';
29
+ import styles from './pharmacy-tables.scss';
30
+
31
+ const PharmaciesTable = () => {
32
+ const { t } = useTranslation();
33
+ const [currentPageSize, setCurrentPageSize] = useState<number>(10);
34
+ const {
35
+ user: { uuid: sessionUserUuid },
36
+ } = useSession();
37
+ const { error, pharmacies, isLoading } = useUserMappedPharmacies(sessionUserUuid);
38
+
39
+ const headerTitle = t('communityPharmacies', 'Community pharmacies');
40
+
41
+ const [pageSize, setPageSize] = useState(10);
42
+
43
+ const { results, totalPages, currentPage, goTo } = usePagination(pharmacies, pageSize);
44
+ const { pageSizes } = usePaginationInfo(pageSize, totalPages, currentPage, results.length);
45
+ const layout = useLayoutType();
46
+
47
+ const headers = [
48
+ {
49
+ header: t('name', 'Name'),
50
+ key: 'name',
51
+ },
52
+ {
53
+ header: t('dateMapped', 'Date Mapped'),
54
+ key: 'dateMapped',
55
+ },
56
+ {
57
+ header: t('cityVillage', 'City village'),
58
+ key: 'cityVillage',
59
+ },
60
+ {
61
+ header: t('stateProvince', 'State province'),
62
+ key: 'stateProvince',
63
+ },
64
+ {
65
+ header: t('countyDistrict', 'County District'),
66
+ key: 'countyDistrict',
67
+ },
68
+ ];
69
+
70
+ const tableRows =
71
+ results?.map((pharmacy) => {
72
+ return {
73
+ id: `${pharmacy.uuid}`,
74
+ name: (
75
+ <ConfigurableLink
76
+ to={window.getOpenmrsSpaBase() + `home/pharmacy/${pharmacy.uuid}`}
77
+ style={{ textDecoration: 'none' }}>
78
+ {pharmacy.name}
79
+ </ConfigurableLink>
80
+ ),
81
+ description: pharmacy.description ?? '--',
82
+ cityVillage: pharmacy.cityVillage ?? '--',
83
+ stateProvince: pharmacy.stateProvince ?? '--',
84
+ countyDistrict: pharmacy.countyDistrict ?? '--',
85
+ dateMapped: pharmacy.dateMaped,
86
+ };
87
+ }) ?? [];
88
+
89
+ const handdleTagPharmacy = () => {};
90
+
91
+ if (isLoading) {
92
+ return <DataTableSkeleton rowCount={5} />;
93
+ }
94
+ if (error) {
95
+ return <ErrorState headerTitle={headerTitle} error={error} />;
96
+ }
97
+
98
+ if (pharmacies.length === 0) {
99
+ return (
100
+ <Layer>
101
+ <Tile className={styles.tile}>
102
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
103
+ <h4>{headerTitle}</h4>
104
+ </div>
105
+ <EmptyDataIllustration />
106
+ <p className={styles.content}>{t('noCommunityPharmacyToList', 'No Community Pharmacies to list.')}</p>
107
+ </Tile>
108
+ </Layer>
109
+ );
110
+ }
111
+ return (
112
+ <div className={styles.widgetContainer}>
113
+ <CardHeader title={`Community Pharmacies (${pharmacies.length})`}>
114
+ <div />
115
+ </CardHeader>
116
+ <DataTable
117
+ useZebraStyles
118
+ size="sm"
119
+ rows={tableRows ?? []}
120
+ headers={headers}
121
+ render={({ rows, headers, getHeaderProps, getTableProps, getTableContainerProps }) => (
122
+ <TableContainer {...getTableContainerProps()}>
123
+ <Table {...getTableProps()}>
124
+ <TableHead>
125
+ <TableRow>
126
+ {headers.map((header) => (
127
+ <TableHeader
128
+ {...getHeaderProps({
129
+ header,
130
+ isSortable: header.isSortable,
131
+ })}>
132
+ {header.header?.content ?? header.header}
133
+ </TableHeader>
134
+ ))}
135
+ </TableRow>
136
+ </TableHead>
137
+ <TableBody>
138
+ {rows.map((row) => (
139
+ <TableRow key={row.id}>
140
+ {row.cells.map((cell) => (
141
+ <TableCell key={cell.id}>{cell.value}</TableCell>
142
+ ))}
143
+ </TableRow>
144
+ ))}
145
+ </TableBody>
146
+ </Table>
147
+ </TableContainer>
148
+ )}
149
+ />
150
+ <Pagination
151
+ page={currentPage}
152
+ pageSize={pageSize}
153
+ pageSizes={pageSizes}
154
+ totalItems={pharmacies.length}
155
+ onChange={({ page, pageSize }) => {
156
+ goTo(page);
157
+ setPageSize(pageSize);
158
+ }}
159
+ />
160
+ </div>
161
+ );
162
+ };
163
+
164
+ export default PharmaciesTable;
@@ -0,0 +1,49 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/type';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .widgetContainer {
7
+ background-color: colors.$white-0;
8
+ border: 1px solid colors.$gray-20;
9
+ margin-bottom: 1rem;
10
+ }
11
+
12
+ .widgetContainer :global(.cds--data-table) thead th button span {
13
+ height: unset !important;
14
+ }
15
+
16
+ .tile {
17
+ text-align: center;
18
+ }
19
+
20
+ .emptyStateContainer {
21
+ margin: 2rem 0;
22
+ }
23
+
24
+ .content {
25
+ @include type.type-style('heading-compact-01');
26
+ color: colors.$gray-70;
27
+ margin-top: layout.$layout-05;
28
+ margin-bottom: layout.$spacing-03;
29
+ }
30
+
31
+ .desktopHeading,
32
+ .tabletHeading {
33
+ text-align: left;
34
+ text-transform: capitalize;
35
+
36
+ h4 {
37
+ @include type.type-style('heading-compact-02');
38
+ color: colors.$gray-70;
39
+
40
+ &:after {
41
+ content: '';
42
+ display: block;
43
+ width: 2rem;
44
+ padding-top: 3px;
45
+ border-bottom: 0.375rem solid;
46
+ @include brand-03(border-bottom-color);
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,197 @@
1
+ import {
2
+ Button,
3
+ DataTable,
4
+ DataTableSkeleton,
5
+ Layer,
6
+ Pagination,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ Tile,
15
+ } from '@carbon/react';
16
+ import { Add, TrashCan } from '@carbon/react/icons';
17
+ import {
18
+ ErrorState,
19
+ UserHasAccess,
20
+ isDesktop,
21
+ launchWorkspace,
22
+ showModal,
23
+ showSnackbar,
24
+ useLayoutType,
25
+ usePagination,
26
+ } from '@openmrs/esm-framework';
27
+ import { CardHeader, EmptyDataIllustration, usePaginationInfo } from '@openmrs/esm-patient-common-lib';
28
+ import React, { useState } from 'react';
29
+ import { useTranslation } from 'react-i18next';
30
+ import { useParams } from 'react-router-dom';
31
+ import { mutate } from 'swr';
32
+ import { usePharmacyUsers } from '../hooks';
33
+ import { revokePharamacyAssignment } from '../pharmacy.resources';
34
+ import styles from './pharmacy-tables.scss';
35
+
36
+ export const PharmacyUsers: React.FC = () => {
37
+ const { pharmacyUuid } = useParams();
38
+ const { t } = useTranslation();
39
+ const [currentPageSize, setCurrentPageSize] = useState<number>(10);
40
+ const { error, users, isLoading } = usePharmacyUsers(pharmacyUuid);
41
+ const headerTitle = t('pharmacyUsers', 'Pharmacy Users');
42
+
43
+ const [pageSize, setPageSize] = useState(10);
44
+
45
+ const { results, totalPages, currentPage, goTo } = usePagination(users, pageSize);
46
+ const { pageSizes } = usePaginationInfo(pageSize, totalPages, currentPage, results.length);
47
+ const layout = useLayoutType();
48
+
49
+ const headers = [
50
+ {
51
+ header: t('name', 'Name'),
52
+ key: 'name',
53
+ },
54
+ {
55
+ header: t('dateMapped', 'Date Mapped'),
56
+ key: 'dateMapped',
57
+ },
58
+ {
59
+ header: t('actions', 'Actions'),
60
+ key: 'actions',
61
+ },
62
+ ];
63
+
64
+ const tableRows =
65
+ results?.map((user) => {
66
+ return {
67
+ id: `${user.uuid}`,
68
+ name: user.name,
69
+ dateMapped: user.dateMapped,
70
+ actions: (
71
+ <UserHasAccess privilege={'coreapps.systemAdministration'} fallback="--">
72
+ <Button
73
+ kind="tertiary"
74
+ renderIcon={TrashCan}
75
+ onClick={() => {
76
+ const dispose = showModal('pharmacy-delete-confirm-dialog', {
77
+ onDelete: () => {
78
+ handleRevoke(user.uuid);
79
+ dispose();
80
+ },
81
+ onClose: () => dispose(),
82
+ });
83
+ }}>
84
+ Revoke
85
+ </Button>
86
+ </UserHasAccess>
87
+ ),
88
+ };
89
+ }) ?? [];
90
+
91
+ const handdleAssignToPharmacy = () => {
92
+ launchWorkspace('pharmacy-assignment-form', {
93
+ workspaceTitle: 'Pharmacy Assignment Form',
94
+ pharmacyUuid,
95
+ type: 'org.openmrs.User',
96
+ });
97
+ };
98
+
99
+ const handleRevoke = async (userUuid: string) => {
100
+ try {
101
+ const results = await revokePharamacyAssignment({
102
+ entityIdentifier: userUuid,
103
+ basisIdentifier: pharmacyUuid,
104
+ entityType: 'org.openmrs.User',
105
+ basisType: 'org.openmrs.Location',
106
+ });
107
+ showSnackbar({ kind: 'success', subtitle: results, title: 'Success' });
108
+
109
+ mutate((key) => {
110
+ return typeof key === 'string' && key.startsWith(`/ws/rest/v1/datafilter/search?type=org.openmrs.User`);
111
+ });
112
+ } catch (error) {
113
+ showSnackbar({ kind: 'error', subtitle: error.message, title: 'Failure' });
114
+ }
115
+ };
116
+
117
+ if (isLoading) {
118
+ return <DataTableSkeleton rowCount={5} />;
119
+ }
120
+ if (error) {
121
+ return <ErrorState headerTitle={headerTitle} error={error} />;
122
+ }
123
+
124
+ if (users.length === 0) {
125
+ return (
126
+ <Layer>
127
+ <Tile className={styles.tile}>
128
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
129
+ <h4>{headerTitle}</h4>
130
+ </div>
131
+ <EmptyDataIllustration />
132
+ <p className={styles.content}>{t('noPharmacyUsers', 'No Pharmacy users to list.')}</p>
133
+ <UserHasAccess privilege={'coreapps.systemAdministration'}>
134
+ <Button onClick={handdleAssignToPharmacy} renderIcon={Add} kind="ghost">
135
+ {t('assignUser', 'Assign User')}
136
+ </Button>
137
+ </UserHasAccess>
138
+ </Tile>
139
+ </Layer>
140
+ );
141
+ }
142
+ return (
143
+ <div className={styles.widgetContainer}>
144
+ <CardHeader title={headerTitle}>
145
+ <UserHasAccess privilege={`coreapps.systemAdministration`}>
146
+ <Button onClick={handdleAssignToPharmacy} renderIcon={Add} kind="ghost">
147
+ {t('assignUser', 'Assign User')}
148
+ </Button>
149
+ </UserHasAccess>
150
+ </CardHeader>
151
+ <DataTable
152
+ useZebraStyles
153
+ size="sm"
154
+ rows={tableRows ?? []}
155
+ headers={headers}
156
+ render={({ rows, headers, getHeaderProps, getTableProps, getTableContainerProps }) => (
157
+ <TableContainer {...getTableContainerProps()}>
158
+ <Table {...getTableProps()}>
159
+ <TableHead>
160
+ <TableRow>
161
+ {headers.map((header) => (
162
+ <TableHeader
163
+ {...getHeaderProps({
164
+ header,
165
+ isSortable: header.isSortable,
166
+ })}>
167
+ {header.header?.content ?? header.header}
168
+ </TableHeader>
169
+ ))}
170
+ </TableRow>
171
+ </TableHead>
172
+ <TableBody>
173
+ {rows.map((row) => (
174
+ <TableRow key={row.id}>
175
+ {row.cells.map((cell) => (
176
+ <TableCell key={cell.id}>{cell.value}</TableCell>
177
+ ))}
178
+ </TableRow>
179
+ ))}
180
+ </TableBody>
181
+ </Table>
182
+ </TableContainer>
183
+ )}
184
+ />
185
+ <Pagination
186
+ page={currentPage}
187
+ pageSize={pageSize}
188
+ pageSizes={pageSizes}
189
+ totalItems={users.length}
190
+ onChange={({ page, pageSize }) => {
191
+ goTo(page);
192
+ setPageSize(pageSize);
193
+ }}
194
+ />
195
+ </div>
196
+ );
197
+ };
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { TabPanels, TabPanel, TabList, Tabs, Tab } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { PharmacyPatients } from '../pharmacy-tables/pharmacy-patients.component';
5
+ import { PharmacyUsers } from '../pharmacy-tables/pharmacy-users.component';
6
+ import styles from './pharmacy-tabs.scss';
7
+
8
+ export const PharmacyTabs: React.FC = () => {
9
+ const { t } = useTranslation();
10
+ return (
11
+ <main>
12
+ <Tabs className={styles.tabs}>
13
+ <TabList className={styles.tablist} aria-label="List tabs" contained>
14
+ <Tab className={styles.tab}>{t('patients', 'Assigned Patients')}</Tab>
15
+ <Tab className={styles.tab}>{t('users', 'Asigned Users')}</Tab>
16
+ </TabList>
17
+ <TabPanels>
18
+ <TabPanel>
19
+ <PharmacyPatients />
20
+ </TabPanel>
21
+ <TabPanel>
22
+ <PharmacyUsers />
23
+ </TabPanel>
24
+ </TabPanels>
25
+ </Tabs>
26
+ </main>
27
+ );
28
+ };
@@ -0,0 +1,28 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/styles/scss/spacing';
3
+ @use '@carbon/styles/scss/type';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .tabs {
7
+ grid-column: span 2;
8
+ }
9
+
10
+ .tablist {
11
+ padding: 0 spacing.$spacing-05;
12
+ }
13
+
14
+ .tab {
15
+ min-width: 8.875rem;
16
+
17
+ &:active {
18
+ outline: 2px solid var(--brand-03) !important;
19
+ }
20
+
21
+ &:focus {
22
+ outline: 2px solid var(--brand-03) !important;
23
+ }
24
+
25
+ &[aria-selected='true'] {
26
+ box-shadow: inset 0 2px 0 0 var(--brand-03) !important;
27
+ }
28
+ }