Skip to content

Commit 2f590a0

Browse files
authored
Eusm commodity create Update (#1330)
* Update group-management dependencies * Extract general re-usable productForm * Define a way to dynamically provide vlaidationRules * Make it possible to configure hiddenfilds and validationRUles * Make the whole Group details section configurable * Move current commodity list implementation to DEfault * Add Eusm centric commodity list * Configurable view details section for group list view * Conditionally render list view wrt to project code * Update utils * Install jest-canvas-mock, mocks canvas for antd upload * Create a mock for window.URL.createObjectURL * Create Eusm edit * Fix lint issues * Update snapshot tests * Show error banner if list id is not configured * Replace fallback image with skeleton image * Link material number to the identifier dataindex * Add material number to view details section * Fix test regressions * Wrap commodity edit in rbaccheck * Refactor lexicalities on variable unitOfMeasure * Cleaning up the code * Wrap commodity edit in rbaccheck * Update mock envs to fix test regression * Update snapshot in commodity list view * Fix missing material number * Wait for binary Query to render form view * Fix binary payload generation and append to list * Disable caching on binary query * Update docstring for helper fun toArrayBuffer * Fix bug where attractive item did not have correct value
1 parent 2e7ee0f commit 2f590a0

File tree

33 files changed

+3131
-2987
lines changed

33 files changed

+3131
-2987
lines changed

jest.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = {
1616
transformIgnorePatterns: [
1717
'node_modules/(?!(@helsenorge/toolkit|@helsenorge/core-utils|@helsenorge/designsystem-react)/)',
1818
],
19-
setupFiles: ['./setupTests'],
19+
setupFiles: ['./setupTests', 'jest-canvas-mock'],
2020
setupFilesAfterEnv: ['<rootDir>/jest-setup.ts'],
2121
roots: ['packages/', 'app'],
2222
moduleNameMapper: {

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"husky": "^8.0.0",
9797
"i18next-parser": "^5.4.0",
9898
"jest": "27.5.1",
99+
"jest-canvas-mock": "^2.5.2",
99100
"jest-environment-jsdom-sixteen": "^2.0.0",
100101
"jest-fetch-mock": "^3.0.3",
101102
"jest-haste-map": "^27.4.6",

packages/fhir-group-management/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"author": "OpenSRP Engineering",
3232
"license": "Apache-2.0",
3333
"dependencies": {
34+
"@ant-design/icons": "^4.7.0",
3435
"@opensrp/notifications": "^0.0.5",
3536
"@opensrp/pkg-config": "^0.0.9",
3637
"@opensrp/rbac": "workspace:^",
@@ -46,6 +47,7 @@
4647
},
4748
"peerDependencies": {
4849
"@opensrp/i18n": "^0.0.1",
49-
"react": "17.0.0"
50+
"react": "17.0.0",
51+
"react-query": "^3.15.1"
5052
}
5153
}

packages/fhir-group-management/src/components/BaseComponents/BaseGroupsListView/index.tsx

+17-6
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,23 @@ import { useTranslation } from '../../../mls';
1919
import { TFunction } from '@opensrp/i18n';
2020
import { RbacCheck } from '@opensrp/rbac';
2121

22-
export type TableData = ReturnType<typeof parseGroup> & Record<string, unknown>;
22+
export type DefaultTableData = ReturnType<typeof parseGroup> & Record<string, unknown>;
2323

24-
export type BaseListViewProps = Partial<Pick<ViewDetailsProps, 'keyValueMapperRenderProp'>> & {
24+
export type ExtendableTableData = Pick<
25+
ReturnType<typeof parseGroup>,
26+
'id' | 'name' | 'active' | 'identifier' | 'lastUpdated'
27+
>;
28+
29+
export type BaseListViewProps<TableData extends ExtendableTableData = DefaultTableData> = Partial<
30+
Pick<ViewDetailsProps, 'keyValueMapperRenderProp'>
31+
> & {
2532
fhirBaseURL: string;
2633
getColumns: (t: TFunction) => Column<TableData>[];
2734
extraQueryFilters?: Record<string, string>;
2835
createButtonLabel: string;
2936
createButtonUrl?: string;
3037
pageTitle: string;
38+
generateTableData?: (groups: IGroup) => TableData;
3139
viewDetailsRender?: (fhirBaseURL: string, resourceId?: string) => ReactNode;
3240
};
3341

@@ -37,7 +45,9 @@ export type BaseListViewProps = Partial<Pick<ViewDetailsProps, 'keyValueMapperRe
3745
* @param props - GroupList component props
3846
* @returns returns healthcare display
3947
*/
40-
export const BaseListView = (props: BaseListViewProps) => {
48+
export function BaseListView<TableData extends ExtendableTableData = DefaultTableData>(
49+
props: BaseListViewProps<TableData>
50+
) {
4151
const {
4252
fhirBaseURL,
4353
extraQueryFilters,
@@ -46,6 +56,7 @@ export const BaseListView = (props: BaseListViewProps) => {
4656
createButtonUrl,
4757
keyValueMapperRenderProp,
4858
pageTitle,
59+
generateTableData = parseGroup,
4960
viewDetailsRender,
5061
} = props;
5162

@@ -73,9 +84,9 @@ export const BaseListView = (props: BaseListViewProps) => {
7384

7485
const tableData = (data?.records ?? []).map((org: IGroup, index: number) => {
7586
return {
76-
...parseGroup(org),
87+
...generateTableData(org),
7788
key: `${index}`,
78-
};
89+
} as TableData;
7990
});
8091

8192
const columns = getColumns(t);
@@ -118,4 +129,4 @@ export const BaseListView = (props: BaseListViewProps) => {
118129
</Row>
119130
</div>
120131
);
121-
};
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React from 'react';
2+
import { Helmet } from 'react-helmet';
3+
import { CommodityForm } from '../../ProductForm';
4+
import { useParams } from 'react-router';
5+
import {
6+
accountabilityPeriod,
7+
appropriateUsage,
8+
availability,
9+
condition,
10+
groupResourceType,
11+
isAttractiveItem,
12+
LIST_COMMODITY_URL,
13+
materialNumber,
14+
productImage,
15+
} from '../../../constants';
16+
import { Spin } from 'antd';
17+
import { PageHeader } from '@opensrp/react-utils';
18+
import { useQuery } from 'react-query';
19+
import { FHIRServiceClass, BrokenPage } from '@opensrp/react-utils';
20+
import { IGroup } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IGroup';
21+
import {
22+
generateGroupPayload,
23+
getGroupFormFields,
24+
postPutGroup,
25+
updateListReferencesFactory,
26+
validationRulesFactory,
27+
} from './utils';
28+
import { useTranslation } from '../../../mls';
29+
30+
export interface GroupAddEditProps {
31+
fhirBaseURL: string;
32+
listId: string;
33+
}
34+
35+
export interface RouteParams {
36+
id?: string;
37+
}
38+
39+
export const CommodityAddEdit = (props: GroupAddEditProps) => {
40+
const { fhirBaseURL: fhirBaseUrl, listId } = props;
41+
42+
const { id: resourceId } = useParams<RouteParams>();
43+
const { t } = useTranslation();
44+
45+
const groupQuery = useQuery(
46+
[groupResourceType, resourceId],
47+
async () =>
48+
new FHIRServiceClass<IGroup>(fhirBaseUrl, groupResourceType).read(resourceId as string),
49+
{
50+
enabled: !!resourceId,
51+
}
52+
);
53+
54+
if (!groupQuery.isIdle && groupQuery.isLoading) {
55+
return <Spin size="large" className="custom-spinner"></Spin>;
56+
}
57+
58+
if (groupQuery.error && !groupQuery.data) {
59+
return <BrokenPage errorMessage={(groupQuery.error as Error).message} />;
60+
}
61+
62+
const initialValues = getGroupFormFields(groupQuery.data);
63+
64+
const pageTitle = groupQuery.data
65+
? t('Edit Commodity | {{name}}', { name: groupQuery.data.name ?? '' })
66+
: t('Create Commodity');
67+
68+
const postSuccess = updateListReferencesFactory(fhirBaseUrl, listId);
69+
70+
return (
71+
<section className="content-section">
72+
<Helmet>
73+
<title>{pageTitle}</title>
74+
</Helmet>
75+
<PageHeader title={pageTitle} />
76+
<div className="bg-white p-5">
77+
<CommodityForm
78+
hidden={[
79+
materialNumber,
80+
isAttractiveItem,
81+
availability,
82+
condition,
83+
appropriateUsage,
84+
accountabilityPeriod,
85+
productImage,
86+
]}
87+
fhirBaseUrl={fhirBaseUrl}
88+
initialValues={initialValues}
89+
cancelUrl={LIST_COMMODITY_URL}
90+
successUrl={LIST_COMMODITY_URL}
91+
postSuccess={postSuccess}
92+
validationRulesFactory={validationRulesFactory}
93+
mutationEffect={async (initialValues, values) => {
94+
const payload = generateGroupPayload(values, initialValues);
95+
return postPutGroup(fhirBaseUrl, payload);
96+
}}
97+
/>
98+
</div>
99+
</section>
100+
);
101+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`renders correctly: active radio button 1`] = `
4+
<input
5+
checked=""
6+
class="ant-radio-input"
7+
type="radio"
8+
value="true"
9+
/>
10+
`;
11+
12+
exports[`renders correctly: disabled radio button 1`] = `
13+
<input
14+
class="ant-radio-input"
15+
type="radio"
16+
value="false"
17+
/>
18+
`;

packages/fhir-group-management/src/components/CommodityAddEdit/tests/fixtures.ts packages/fhir-group-management/src/components/CommodityAddEdit/Default/tests/fixtures.ts

+40
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ export const newList = {
116116
entry: [],
117117
};
118118

119+
export const editedList = {
120+
resourceType: 'List',
121+
id: 'list-resource-id',
122+
identifier: [{ use: 'official', value: 'list-resource-id' }],
123+
status: 'current',
124+
mode: 'working',
125+
title: 'Supply Chain commodities',
126+
code: {
127+
coding: [{ system: 'http://ona.io', code: 'supply-chain', display: 'Supply Chain Commodity' }],
128+
text: 'Supply Chain Commodity',
129+
},
130+
entry: [{ item: { reference: 'Group/123' } }],
131+
};
132+
119133
export const createdCommodity1 = {
120134
code: {
121135
coding: [{ system: 'http://snomed.info/sct', code: '386452003', display: 'Supply management' }],
@@ -140,3 +154,29 @@ export const createdCommodity1 = {
140154
},
141155
],
142156
};
157+
158+
export const editedCommodity1 = {
159+
resourceType: 'Group',
160+
id: '567ec5f2-db90-4fac-b578-6e07df3f48de',
161+
identifier: [{ value: '43245245336', use: 'official' }],
162+
active: true,
163+
type: 'device',
164+
actual: false,
165+
code: {
166+
coding: [{ system: 'http://snomed.info/sct', code: '386452003', display: 'Supply management' }],
167+
},
168+
name: 'Paracetamol 100mg TabletsDettol',
169+
characteristic: [
170+
{
171+
code: {
172+
coding: [
173+
{ system: 'http://snomed.info/sct', code: '767524001', display: 'Unit of measure' },
174+
],
175+
},
176+
valueCodeableConcept: {
177+
coding: [{ system: 'http://snomed.info/sct', code: '767525000', display: 'Unit' }],
178+
text: 'Bottles',
179+
},
180+
},
181+
],
182+
};

0 commit comments

Comments
 (0)