Skip to content

Commit e2e02d9

Browse files
authored
Merge pull request #6 from projkov/5-signup-wizard
Add SignUpWizard component
2 parents 91de668 + f7630c0 commit e2e02d9

5 files changed

Lines changed: 170 additions & 28 deletions

File tree

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Questionnaire, QuestionnaireResponse, Patient, Consent } from 'fhir/r4b';
2+
import { compact } from 'lodash';
3+
4+
import { getFHIRResources } from '@beda.software/emr/services';
5+
import { extractBundleResources, useService } from '@beda.software/fhir-react';
6+
import { mapSuccess, resolveMap } from '@beda.software/remote-data';
7+
8+
export function useSignUpWizard(patient: Patient) {
9+
const [response] = useService(async () => {
10+
const questionnaireIDs = ['patient-informed-consent', 'authorization-for-release-of-medical-images', 'breast-cancer-study-survey'];
11+
12+
return mapSuccess(
13+
await resolveMap({
14+
consentBundle: getFHIRResources<Consent>('Consent', {
15+
category: 'npp',
16+
patient: `Patient/${patient.id}`,
17+
}),
18+
questionnaireBundle: getFHIRResources<Questionnaire>('Questionnaire', {
19+
_id: questionnaireIDs.join(','),
20+
_elements: 'id,title',
21+
}),
22+
questionnaireResponseBundle: getFHIRResources<QuestionnaireResponse>('QuestionnaireResponse', {
23+
subject: patient?.id,
24+
questionnaire: questionnaireIDs.join(','),
25+
}),
26+
}),
27+
({ consentBundle, questionnaireBundle, questionnaireResponseBundle }) => {
28+
const consent = extractBundleResources<Consent>(consentBundle).Consent[0];
29+
const questionnaireResponses =
30+
extractBundleResources(questionnaireResponseBundle).QuestionnaireResponse;
31+
const questionnaires = extractBundleResources(questionnaireBundle).Questionnaire;
32+
33+
const finishedQuestionnaireIds = compact(questionnaireResponses.map((qr) => qr.questionnaire));
34+
const questionnairesInOrder = compact(
35+
questionnaireIDs.map((qId) => questionnaires.find((q) => q.id === qId)),
36+
);
37+
const notFinishedQuestionnaires = questionnairesInOrder.filter(
38+
(q) => !finishedQuestionnaireIds.includes(q.id),
39+
);
40+
const showWizard = notFinishedQuestionnaires.length > 0 || !consent;
41+
42+
return {
43+
questionnaires: questionnairesInOrder,
44+
notFinishedQuestionnaires,
45+
questionnaireResponses,
46+
consent,
47+
showWizard
48+
};
49+
},
50+
);
51+
});
52+
53+
return { response };
54+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { useState } from 'react';
2+
3+
import { QuestionnairesWizard, QuestionnairesWizardHeader } from '@beda.software/emr/components';
4+
5+
import { S } from './styles';
6+
import { SignUpWizardProps } from './types';
7+
8+
const WizardContainer = ({ children }: { children: React.ReactNode }) => (
9+
<S.OuterContainer>
10+
<S.InnerContainer>
11+
{children}
12+
</S.InnerContainer>
13+
</S.OuterContainer>
14+
);
15+
16+
export function SignUpWizard(props: SignUpWizardProps) {
17+
const { patient, onSuccess, questionnaires, notFinishedQuestionnaires,
18+
questionnaireResponses, show } = props;
19+
const [headerProps, setHeaderProps] = useState({ title: "", index: 0, total: 0 });
20+
21+
if (!show) {
22+
return null;
23+
}
24+
25+
return (
26+
<WizardContainer>
27+
<QuestionnairesWizardHeader {...headerProps} />
28+
<S.FormContainer>
29+
<QuestionnairesWizard
30+
questionnaires={questionnaires}
31+
questionnaireResponses={questionnaireResponses}
32+
initialQuestionnaireResponse={{
33+
subject: { reference: `${patient?.resourceType}/${patient?.id}` },
34+
}}
35+
initialQuestionnaireId={
36+
notFinishedQuestionnaires[0]?.id
37+
}
38+
onQuestionnaireChange={(q, index) =>
39+
setHeaderProps({ title: q.title ?? "", index: index, total: questionnaires.length })}
40+
launchContextParameters={[{ name: 'Patient', resource: patient }]}
41+
onSuccess={onSuccess}
42+
/>
43+
</S.FormContainer>
44+
</WizardContainer>
45+
);
46+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import styled from 'styled-components';
2+
3+
const OuterContainer = styled.div`
4+
display: flex;
5+
justify-content: center;
6+
align-items: center;
7+
`;
8+
9+
const InnerContainer = styled.div`
10+
width: 800px;
11+
padding-top: 40px;
12+
padding-bottom: 40px;
13+
gap: 100px;
14+
flex-direction: 'column';
15+
display: 'flex';
16+
`;
17+
18+
const FormContainer = styled.div`
19+
margin-top: 40px;
20+
`;
21+
22+
export const S = {
23+
OuterContainer: OuterContainer,
24+
InnerContainer: InnerContainer,
25+
FormContainer: FormContainer
26+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Patient, Questionnaire, QuestionnaireResponse } from 'fhir/r4b';
2+
3+
export interface SignUpWizardProps {
4+
patient: Patient;
5+
questionnaires: Questionnaire[];
6+
notFinishedQuestionnaires: Questionnaire[];
7+
questionnaireResponses: QuestionnaireResponse[];
8+
show: boolean;
9+
onSuccess: () => void;
10+
}

src/containers/App/index.tsx

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ import { sharedAuthorizedPatient, sharedAuthorizedUser } from '@beda.software/em
3939
import { matchCurrentUserRole, Role } from '@beda.software/emr/utils';
4040

4141
import { BaseLayout } from 'src/components/BaseLayout';
42+
import { SignUpWizard } from 'src/components/SignUpWizard';
43+
import { useSignUpWizard } from 'src/components/SignUpWizard/hooks';
4244

43-
import { usePatientConsent } from './hooks';
4445
import { DocumentPrint } from '../DocumentPrint';
4546
import { EnableTwoFactor } from '../EnableTwoFactor';
4647
import { ForgotPassword } from '../ForgotPassword';
@@ -237,7 +238,7 @@ function AuthenticatedPatientUserApp({ reload }: { reload: () => void }) {
237238

238239
const [patient] = sharedAuthorizedPatient.useSharedState();
239240
const [user] = sharedAuthorizedUser.useSharedState();
240-
const { response } = usePatientConsent(patient!);
241+
const { response } = useSignUpWizard(patient!);
241242

242243
const doLogout = useCallback(async (path: string) => {
243244
await logout();
@@ -263,33 +264,38 @@ function AuthenticatedPatientUserApp({ reload }: { reload: () => void }) {
263264

264265
return (
265266
<RenderRemoteData remoteData={response} renderLoading={Spinner}>
266-
{({ consent }) => (
267-
<Routes>
268-
<Route path={`/print-patient-document/:id/:qrId`} element={<DocumentPrint />} />
269-
<Route
270-
path="*"
271-
element={
272-
<BaseLayout>
273-
<Routes>
274-
<Route path={`/patients/:id/*`} element={<PatientDetails />} />
275-
{consent ? (
267+
{({ showWizard, questionnaires, notFinishedQuestionnaires, questionnaireResponses }) => {
268+
269+
if (showWizard) {
270+
return (
271+
<SignUpWizard
272+
patient={patient!}
273+
questionnaires={questionnaires}
274+
notFinishedQuestionnaires={notFinishedQuestionnaires}
275+
questionnaireResponses={questionnaireResponses}
276+
show={showWizard}
277+
onSuccess={reload}
278+
/>
279+
);
280+
};
281+
282+
return (
283+
<Routes>
284+
<Route path={`/print-patient-document/:id/:qrId`} element={<DocumentPrint />} />
285+
<Route
286+
path="*"
287+
element={
288+
<BaseLayout>
289+
<Routes>
290+
<Route path={`/patients/:id/*`} element={<PatientDetails />} />
276291
<Route path="*" element={<Navigate to={`/patients/${patient!.id}`} />} />
277-
) : (
278-
<Route
279-
path="*"
280-
element={
281-
<Navigate
282-
to={`/patients/${patient!.id}/documents/new/patient-informed-consent`}
283-
/>
284-
}
285-
/>
286-
)}
287-
</Routes>
288-
</BaseLayout>
289-
}
290-
/>
291-
</Routes>
292-
)}
292+
</Routes>
293+
</BaseLayout>
294+
}
295+
/>
296+
</Routes>
297+
);
298+
}}
293299
</RenderRemoteData>
294300
);
295301
}

0 commit comments

Comments
 (0)