Skip to content

Commit 8ede057

Browse files
committed
feat: add RegisterEpisode and connect with api
1 parent d646798 commit 8ede057

File tree

19 files changed

+903
-16
lines changed

19 files changed

+903
-16
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"@emotion/jest": "^11.2.1",
1111
"@emotion/react": "^11.4.1",
1212
"@emotion/styled": "^11.3.0",
13-
"@orfium/ictinus": "^3.9.1",
13+
"@orfium/ictinus": "^3.14.1",
1414
"@testing-library/jest-dom": "^5.11.9",
1515
"@testing-library/react": "^12.1.2",
1616
"@testing-library/user-event": "^13.1.3",
@@ -23,11 +23,13 @@
2323
"axios": "^0.21.1",
2424
"customize-cra": "^1.0.0",
2525
"final-form": "^4.20.2",
26+
"final-form-arrays": "^3.0.2",
2627
"history": "^4.10.1",
2728
"lodash": "^4.17.21",
2829
"react": "^17.0.2",
2930
"react-dom": "^17.0.2",
3031
"react-final-form": "^6.5.3",
32+
"react-final-form-arrays": "^3.1.3",
3133
"react-final-form-listeners": "^1.0.3",
3234
"react-query": "^3.16.0",
3335
"react-router-dom": "^5.2.0",
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2-
import { RegisterPatientPayload, PatientsPayload, PaginationParams } from '../../models/apiTypes';
2+
import {
3+
RegisterPatientPayload,
4+
PatientsPayload,
5+
PaginationParams,
6+
RegisterEpisodePayload,
7+
} from '../../models/apiTypes';
38
import { METHODS, request } from '../axiosInstances';
49

510
export default {
611
getHospitals: (params?: PaginationParams) => request(METHODS.GET, '/hospitals/', { params }),
7-
getHospital: (id: string) => request(METHODS.GET, `/hospitals/${id}`, {}),
12+
getHospital: (id: string) => request(METHODS.GET, `/hospitals/${id}/`, {}),
813
getPatients: (params?: PatientsPayload) => request(METHODS.GET, '/patients/', { params }),
9-
getPatient: (id: string) => request(METHODS.GET, `/patients/${id}`, {}),
14+
getSurgeons: (params?: PaginationParams) =>
15+
request(METHODS.GET, '/medical-personnel/', { params }),
16+
getPatient: (id: string) => request(METHODS.GET, `/patients/${id}/`, {}),
1017
registerPatient: (params: RegisterPatientPayload) =>
1118
request(METHODS.POST, '/patients/', { params }),
19+
registerEpisode: (params: RegisterEpisodePayload) =>
20+
request(METHODS.POST, '/episodes/', { params }),
1221
};

src/common.style.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ export const PageTitle = styled.div`
7676
padding: 16px;
7777
`;
7878

79+
export const PageSubtitle = styled.div`
80+
color: ${(props) => props.theme.utils.getColor('darkGray', 400)};
81+
display: flex;
82+
font-size: 18px;
83+
font-weight: 400;
84+
gap: 16px;
85+
padding: 16px;
86+
`;
87+
7988
export const SectionTitle = styled.div`
8089
color: ${(props) => props.theme.utils.getColor('blue', 500)};
8190
font-size: 18px;

src/hooks/api/patientHooks.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import {
1111
PatientAPI,
1212
PatientsPayload,
1313
PatientsResponse,
14+
RegisterEpisodePayload,
1415
RegisterPatientPayload,
16+
SurgeonsResponse,
1517
} from '../../models/apiTypes';
18+
import { RegisterEpisodeFormType } from '../../pages/RegisterEpisode/types';
1619
import { RegisterPatientFormType } from '../../pages/RegisterPatient/types';
1720
import urls from '../../routing/urls';
1821

@@ -77,6 +80,22 @@ export const useGetPatients = (params?: PatientsPayload) => {
7780
);
7881
};
7982

83+
export const useGetSurgeons = (params?: PaginationParams) => {
84+
return useQuery<SurgeonsResponse, AxiosError, SurgeonsResponse>(
85+
[ReactQueryKeys.SurgeonsQuery, params?.limit, params?.offset, params?.ordering],
86+
async () => {
87+
const { request } = patientsAPI.single.getSurgeons(params);
88+
return await request();
89+
},
90+
{
91+
onError: (errors) => {
92+
console.log(errors);
93+
},
94+
retry: false,
95+
}
96+
);
97+
};
98+
8099
export const useGetPatient = (id: string) => {
81100
return useQuery<PatientAPI, AxiosError, PatientAPI>(
82101
[ReactQueryKeys.PatientsQuery, id],
@@ -122,3 +141,44 @@ export const useRegisterPatient = () => {
122141
}
123142
);
124143
};
144+
145+
export const useRegisterEpisode = (
146+
hospitalID?: string,
147+
patientID?: string,
148+
episodeType = 'Inguinal Mesh Hernia Repair'
149+
) => {
150+
const history = useHistory();
151+
152+
return useMutation<RegisterEpisodePayload, AxiosError, RegisterEpisodeFormType>(
153+
(params) => {
154+
const payload = {
155+
hospital_id: params?.hospital?.value,
156+
patient_id: parseInt(patientID ?? '0'),
157+
anaesthetic_type: params?.anaestheticType?.label,
158+
diathermy_used: params?.diathermyUsed?.label === 'True',
159+
surgeon_ids: params?.surgeons?.map((surgeon) => surgeon?.value) ?? ['1'],
160+
comments: params?.comments,
161+
mesh_type: params?.meshType?.label,
162+
episode_type: episodeType,
163+
type: params.type?.label,
164+
cepod: params.cepod?.label,
165+
complexity: params?.complexity?.label,
166+
occurence: params?.occurence?.label,
167+
side: params?.side?.label,
168+
surgery_date: params?.surgeryDate,
169+
};
170+
171+
const { request } = patientsAPI.single.registerEpisode(payload);
172+
173+
return request();
174+
},
175+
{
176+
onSuccess: () => {
177+
history.replace(`${urls.patients()}/${hospitalID}/${patientID}`);
178+
},
179+
onError: (errors) => {
180+
console.log(errors);
181+
},
182+
}
183+
);
184+
};

src/hooks/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export const ReactQueryKeys = {
22
PatientsQuery: 'patientsQuery',
33
HospitalsQuery: 'hospitalsQuery',
4+
SurgeonsQuery: 'surgeonsQuery',
45
};

src/models/apiTypes.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,36 @@ export type HospitalsAPI = {
3636
patient_hospital_id?: number;
3737
};
3838

39-
// export type EpisodesAPI = {};
39+
export type EpisodesAPI = {
40+
episode_type: string;
41+
cepod: string;
42+
side: string;
43+
occurence: string;
44+
type: string;
45+
complexity: string;
46+
mesh_type: string;
47+
diathermy_used: boolean;
48+
comments?: string;
49+
anaesthetic_type: string;
50+
surgeons: SurgeonsAPI[];
51+
};
52+
53+
export type RegisterEpisodePayload = {
54+
hospital_id: number;
55+
patient_id: number;
56+
surgery_date: string;
57+
episode_type: string;
58+
cepod: string;
59+
side: string;
60+
occurence: string;
61+
type: string;
62+
complexity: string;
63+
mesh_type: string;
64+
diathermy_used: boolean;
65+
comments?: string;
66+
anaesthetic_type: string;
67+
surgeon_ids: number[];
68+
};
4069

4170
export interface HospitalsResponse extends PaginationResponse, PaginationParams {
4271
results: HospitalsAPI[];
@@ -73,9 +102,20 @@ export type PatientAPI = {
73102
phone_2: string;
74103
address: string;
75104
hospital_mappings: HospitalsAPI[];
76-
// episodes: EpisodesAPI[];
105+
episodes: EpisodesAPI[];
77106
};
78107

79108
export interface PatientsResponse extends PaginationResponse, PaginationParams {
80109
results: PatientAPI[];
81110
}
111+
112+
export type SurgeonsAPI = {
113+
id: number;
114+
user: {
115+
email: string;
116+
};
117+
level: string;
118+
};
119+
export interface SurgeonsResponse extends PaginationResponse, PaginationParams {
120+
results: SurgeonsAPI[];
121+
}

src/pages/PatientDetails/PatientDetails.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ const PatientDetails: React.FC = () => {
5757
)}
5858
</ComponentWrapper>
5959
<ButtonContainer>
60-
<Button color={'blue-500'} buttonType="button" disabled={isLoading} block size="md">
60+
<Button
61+
color={'blue-500'}
62+
buttonType="button"
63+
disabled={isLoading}
64+
block
65+
size="md"
66+
onClick={() => history.push(`${history.location.pathname}/add-episode`)}
67+
>
6168
Register new episode
6269
</Button>
6370
</ButtonContainer>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import styled from '@emotion/styled';
2+
3+
export const FormHeading = styled.span`
4+
font-size: 14px;
5+
font-weight: 700;
6+
margin-bottom: 12px;
7+
padding: 18px;
8+
`;
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/** @jsxImportSource @emotion/react */
2+
import React, { useState } from 'react';
3+
4+
import { Button, Icon } from '@orfium/ictinus';
5+
import { ButtonContainer, PageSubtitle, PageTitle, PageWrapper } from 'common.style';
6+
import ConfirmationModal from 'components/ConfirmationModal';
7+
import arrayMutators from 'final-form-arrays';
8+
import { Form } from 'react-final-form';
9+
import { useHistory } from 'react-router';
10+
import { useRouteMatch } from 'react-router-dom';
11+
import urls from 'routing/urls';
12+
13+
import {
14+
useGetHospital,
15+
useGetHospitals,
16+
useGetPatient,
17+
useGetSurgeons,
18+
useRegisterEpisode,
19+
} from '../../hooks/api/patientHooks';
20+
import RegisterEpisodeForm from './components/RegisterEpisodeForm';
21+
import { RegisterEpisodeFormType } from './types';
22+
import { formValidation } from './utils';
23+
24+
const RegisterEpisode: React.FC = () => {
25+
const match = useRouteMatch<{ hospitalID?: string; patientID?: string }>();
26+
const { hospitalID, patientID } = match.params;
27+
28+
const { data: hospitals, isLoading: isHospitalsLoading } = useGetHospitals({
29+
offset: 0,
30+
limit: 100,
31+
});
32+
const { data: patient, isLoading: isPatientLoading } = useGetPatient(patientID ?? '');
33+
const { data: hospital, isLoading: isHospitalLoading } = useGetHospital(hospitalID ?? '');
34+
const { data: surgeons, isLoading: isSurgeonsLoading } = useGetSurgeons({
35+
offset: 0,
36+
limit: 100,
37+
});
38+
39+
const hospitalPatientID = patient?.hospital_mappings.find(
40+
(value) => value.hospital_id === hospital?.id
41+
)?.patient_hospital_id;
42+
43+
const isLoading =
44+
isHospitalLoading || isHospitalsLoading || isSurgeonsLoading || isPatientLoading;
45+
46+
const { mutate, isLoading: isSubmitLoading } = useRegisterEpisode(hospitalID, patientID);
47+
48+
const handleSubmit = (form: RegisterEpisodeFormType) => {
49+
mutate(form);
50+
};
51+
52+
const [isFormDirty, setIsFormDirty] = useState(false);
53+
const [showWarningModal, setShowWarningModal] = useState(false);
54+
55+
const history = useHistory();
56+
57+
return (
58+
<>
59+
<PageWrapper>
60+
<PageTitle>
61+
<Icon
62+
name="fatArrowLeft"
63+
size={24}
64+
color={'lightGray-700'}
65+
onClick={() => {
66+
if (isFormDirty) {
67+
setShowWarningModal(true);
68+
} else {
69+
history.push(urls.patients());
70+
}
71+
}}
72+
/>
73+
Register an Episode
74+
</PageTitle>
75+
<PageSubtitle>
76+
Please verify that the hospital of the surgery is correct. If you wish, you can choose
77+
another hospital.
78+
</PageSubtitle>
79+
<Form
80+
initialValues={{
81+
hospital: { value: hospital?.id, label: hospital?.name },
82+
patientHospitalId: hospitalPatientID,
83+
surgeons: [{}, {}],
84+
}}
85+
validate={formValidation}
86+
mutators={{
87+
...arrayMutators,
88+
}}
89+
onSubmit={handleSubmit}
90+
>
91+
{({ handleSubmit, values, dirty, valid, submitting }) => {
92+
if (dirty) {
93+
setIsFormDirty(true);
94+
}
95+
96+
return (
97+
<form
98+
onSubmit={handleSubmit}
99+
css={{
100+
display: 'flex',
101+
flexDirection: 'column',
102+
height: 'calc(100vh)',
103+
overflow: 'hidden',
104+
}}
105+
>
106+
{patient && surgeons && hospitals && hospital && (
107+
<RegisterEpisodeForm
108+
values={values}
109+
surgeons={surgeons?.results ?? []}
110+
patient={patient}
111+
selectedHospital={hospital}
112+
hospitals={hospitals?.results ?? []}
113+
/>
114+
)}
115+
<ButtonContainer>
116+
<Button
117+
color={'blue-500'}
118+
buttonType="button"
119+
onClick={handleSubmit}
120+
disabled={isLoading || !valid || submitting || isSubmitLoading}
121+
block
122+
size="md"
123+
>
124+
Register an Episode
125+
</Button>
126+
</ButtonContainer>
127+
</form>
128+
);
129+
}}
130+
</Form>
131+
</PageWrapper>
132+
{showWarningModal && (
133+
<ConfirmationModal
134+
onClose={() => {
135+
setShowWarningModal(false);
136+
}}
137+
title={'Cancel new registration?'}
138+
subtitle={
139+
'Are you sure you want to cancel registering an episode? All information you’ve entered will be lost!'
140+
}
141+
buttonText={'Yes, cancel new addition'}
142+
onClick={() => history.push(`${urls.patients()}/${hospitalID}/${patientID}`)}
143+
/>
144+
)}
145+
</>
146+
);
147+
};
148+
149+
export default RegisterEpisode;

0 commit comments

Comments
 (0)