-
Notifications
You must be signed in to change notification settings - Fork 2
/
ResourceForm.tsx
110 lines (99 loc) · 3.09 KB
/
ResourceForm.tsx
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
import { Center } from '@mantine/core';
import { Resource } from '@medplum/fhirtypes';
import { Loading, useMedplum } from '@medplum/react';
import { IconCircleCheck, IconCircleOff } from '@tabler/icons-react';
import { useEffect, useState } from 'react';
import { FormChildrenProps } from './types';
import { showNotification } from '@mantine/notifications';
import { normalizeErrorString } from '@medplum/core';
import { Form } from './Form';
interface ResourceFormProps<T extends Resource> {
children: (props: FormChildrenProps) => React.ReactNode;
fetchResource?: () => Promise<T | undefined>;
resourceToFormData?: (resource: T) => Record<string, any>;
formDataToResource?: (formData: Record<string, any>) => Record<string, any>;
onSuccess?: (resource: T) => void;
defaultData?: T | undefined;
}
export function ResourceForm<T extends Resource>(props: ResourceFormProps<T>): JSX.Element {
const {
children,
fetchResource = () => Promise.resolve(undefined),
resourceToFormData = (resource) => resource as Record<string, any>,
formDataToResource = (formData) => formData,
onSuccess,
defaultData,
} = props;
const medplum = useMedplum();
const [formData, setFormData] = useState<Record<string, any> | undefined>();
const [baseResource, setBaseResource] = useState<T | undefined>();
useEffect(() => {
async function callFetchResource() {
const resource = await fetchResource();
if (resource) {
setFormData(resourceToFormData(resource));
setBaseResource(resource);
} else if (defaultData) {
setFormData(resourceToFormData(defaultData));
setBaseResource(defaultData);
} else {
setFormData({});
}
}
callFetchResource();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
function handleSubmit(formData: Record<string, any>, error?: string): void {
if (error) {
showNotification({
color: 'red',
icon: <IconCircleOff />,
title: 'Error',
message: error,
});
return;
}
const resource = {
...baseResource,
...formDataToResource(formData),
};
let request, successMessage;
if (resource.id) {
request = medplum.updateResource(resource as T);
successMessage = 'Resource edited';
} else {
request = medplum.createResource(resource as T);
successMessage = 'Resource created';
}
request
.then((newResource: T) => {
setFormData(resourceToFormData(newResource));
showNotification({
icon: <IconCircleCheck />,
title: 'Success',
message: successMessage,
});
window.scroll(0, 0);
onSuccess?.(newResource as T);
})
.catch((err) => {
showNotification({
color: 'red',
icon: <IconCircleOff />,
title: 'Error',
message: normalizeErrorString(err),
});
});
}
if (!formData) {
return (
<Center h="100%">
<Loading />
</Center>
);
}
return (
<Form onSubmit={handleSubmit} defaultData={formData}>
{children}
</Form>
);
}