@kenyaemr/esm-active-visits-app 7.0.2-pre.65

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 (79) hide show
  1. package/.turbo/turbo-build.log +32 -0
  2. package/dist/130.js +2 -0
  3. package/dist/130.js.LICENSE.txt +3 -0
  4. package/dist/130.js.map +1 -0
  5. package/dist/255.js +2 -0
  6. package/dist/255.js.LICENSE.txt +9 -0
  7. package/dist/255.js.map +1 -0
  8. package/dist/271.js +1 -0
  9. package/dist/316.js +2 -0
  10. package/dist/316.js.LICENSE.txt +19 -0
  11. package/dist/316.js.map +1 -0
  12. package/dist/319.js +1 -0
  13. package/dist/382.js +1 -0
  14. package/dist/382.js.map +1 -0
  15. package/dist/443.js +1 -0
  16. package/dist/443.js.map +1 -0
  17. package/dist/460.js +1 -0
  18. package/dist/574.js +1 -0
  19. package/dist/635.js +1 -0
  20. package/dist/635.js.map +1 -0
  21. package/dist/644.js +1 -0
  22. package/dist/729.js +1 -0
  23. package/dist/729.js.map +1 -0
  24. package/dist/757.js +1 -0
  25. package/dist/784.js +2 -0
  26. package/dist/784.js.LICENSE.txt +9 -0
  27. package/dist/784.js.map +1 -0
  28. package/dist/788.js +1 -0
  29. package/dist/807.js +1 -0
  30. package/dist/833.js +1 -0
  31. package/dist/835.js +1 -0
  32. package/dist/835.js.map +1 -0
  33. package/dist/875.js +2 -0
  34. package/dist/875.js.LICENSE.txt +15 -0
  35. package/dist/875.js.map +1 -0
  36. package/dist/879.js +1 -0
  37. package/dist/879.js.map +1 -0
  38. package/dist/kenyaemr-esm-active-visits-app.js +1 -0
  39. package/dist/kenyaemr-esm-active-visits-app.js.buildmanifest.json +580 -0
  40. package/dist/kenyaemr-esm-active-visits-app.js.map +1 -0
  41. package/dist/main.js +2 -0
  42. package/dist/main.js.LICENSE.txt +25 -0
  43. package/dist/main.js.map +1 -0
  44. package/dist/routes.json +1 -0
  45. package/jest.config.js +3 -0
  46. package/package.json +55 -0
  47. package/src/active-visits-widget/active-visits.component.tsx +311 -0
  48. package/src/active-visits-widget/active-visits.resource.tsx +148 -0
  49. package/src/active-visits-widget/active-visits.scss +191 -0
  50. package/src/active-visits-widget/active-visits.test.tsx +119 -0
  51. package/src/active-visits-widget/empty-data-illustration.component.tsx +39 -0
  52. package/src/config-schema.ts +57 -0
  53. package/src/declarations.d.ts +4 -0
  54. package/src/index.ts +21 -0
  55. package/src/root.scss +30 -0
  56. package/src/routes.json +20 -0
  57. package/src/types/index.ts +28 -0
  58. package/src/visits-summary/visit-detail-overview.scss +328 -0
  59. package/src/visits-summary/visit-detail.component.tsx +77 -0
  60. package/src/visits-summary/visit-detail.test.tsx +122 -0
  61. package/src/visits-summary/visit.resource.ts +190 -0
  62. package/src/visits-summary/visits-components/encounter-list.component.tsx +127 -0
  63. package/src/visits-summary/visits-components/encounter-observations.component.tsx +43 -0
  64. package/src/visits-summary/visits-components/encounter-observations.test.tsx +36 -0
  65. package/src/visits-summary/visits-components/medications-summary.component.tsx +105 -0
  66. package/src/visits-summary/visits-components/notes-summary.component.tsx +51 -0
  67. package/src/visits-summary/visits-components/tests-summary.component.tsx +21 -0
  68. package/src/visits-summary/visits-components/visit-summary.component.tsx +118 -0
  69. package/translations/am.json +35 -0
  70. package/translations/ar.json +35 -0
  71. package/translations/en.json +35 -0
  72. package/translations/es.json +35 -0
  73. package/translations/fr.json +35 -0
  74. package/translations/he.json +35 -0
  75. package/translations/km.json +35 -0
  76. package/translations/zh.json +35 -0
  77. package/translations/zh_CN.json +35 -0
  78. package/tsconfig.json +5 -0
  79. package/webpack.config.js +1 -0
@@ -0,0 +1 @@
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0"},"extensions":[{"name":"active-visits-widget","slot":"homepage-widgets-slot","component":"activeVisits","order":0},{"name":"visit-summary-widget","slot":"visit-summary-slot","component":"visitDetail"}],"pages":[],"version":"7.0.2-pre.65"}
package/jest.config.js ADDED
@@ -0,0 +1,3 @@
1
+ const rootConfig = require('../../jest.config.js');
2
+
3
+ module.exports = rootConfig;
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@kenyaemr/esm-active-visits-app",
3
+ "version": "7.0.2-pre.65",
4
+ "description": "Active visits widget microfrontend for the OpenMRS SPA",
5
+ "browser": "dist/kenyaemr-esm-active-visits-app.js",
6
+ "main": "src/index.ts",
7
+ "source": true,
8
+ "license": "MPL-2.0",
9
+ "homepage": "https://github.com/openmrs/openmrs-esm-patient-management#readme",
10
+ "scripts": {
11
+ "start": "openmrs develop",
12
+ "serve": "webpack serve --mode=development",
13
+ "debug": "npm run serve",
14
+ "build": "webpack --mode production",
15
+ "analyze": "webpack --mode=production --env.analyze=true",
16
+ "lint": "cross-env eslint src --ext ts,tsx",
17
+ "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests --color",
18
+ "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
19
+ "coverage": "yarn test --coverage",
20
+ "typescript": "tsc",
21
+ "extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
22
+ },
23
+ "browserslist": [
24
+ "extends browserslist-config-openmrs"
25
+ ],
26
+ "keywords": [
27
+ "openmrs"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/openmrs/openmrs-esm-patient-management.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/openmrs/openmrs-esm-patient-management/issues"
38
+ },
39
+ "dependencies": {
40
+ "@carbon/react": "~1.37.0",
41
+ "lodash-es": "^4.17.15"
42
+ },
43
+ "peerDependencies": {
44
+ "@openmrs/esm-framework": "5.x",
45
+ "dayjs": "1.x",
46
+ "react": "^18.1.0",
47
+ "react-dom": "^18.1.0",
48
+ "react-i18next": "11.x",
49
+ "swr": "2.x"
50
+ },
51
+ "devDependencies": {
52
+ "webpack": "^5.74.0"
53
+ },
54
+ "stableVersion": "7.0.1"
55
+ }
@@ -0,0 +1,311 @@
1
+ import React, { useMemo, useState, useCallback } from 'react';
2
+ import {
3
+ DataTable,
4
+ DataTableSkeleton,
5
+ InlineLoading,
6
+ Layer,
7
+ Pagination,
8
+ Search,
9
+ Table,
10
+ TableBody,
11
+ TableCell,
12
+ TableContainer,
13
+ TableExpandedRow,
14
+ TableExpandHeader,
15
+ TableExpandRow,
16
+ TableHead,
17
+ TableHeader,
18
+ TableRow,
19
+ Tile,
20
+ } from '@carbon/react';
21
+ import { useTranslation } from 'react-i18next';
22
+ import {
23
+ useLayoutType,
24
+ isDesktop,
25
+ useConfig,
26
+ usePagination,
27
+ ExtensionSlot,
28
+ ErrorState,
29
+ ConfigurableLink,
30
+ } from '@openmrs/esm-framework';
31
+ import { EmptyDataIllustration } from './empty-data-illustration.component';
32
+ import { useActiveVisits } from './active-visits.resource';
33
+ import styles from './active-visits.scss';
34
+
35
+ function generateTableHeaders(t, config) {
36
+ let headersIndex = 0;
37
+
38
+ const headers = [
39
+ {
40
+ id: headersIndex++,
41
+ header: t('visitStartTime', 'Visit Time'),
42
+ key: 'visitStartTime',
43
+ },
44
+ ];
45
+
46
+ config?.activeVisits?.identifiers?.map((identifier) => {
47
+ headers.push({
48
+ id: headersIndex++,
49
+ header: t(identifier?.header?.key, identifier?.header?.default),
50
+ key: identifier?.header?.key,
51
+ });
52
+ });
53
+
54
+ if (!config?.activeVisit?.identifiers) {
55
+ headers.push({
56
+ id: headersIndex++,
57
+ header: t('idNumber', 'ID Number'),
58
+ key: 'idNumber',
59
+ });
60
+ }
61
+
62
+ config?.activeVisits?.attributes?.map((attribute) => {
63
+ headers.push({
64
+ id: headersIndex++,
65
+ header: t(attribute?.header?.key, attribute?.header?.default),
66
+ key: attribute?.header?.key,
67
+ });
68
+ });
69
+
70
+ headers.push(
71
+ {
72
+ id: headersIndex++,
73
+ header: t('name', 'Name'),
74
+ key: 'name',
75
+ },
76
+ {
77
+ id: headersIndex++,
78
+ header: t('gender', 'Gender'),
79
+ key: 'gender',
80
+ },
81
+ {
82
+ id: headersIndex++,
83
+ header: t('age', 'Age'),
84
+ key: 'age',
85
+ },
86
+ {
87
+ id: headersIndex++,
88
+ header: t('visitType', 'Visit Type'),
89
+ key: 'visitType',
90
+ },
91
+ );
92
+
93
+ return headers;
94
+ }
95
+
96
+ const ActiveVisitsTable = () => {
97
+ const { t } = useTranslation();
98
+ const config = useConfig();
99
+ const layout = useLayoutType();
100
+ const pageSizes = config?.activeVisits?.pageSizes ?? [10, 20, 30, 40, 50];
101
+ const [pageSize, setPageSize] = useState(config?.activeVisits?.pageSize ?? 10);
102
+ const { activeVisits, isLoading, isValidating, error } = useActiveVisits();
103
+ const [searchString, setSearchString] = useState('');
104
+ const headerData = useMemo(() => generateTableHeaders(t, config), [config, t]);
105
+
106
+ const searchResults = useMemo(() => {
107
+ if (activeVisits !== undefined && activeVisits.length > 0) {
108
+ if (searchString && searchString.trim() !== '') {
109
+ const search = searchString.toLowerCase();
110
+ return activeVisits?.filter((activeVisitRow) =>
111
+ Object.entries(activeVisitRow).some(([header, value]) => {
112
+ if (header === 'patientUuid') {
113
+ return false;
114
+ }
115
+ return `${value}`.toLowerCase().includes(search);
116
+ }),
117
+ );
118
+ }
119
+ }
120
+
121
+ return activeVisits;
122
+ }, [searchString, activeVisits]);
123
+
124
+ const { paginated, goTo, results, currentPage } = usePagination(searchResults, pageSize);
125
+
126
+ const handleSearch = useCallback(
127
+ (e) => {
128
+ goTo(1);
129
+ setSearchString(e.target.value);
130
+ },
131
+ [goTo, setSearchString],
132
+ );
133
+
134
+ if (isLoading) {
135
+ return (
136
+ <div className={styles.activeVisitsContainer}>
137
+ <div className={styles.activeVisitsDetailHeaderContainer}>
138
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
139
+ <h4>{t('activeVisits', 'Active Visits')}</h4>
140
+ </div>
141
+ <div className={styles.backgroundDataFetchingIndicator}>
142
+ <span>{isValidating ? <InlineLoading /> : null}</span>
143
+ </div>
144
+ </div>
145
+ <Search
146
+ labelText=""
147
+ placeholder={t('filterTable', 'Filter table')}
148
+ onChange={handleSearch}
149
+ size={isDesktop(layout) ? 'sm' : 'lg'}
150
+ disabled
151
+ />
152
+ <DataTableSkeleton
153
+ rowCount={pageSize}
154
+ showHeader={false}
155
+ showToolbar={false}
156
+ zebra
157
+ columnCount={headerData?.length}
158
+ size={isDesktop(layout) ? 'sm' : 'lg'}
159
+ />
160
+ </div>
161
+ );
162
+ }
163
+
164
+ if (error) {
165
+ return (
166
+ <div className={styles.activeVisitsContainer}>
167
+ <Layer>
168
+ <ErrorState error={error} headerTitle={t('activeVisits', 'Active Visits')} />
169
+ </Layer>
170
+ </div>
171
+ );
172
+ }
173
+
174
+ if (!activeVisits.length) {
175
+ return (
176
+ <div className={styles.activeVisitsContainer}>
177
+ <Layer>
178
+ <Tile className={styles.tile}>
179
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
180
+ <h4>{t('activeVisits', 'Active Visits')}</h4>
181
+ </div>
182
+ <EmptyDataIllustration />
183
+ <p className={styles.content}>
184
+ {t('noActiveVisitsForLocation', 'There are no active visits to display for this location.')}
185
+ </p>
186
+ </Tile>
187
+ </Layer>
188
+ </div>
189
+ );
190
+ } else {
191
+ return (
192
+ <div className={styles.activeVisitsContainer}>
193
+ <div className={styles.activeVisitsDetailHeaderContainer}>
194
+ <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
195
+ <h4>{t('activeVisits', 'Active Visits')}</h4>
196
+ </div>
197
+ <div className={styles.backgroundDataFetchingIndicator}>
198
+ <span>{isValidating ? <InlineLoading /> : null}</span>
199
+ </div>
200
+ </div>
201
+ <Search
202
+ labelText=""
203
+ placeholder={t('filterTable', 'Filter table')}
204
+ onChange={handleSearch}
205
+ size={isDesktop(layout) ? 'sm' : 'lg'}
206
+ />
207
+ <DataTable
208
+ rows={results}
209
+ headers={headerData}
210
+ size={isDesktop(layout) ? 'sm' : 'lg'}
211
+ useZebraStyles={activeVisits?.length > 1 ? true : false}>
212
+ {({ rows, headers, getHeaderProps, getTableProps, getRowProps, getExpandHeaderProps }) => (
213
+ <TableContainer className={styles.tableContainer}>
214
+ <Table className={styles.activeVisitsTable} {...getTableProps()}>
215
+ <TableHead>
216
+ <TableRow>
217
+ <TableExpandHeader enableToggle {...getExpandHeaderProps()} />
218
+ {headers.map((header) => (
219
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
220
+ ))}
221
+ </TableRow>
222
+ </TableHead>
223
+ <TableBody>
224
+ {rows.map((row, index) => {
225
+ const currentVisit = activeVisits.find((visit) => visit.id === row.id);
226
+
227
+ if (!currentVisit) {
228
+ return null;
229
+ }
230
+
231
+ const patientChartUrl = '${openmrsSpaBase}/patient/${patientUuid}/chart/Patient%20Summary';
232
+
233
+ return (
234
+ <React.Fragment key={`active-visit-row-${index}`}>
235
+ <TableExpandRow
236
+ {...getRowProps({ row })}
237
+ data-testid={`activeVisitRow${currentVisit.patientUuid || 'unknown'}`}>
238
+ {row.cells.map((cell) => (
239
+ <TableCell key={`active-visit-row-${index}-cell-${cell.id}`} data-testid={cell.id}>
240
+ {cell.info.header === 'name' && currentVisit.patientUuid ? (
241
+ <ConfigurableLink
242
+ to={patientChartUrl}
243
+ templateParams={{ patientUuid: currentVisit.patientUuid }}>
244
+ {cell.value}
245
+ </ConfigurableLink>
246
+ ) : (
247
+ cell.value
248
+ )}
249
+ </TableCell>
250
+ ))}
251
+ </TableExpandRow>
252
+ {row.isExpanded ? (
253
+ <TableRow className={styles.expandedActiveVisitRow}>
254
+ <th colSpan={headers.length + 2}>
255
+ <ExtensionSlot
256
+ className={styles.visitSummaryContainer}
257
+ name="visit-summary-slot"
258
+ state={{
259
+ patientUuid: currentVisit.patientUuid,
260
+ visitUuid: currentVisit.visitUuid,
261
+ }}
262
+ />
263
+ </th>
264
+ </TableRow>
265
+ ) : (
266
+ <TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
267
+ )}
268
+ </React.Fragment>
269
+ );
270
+ })}
271
+ </TableBody>
272
+ </Table>
273
+ </TableContainer>
274
+ )}
275
+ </DataTable>
276
+ {searchResults?.length === 0 && (
277
+ <div className={styles.filterEmptyState}>
278
+ <Layer level={0}>
279
+ <Tile className={styles.filterEmptyStateTile}>
280
+ <p className={styles.filterEmptyStateContent}>{t('noVisitsToDisplay', 'No visits to display')}</p>
281
+ <p className={styles.filterEmptyStateHelper}>{t('checkFilters', 'Check the filters above')}</p>
282
+ </Tile>
283
+ </Layer>
284
+ </div>
285
+ )}
286
+ {paginated && (
287
+ <Pagination
288
+ forwardText="Next page"
289
+ backwardText="Previous page"
290
+ page={currentPage}
291
+ pageSize={pageSize}
292
+ pageSizes={pageSizes}
293
+ totalItems={searchResults?.length}
294
+ className={styles.pagination}
295
+ size={isDesktop(layout) ? 'sm' : 'lg'}
296
+ onChange={({ pageSize: newPageSize, page: newPage }) => {
297
+ if (newPageSize !== pageSize) {
298
+ setPageSize(newPageSize);
299
+ }
300
+ if (newPage !== currentPage) {
301
+ goTo(newPage);
302
+ }
303
+ }}
304
+ />
305
+ )}
306
+ </div>
307
+ );
308
+ }
309
+ };
310
+
311
+ export default ActiveVisitsTable;
@@ -0,0 +1,148 @@
1
+ import { useEffect } from 'react';
2
+ import useSWRInfinite from 'swr/infinite';
3
+ import dayjs from 'dayjs';
4
+ import isToday from 'dayjs/plugin/isToday';
5
+ import last from 'lodash-es/last';
6
+ import {
7
+ openmrsFetch,
8
+ type Visit,
9
+ useSession,
10
+ type FetchResponse,
11
+ formatDatetime,
12
+ parseDate,
13
+ useConfig,
14
+ restBaseUrl,
15
+ } from '@openmrs/esm-framework';
16
+ dayjs.extend(isToday);
17
+
18
+ export interface ActiveVisit {
19
+ age: string;
20
+ id: string;
21
+ idNumber: string;
22
+ gender: string;
23
+ location: string;
24
+ name: string;
25
+ patientUuid: string;
26
+ visitStartTime: string;
27
+ visitType: string;
28
+ visitUuid: string;
29
+ [identifier: string]: string;
30
+ }
31
+
32
+ interface VisitResponse {
33
+ results: Array<Visit>;
34
+ links: Array<{ rel: 'prev' | 'next' }>;
35
+ totalCount: number;
36
+ }
37
+
38
+ export function useActiveVisits() {
39
+ const session = useSession();
40
+ const config = useConfig();
41
+ const sessionLocation = session?.sessionLocation?.uuid;
42
+
43
+ const customRepresentation =
44
+ 'custom:(uuid,patient:(uuid,identifiers:(identifier,uuid,identifierType:(name,uuid)),person:(age,display,gender,uuid,attributes:(value,attributeType:(uuid,display)))),' +
45
+ 'visitType:(uuid,name,display),location:(uuid,name,display),startDatetime,stopDatetime)';
46
+
47
+ const getUrl = (pageIndex, previousPageData: FetchResponse<VisitResponse>) => {
48
+ if (pageIndex && !previousPageData?.data?.links?.some((link) => link.rel === 'next')) {
49
+ return null;
50
+ }
51
+
52
+ let url = `${restBaseUrl}/visit?v=${customRepresentation}&`;
53
+ let urlSearchParams = new URLSearchParams();
54
+
55
+ urlSearchParams.append('includeInactive', 'false');
56
+ urlSearchParams.append('totalCount', 'true');
57
+ urlSearchParams.append('location', `${sessionLocation}`);
58
+
59
+ if (pageIndex) {
60
+ urlSearchParams.append('startIndex', `${pageIndex * 50}`);
61
+ }
62
+
63
+ return url + urlSearchParams.toString();
64
+ };
65
+
66
+ const {
67
+ data,
68
+ error,
69
+ isLoading,
70
+ isValidating,
71
+ size: pageNumber,
72
+ setSize,
73
+ } = useSWRInfinite<FetchResponse<VisitResponse>, Error>(sessionLocation ? getUrl : null, openmrsFetch);
74
+
75
+ useEffect(() => {
76
+ if (data && data?.[pageNumber - 1]?.data?.links?.some((link) => link.rel === 'next')) {
77
+ setSize((currentSize) => currentSize + 1);
78
+ }
79
+ }, [data, pageNumber]);
80
+
81
+ const mapVisitProperties = (visit: Visit): ActiveVisit => {
82
+ // create base object
83
+ const activeVisits: ActiveVisit = {
84
+ age: visit?.patient?.person?.age,
85
+ id: visit.uuid,
86
+ idNumber: null,
87
+ gender: visit?.patient?.person?.gender,
88
+ location: visit?.location?.uuid,
89
+ name: visit?.patient?.person?.display,
90
+ patientUuid: visit?.patient?.uuid,
91
+ visitStartTime: formatDatetime(parseDate(visit?.startDatetime)),
92
+ visitType: visit?.visitType?.display,
93
+ visitUuid: visit.uuid,
94
+ };
95
+
96
+ // in case no configuration is given the previous behavior remains the same
97
+ if (!config?.activeVisits?.identifiers) {
98
+ activeVisits.idNumber = visit?.patient?.identifiers[0]?.identifier ?? '--';
99
+ } else {
100
+ // map identifiers on config
101
+ config?.activeVisits?.identifiers?.map((configIdentifier) => {
102
+ // check if in the current visit the patient has in his identifiers the current identifierType name
103
+ const visitIdentifier = visit?.patient?.identifiers.find(
104
+ (visitIdentifier) => visitIdentifier?.identifierType?.name === configIdentifier?.identifierName,
105
+ );
106
+
107
+ // add the new identifier or rewrite existing one to activeVisit object
108
+ // the parameter will corresponds to the name of the key value of the configuration
109
+ // and the respective value is the visit identifier
110
+ // If there isn't a identifier we display this default text '--'
111
+ activeVisits[configIdentifier.header?.key] = visitIdentifier?.identifier ?? '--';
112
+ });
113
+ }
114
+
115
+ // map attributes on config
116
+ config?.activeVisits?.attributes?.map(({ display, header }) => {
117
+ // check if in the current visit the person has in his attributes the current display
118
+ const personAttributes = visit?.patient?.person?.attributes.find(
119
+ (personAttributes) => personAttributes?.attributeType?.display === display,
120
+ );
121
+
122
+ // add the new attribute or rewrite existing one to activeVisit object
123
+ // the parameter will correspond to the name of the key value of the configuration
124
+ // and the respective value is the persons value
125
+ // If there isn't a attribute we display this default text '--'
126
+ activeVisits[header?.key] = personAttributes?.value ?? '--';
127
+ });
128
+
129
+ return activeVisits;
130
+ };
131
+
132
+ const formattedActiveVisits: Array<ActiveVisit> = data
133
+ ? [].concat(...data?.map((res) => res?.data?.results?.map(mapVisitProperties)))
134
+ : [];
135
+
136
+ return {
137
+ activeVisits: formattedActiveVisits,
138
+ error,
139
+ isLoading,
140
+ isValidating,
141
+ totalResults: data?.[0]?.data?.totalCount ?? 0,
142
+ };
143
+ }
144
+
145
+ export const getOriginFromPathName = (pathname = '') => {
146
+ const from = pathname.split('/');
147
+ return last(from);
148
+ };