Skip to content

Commit

Permalink
Merge branch 'development' into feat/pwa-support
Browse files Browse the repository at this point in the history
  • Loading branch information
MiquelAdell authored Feb 4, 2025
2 parents daa65fe + 4c28a37 commit ac1ce92
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 60 deletions.
108 changes: 50 additions & 58 deletions src/webapp/components/survey/SurveyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ import styled from "styled-components";
import { getSurveyDisplayName } from "../../../domain/utils/PPSProgramsHelper";
import { SurveyFormOUSelector } from "./SurveyFormOUSelector";
import { SurveySection } from "./SurveySection";
import { SurveyStageSection } from "./SurveyStageSection";
import { useHistory } from "react-router-dom";
import useReadOnlyAccess from "./hook/useReadOnlyAccess";
import { GridSection } from "./GridSection";
import _c from "../../../domain/entities/generic/Collection";
import { TableSection } from "./TableSection";
import { useOfflineSnackbar } from "../../hooks/useOfflineSnackbar";


export interface SurveyFormProps {
hideForm: () => void;
currentSurveyId?: Id;
formType: SURVEY_FORM_TYPES;
}

const CancelButton = withStyles(() => ({
export const CancelButton = withStyles(() => ({
root: {
color: "white",
backgroundColor: "#bd1818",
Expand All @@ -42,6 +44,7 @@ export const SurveyForm: React.FC<SurveyFormProps> = props => {

const {
questionnaire,
surveyStages,
loading,
setLoading,
currentOrgUnit,
Expand Down Expand Up @@ -110,69 +113,58 @@ export const SurveyForm: React.FC<SurveyFormProps> = props => {
/>
</PaddedDiv>
)}
{questionnaire?.stages?.map(stage => {

{surveyStages.map(stage => {
if (!stage?.isVisible) return null;

return (
<PaddedDiv key={stage.id}>
<Typography>{i18n.t(`Stage - ${stage.title}`)}</Typography>

{stage.sections.map(section => {
if (!section.isVisible || section.isAntibioticSection) return null;

if (section.isSpeciesSection)
return (
<GridSection
speciesSection={section}
antibioticStage={stage}
updateQuestion={question =>
updateQuestion(question, stage.id)
}
viewOnly={hasReadOnlyAccess}
/>
);
if (section.isAntibioticTreatmentHospitalEpisodeSection)
return (
<TableSection
<PaddedDiv key={stage.title}>
{"repeatableStages" in stage ? (
<>
{stage.repeatableStages.map(repeatableStage => (
<PaddedDiv key={repeatableStage.id}>
<Typography>
{i18n.t(`Stage - ${stage.title}`)}
</Typography>

{repeatableStage.sections.map(section => (
<SurveyStageSection
key={repeatableStage.id}
section={section}
stage={repeatableStage}
viewOnly={hasReadOnlyAccess}
removeProgramStage={removeProgramStage}
updateQuestion={updateQuestion}
/>
))}
</PaddedDiv>
))}

<RightAlignedDiv>
<Button
variant="contained"
color="primary"
onClick={() => addProgramStage(stage.code)}
>
{i18n.t(`Add Another ${stage.title}`)}
</Button>
</RightAlignedDiv>
</>
) : (
<>
<Typography>{i18n.t(`Stage - ${stage.title}`)}</Typography>

{stage.sections.map(section => (
<SurveyStageSection
key={stage.id}
section={section}
updateQuestion={question =>
updateQuestion(question, stage.id)
}
stage={stage}
viewOnly={hasReadOnlyAccess}
removeProgramStage={removeProgramStage}
updateQuestion={updateQuestion}
/>
);

return (
<SurveySection
key={section.code}
title={section.title}
updateQuestion={question =>
updateQuestion(question, stage.id)
}
questions={section.questions}
viewOnly={hasReadOnlyAccess}
/>
);
})}

{stage.repeatable && (
<RightAlignedDiv>
<Button
variant="contained"
color="primary"
onClick={() => addProgramStage(stage.code)}
>
{i18n.t(`Add Another ${stage.title}`)}
</Button>
{stage.isAddedByUser && (
<CancelButton
variant="outlined"
onClick={() => removeProgramStage(stage.id)}
>
{i18n.t(`Remove ${stage.title}`)}
</CancelButton>
)}
</RightAlignedDiv>
))}
</>
)}
</PaddedDiv>
);
Expand Down
71 changes: 71 additions & 0 deletions src/webapp/components/survey/SurveyStageSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import i18n from "@eyeseetea/d2-ui-components/locales";
import { QuestionnaireStage } from "../../../domain/entities/Questionnaire/Questionnaire";
import { Question } from "../../../domain/entities/Questionnaire/QuestionnaireQuestion";
import { QuestionnaireSection } from "../../../domain/entities/Questionnaire/QuestionnaireSection";
import { Id } from "../../../domain/entities/Ref";
import { GridSection } from "./GridSection";
import { CancelButton } from "./SurveyForm";
import { SurveySection } from "./SurveySection";
import { TableSection } from "./TableSection";
import styled from "styled-components";

type SurveyStageSectionProps = {
section: QuestionnaireSection;
stage: QuestionnaireStage;
viewOnly: boolean;
removeProgramStage: (stageId: Id) => void;
updateQuestion: (question: Question, stageId?: Id) => void;
};

export const SurveyStageSection: React.FC<SurveyStageSectionProps> = props => {
const { section, stage, viewOnly, removeProgramStage, updateQuestion } = props;

switch (true) {
case !section.isVisible:
case section.isAntibioticSection:
return null;
case section.isSpeciesSection:
return (
<GridSection
speciesSection={section}
antibioticStage={stage}
updateQuestion={question => updateQuestion(question, stage.id)}
viewOnly={viewOnly}
/>
);
case section.isAntibioticTreatmentHospitalEpisodeSection:
return (
<TableSection
section={section}
updateQuestion={question => updateQuestion(question, stage.id)}
viewOnly={viewOnly}
/>
);
default:
return (
<>
<SurveySection
title={section.title}
updateQuestion={question => updateQuestion(question, stage.id)}
questions={section.questions}
viewOnly={viewOnly}
/>

{stage.repeatable && stage.isAddedByUser && (
<PaddedDiv>
<CancelButton
variant="outlined"
onClick={() => removeProgramStage(stage.id)}
>
{i18n.t(`Remove ${stage.title}`)}
</CancelButton>
</PaddedDiv>
)}
</>
);
}
};

const PaddedDiv = styled.div`
padding: 15px 0;
`;
57 changes: 55 additions & 2 deletions src/webapp/components/survey/hook/useSurveyForm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useAppContext } from "../../../contexts/app-context";
import { Questionnaire } from "../../../../domain/entities/Questionnaire/Questionnaire";
import {
Questionnaire,
QuestionnaireStage,
} from "../../../../domain/entities/Questionnaire/Questionnaire";
import { SURVEY_FORM_TYPES } from "../../../../domain/entities/Survey";
import { OrgUnitAccess } from "../../../../domain/entities/User";
import { useCurrentSurveys } from "../../../contexts/current-surveys-context";
Expand All @@ -9,6 +12,19 @@ import useReadOnlyAccess from "./useReadOnlyAccess";
import { useCurrentModule } from "../../../contexts/current-module-context";
import { Code, Question } from "../../../../domain/entities/Questionnaire/QuestionnaireQuestion";
import { Id } from "../../../../domain/entities/Ref";
import { Maybe } from "../../../../utils/ts-utils";
import _c from "../../../../domain/entities/generic/Collection";

type RepeatableStage = {
title: string;
sortOrder: number;
repeatable: boolean;
isVisible: boolean;
code: Code;
repeatableStages: QuestionnaireStage[];
};

type SurveyStage = QuestionnaireStage | RepeatableStage;

export function useSurveyForm(formType: SURVEY_FORM_TYPES, eventId: string | undefined) {
const { compositionRoot, currentUser, ppsHospitals, prevalenceHospitals } = useAppContext();
Expand Down Expand Up @@ -203,8 +219,13 @@ export function useSurveyForm(formType: SURVEY_FORM_TYPES, eventId: string | und
[compositionRoot.surveys, questionnaire]
);

const surveyStages = useMemo(() => {
return buildSurveyStages(questionnaire);
}, [questionnaire]);

return {
questionnaire,
surveyStages,
setQuestionnaire,
loading,
currentOrgUnit,
Expand All @@ -217,3 +238,35 @@ export function useSurveyForm(formType: SURVEY_FORM_TYPES, eventId: string | und
removeProgramStage,
};
}

const buildSurveyStages = (questionnaire: Maybe<Questionnaire>): SurveyStage[] => {
if (!questionnaire) return [];

const { stages } = questionnaire;
const nonRepeatableStages = stages.filter(stage => !stage.repeatable);
const repeatableStages = stages.filter(stage => stage.repeatable);

const groupedRepeatableStages = _c(repeatableStages)
.groupBy(stage => stage.title)
.mapValues(([title, questionnaireStages]) => {
const questionnaireStage = questionnaireStages[0];
if (!questionnaireStage) return undefined;

const { sortOrder, isVisible, code, repeatable } = questionnaireStage;

return {
code: code,
isVisible: isVisible,
repeatable: repeatable,
repeatableStages: questionnaireStages,
sortOrder: sortOrder,
title: title,
};
})
.values()
.filter((stage): stage is RepeatableStage => stage !== undefined);

return _c([...nonRepeatableStages, ...groupedRepeatableStages])
.sortBy(stage => stage.sortOrder)
.value();
};

0 comments on commit ac1ce92

Please sign in to comment.