-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMeasureFileUpload.tsx
More file actions
112 lines (102 loc) · 3.79 KB
/
Copy pathMeasureFileUpload.tsx
File metadata and controls
112 lines (102 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { Dropzone } from '@mantine/dropzone';
import { showNotification } from '@mantine/notifications';
import { Center, Text, createStyles } from '@mantine/core';
import { IconFileImport, IconFileCheck, IconAlertCircle, IconCircleCheck } from '@tabler/icons-react';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { measureBundleState } from '../../state/atoms/measureBundle';
import { measurementPeriodEndState, measurementPeriodStartState } from '../../state/atoms/measurementPeriod';
import {
MeasureUploadProps,
identifyMissingValueSets,
populateMeasurementPeriod,
rejectUpload
} from '../../util/measureUploadUtils';
const useStyles = createStyles({
text: {
wordBreak: 'break-all'
}
});
export default function MeasureFileUpload({ logError }: MeasureUploadProps) {
const setPeriodStart = useSetRecoilState(measurementPeriodStartState);
const setPeriodEnd = useSetRecoilState(measurementPeriodEndState);
const [measureBundle, setMeasureBundle] = useRecoilState(measureBundleState);
const { classes } = useStyles();
const extractMeasureBundle = (file: File) => {
const reader = new FileReader();
reader.onload = async () => {
const bundle = JSON.parse(reader.result as string) as fhir4.Bundle;
const measures = bundle.entry?.filter(r => r?.resource?.resourceType === 'Measure');
if (bundle.resourceType !== 'Bundle') {
rejectUpload("Uploaded file must be a JSON FHIR Resource of type 'Bundle'", file.name, logError);
return;
} else if (!measures || measures.length !== 1) {
rejectUpload("Uploaded bundle must contain exactly one resource of type 'Measure'", file.name, logError);
return;
}
const missingValueSets = await identifyMissingValueSets(bundle);
if (missingValueSets.length > 0) {
rejectUpload(missingValueSets, file.name, logError, false, true);
return;
}
setMeasureBundle(mb => ({
...mb,
fileName: file.name,
content: bundle,
isFile: true,
selectedMeasureId: null,
displayMap: {}
}));
// Safe to cast measures as error will be set if undefined above
const effectivePeriod = ((measures as fhir4.BundleEntry[])[0].resource as fhir4.Measure).effectivePeriod;
// Set measurement period to default period
const { start, end } = populateMeasurementPeriod(effectivePeriod?.start, effectivePeriod?.end);
setPeriodStart(start);
setPeriodEnd(end);
showNotification({
icon: <IconCircleCheck />,
title: 'Upload Success',
message: `Successfully uploaded ${file.name}`,
color: 'green'
});
};
reader.readAsText(file);
};
return (
<>
<Dropzone
onDrop={files => extractMeasureBundle(files[0])}
onReject={files =>
showNotification({
id: 'failed-upload',
icon: <IconAlertCircle />,
title: 'File upload failed',
message: `Could not upload file: ${files[0].file.name}. ${files[0].errors[0].message}`,
color: 'red'
})
}
accept={['application/json']}
multiple={false}
p={36}
>
<Center>
{measureBundle.fileName && measureBundle.isFile ? (
<IconFileCheck size={48} color="green" />
) : (
<IconFileImport size={48} />
)}
</Center>
<Text
align="center"
size="lg"
inline
className={classes.text}
style={{ color: measureBundle.fileName && measureBundle.isFile ? 'green' : 'black' }}
>
{measureBundle.fileName && measureBundle.isFile
? measureBundle.fileName
: 'Drag a Measure Bundle JSON file here or click to select file'}
</Text>
</Dropzone>
</>
);
}