|
| 1 | +import React from 'react'; |
| 2 | +import { Space, Button, Divider, Dropdown, Popconfirm, MenuProps } from 'antd'; |
| 3 | +import { parseGroup } from '../../BaseComponents/GroupDetail'; |
| 4 | +import { MoreOutlined } from '@ant-design/icons'; |
| 5 | +import { ADD_EDIT_COMMODITY_URL, groupResourceType, listResourceType } from '../../../constants'; |
| 6 | +import { Link } from 'react-router-dom'; |
| 7 | +import { useTranslation } from '../../../mls'; |
| 8 | +import { |
| 9 | + BaseListView, |
| 10 | + BaseListViewProps, |
| 11 | + TableData, |
| 12 | +} from '../../BaseComponents/BaseGroupsListView'; |
| 13 | +import { TFunction } from '@opensrp/i18n'; |
| 14 | +import { |
| 15 | + FHIRServiceClass, |
| 16 | + SingleKeyNestedValue, |
| 17 | + useSearchParams, |
| 18 | + viewDetailsQuery, |
| 19 | +} from '@opensrp/react-utils'; |
| 20 | +import { IGroup } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IGroup'; |
| 21 | +import { IList } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IList'; |
| 22 | +import { get } from 'lodash'; |
| 23 | +import { |
| 24 | + getUnitMeasureCharacteristic, |
| 25 | + supplyMgSnomedCode, |
| 26 | + snomedCodeSystem, |
| 27 | +} from '../../../helpers/utils'; |
| 28 | +import { useQueryClient } from 'react-query'; |
| 29 | +import { |
| 30 | + sendErrorNotification, |
| 31 | + sendInfoNotification, |
| 32 | + sendSuccessNotification, |
| 33 | +} from '@opensrp/notifications'; |
| 34 | +import { RbacCheck, useUserRole } from '@opensrp/rbac'; |
| 35 | + |
| 36 | +export interface GroupListProps { |
| 37 | + fhirBaseURL: string; |
| 38 | + listId: string; // commodities are added to list resource with this id |
| 39 | +} |
| 40 | + |
| 41 | +const keyValueDetailRender = (obj: IGroup, t: TFunction) => { |
| 42 | + const { name, active, id, identifier } = parseGroup(obj); |
| 43 | + |
| 44 | + const unitMeasureCharacteristic = getUnitMeasureCharacteristic(obj); |
| 45 | + |
| 46 | + const keyValues = { |
| 47 | + [t('Commodity Id')]: id, |
| 48 | + [t('Identifier')]: identifier, |
| 49 | + [t('Name')]: name, |
| 50 | + [t('Active')]: active ? t('Active') : t('Disabled'), |
| 51 | + [t('Unit of measure')]: get(unitMeasureCharacteristic, 'valueCodeableConcept.text'), |
| 52 | + }; |
| 53 | + |
| 54 | + return ( |
| 55 | + <Space direction="vertical"> |
| 56 | + {Object.entries(keyValues).map(([key, value]) => { |
| 57 | + const props = { |
| 58 | + [key]: value, |
| 59 | + }; |
| 60 | + return value ? ( |
| 61 | + <div key={key} data-testid="key-value"> |
| 62 | + <SingleKeyNestedValue {...props} /> |
| 63 | + </div> |
| 64 | + ) : null; |
| 65 | + })} |
| 66 | + </Space> |
| 67 | + ); |
| 68 | +}; |
| 69 | + |
| 70 | +/** |
| 71 | + * Shows the list of all group and there details |
| 72 | + * |
| 73 | + * @param props - GroupList component props |
| 74 | + * @returns returns healthcare display |
| 75 | + */ |
| 76 | +export const DefaultCommodityList = (props: GroupListProps) => { |
| 77 | + const { fhirBaseURL, listId } = props; |
| 78 | + |
| 79 | + const { t } = useTranslation(); |
| 80 | + const queryClient = useQueryClient(); |
| 81 | + const { addParam } = useSearchParams(); |
| 82 | + const userRole = useUserRole(); |
| 83 | + |
| 84 | + const getItems = (record: TableData): MenuProps['items'] => { |
| 85 | + return [ |
| 86 | + { |
| 87 | + key: '1', |
| 88 | + permissions: [], |
| 89 | + label: ( |
| 90 | + <Button |
| 91 | + data-testid="view-details" |
| 92 | + onClick={() => addParam(viewDetailsQuery, record.id)} |
| 93 | + type="link" |
| 94 | + > |
| 95 | + {t('View Details')} |
| 96 | + </Button> |
| 97 | + ), |
| 98 | + }, |
| 99 | + { |
| 100 | + key: '2', |
| 101 | + permissions: ['Group.delete'], |
| 102 | + label: ( |
| 103 | + <Popconfirm |
| 104 | + title={t('Are you sure you want to delete this Commodity?')} |
| 105 | + okText={t('Yes')} |
| 106 | + cancelText={t('No')} |
| 107 | + onConfirm={async () => { |
| 108 | + deleteCommodity(fhirBaseURL, record.obj, listId) |
| 109 | + .then(() => { |
| 110 | + queryClient.invalidateQueries([groupResourceType]).catch(() => { |
| 111 | + sendInfoNotification( |
| 112 | + t('Unable to refresh data at the moment, please refresh the page') |
| 113 | + ); |
| 114 | + }); |
| 115 | + sendSuccessNotification(t('Successfully deleted commodity')); |
| 116 | + }) |
| 117 | + .catch(() => { |
| 118 | + sendErrorNotification(t('Deletion of commodity failed')); |
| 119 | + }); |
| 120 | + }} |
| 121 | + > |
| 122 | + <Button danger type="link" style={{ color: '#' }}> |
| 123 | + {t('Delete')} |
| 124 | + </Button> |
| 125 | + </Popconfirm> |
| 126 | + ), |
| 127 | + }, |
| 128 | + ] |
| 129 | + .filter((item) => userRole.hasPermissions(item.permissions)) |
| 130 | + .map((item) => { |
| 131 | + const { permissions, ...rest } = item; |
| 132 | + return rest; |
| 133 | + }); |
| 134 | + }; |
| 135 | + |
| 136 | + const getColumns = (t: TFunction) => [ |
| 137 | + { |
| 138 | + title: t('Name'), |
| 139 | + dataIndex: 'name' as const, |
| 140 | + key: 'name' as const, |
| 141 | + }, |
| 142 | + { |
| 143 | + title: t('Active'), |
| 144 | + dataIndex: 'active' as const, |
| 145 | + key: 'active' as const, |
| 146 | + render: (value: boolean) => <div>{value ? t('Active') : t('Disabled')}</div>, |
| 147 | + }, |
| 148 | + { |
| 149 | + title: t('type'), |
| 150 | + dataIndex: 'type' as const, |
| 151 | + key: 'type' as const, |
| 152 | + }, |
| 153 | + { |
| 154 | + title: t('Actions'), |
| 155 | + width: '10%', |
| 156 | + // eslint-disable-next-line react/display-name |
| 157 | + render: (_: unknown, record: TableData) => ( |
| 158 | + <span className="d-flex align-items-center"> |
| 159 | + <RbacCheck permissions={['Group.update']}> |
| 160 | + <> |
| 161 | + <Link to={`${ADD_EDIT_COMMODITY_URL}/${record.id}`} className="m-0 p-1"> |
| 162 | + {t('Edit')} |
| 163 | + </Link> |
| 164 | + <Divider type="vertical" /> |
| 165 | + </> |
| 166 | + </RbacCheck> |
| 167 | + <Divider type="vertical" /> |
| 168 | + <Dropdown |
| 169 | + menu={{ items: getItems(record) }} |
| 170 | + placement="bottomRight" |
| 171 | + arrow |
| 172 | + trigger={['click']} |
| 173 | + > |
| 174 | + <MoreOutlined data-testid="action-dropdown" className="more-options" /> |
| 175 | + </Dropdown> |
| 176 | + </span> |
| 177 | + ), |
| 178 | + }, |
| 179 | + ]; |
| 180 | + |
| 181 | + const baseListViewProps: BaseListViewProps = { |
| 182 | + getColumns: getColumns, |
| 183 | + keyValueMapperRenderProp: keyValueDetailRender, |
| 184 | + createButtonLabel: t('Add Commodity'), |
| 185 | + createButtonUrl: ADD_EDIT_COMMODITY_URL, |
| 186 | + fhirBaseURL, |
| 187 | + pageTitle: t('Commodity List'), |
| 188 | + extraQueryFilters: { |
| 189 | + code: `${snomedCodeSystem}|${supplyMgSnomedCode}`, |
| 190 | + '_has:List:item:_id': listId, |
| 191 | + }, |
| 192 | + }; |
| 193 | + |
| 194 | + return <BaseListView {...baseListViewProps} />; |
| 195 | +}; |
| 196 | + |
| 197 | +/** |
| 198 | + * Soft deletes a commodity resource. Sets its active to false and removes it from the |
| 199 | + * list resource. |
| 200 | + * |
| 201 | + * @param fhirBaseURL - base url to fhir server |
| 202 | + * @param obj - commodity resource to be disabled |
| 203 | + * @param listId - id of list resource where this was referenced. |
| 204 | + */ |
| 205 | +export const deleteCommodity = async (fhirBaseURL: string, obj: IGroup, listId: string) => { |
| 206 | + if (!listId) { |
| 207 | + throw new Error('List id is not configured correctly'); |
| 208 | + } |
| 209 | + const disabledGroup: IGroup = { |
| 210 | + ...obj, |
| 211 | + active: false, |
| 212 | + }; |
| 213 | + const serve = new FHIRServiceClass<IGroup>(fhirBaseURL, groupResourceType); |
| 214 | + const listServer = new FHIRServiceClass<IList>(fhirBaseURL, listResourceType); |
| 215 | + const list = await listServer.read(listId); |
| 216 | + const leftEntries = (list.entry ?? []).filter((entry) => { |
| 217 | + return entry.item.reference !== `${groupResourceType}/${obj.id}`; |
| 218 | + }); |
| 219 | + const listPayload = { |
| 220 | + ...list, |
| 221 | + entry: leftEntries, |
| 222 | + }; |
| 223 | + return listServer.update(listPayload).then(() => { |
| 224 | + return serve.update(disabledGroup); |
| 225 | + }); |
| 226 | +}; |
0 commit comments