From 2d6d7943ea81519ede189c8953ac5b01c6354b10 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Tue, 21 May 2024 22:43:18 +0530 Subject: [PATCH 1/7] fix: fix order of fields for event programs --- .../repositories/SurveyFormD2Repository.ts | 18 ++++++++++++++---- src/data/utils/questionHelper.ts | 1 + .../survey-questions/QuestionWidget.tsx | 14 +------------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/data/repositories/SurveyFormD2Repository.ts b/src/data/repositories/SurveyFormD2Repository.ts index 294a1809..7b887b97 100644 --- a/src/data/repositories/SurveyFormD2Repository.ts +++ b/src/data/repositories/SurveyFormD2Repository.ts @@ -27,7 +27,7 @@ import { AMR_SURVEYS_PREVALENCE_DEA_CUSTOM_AST_GUIDE, AMR_SURVEYS_PREVALENCE_DEA_AST_GUIDELINES, } from "../entities/D2Survey"; -import { ProgramMetadata } from "../entities/D2Program"; +import { ProgramDataElement, ProgramMetadata } from "../entities/D2Program"; import { mapProgramToQuestionnaire, mapQuestionnaireToEvent, @@ -57,6 +57,16 @@ export class SurveyD2Repository implements SurveyRepository { const programDataElements = resp.programStageDataElements.map( psde => psde.dataElement ); + const dataElementsWithSortOrder: ProgramDataElement[] = resp.dataElements.map( + de => { + return { + ...de, + sortOrder: resp.programStageDataElements.find( + psde => psde.dataElement.id === de.id + )?.sortOrder, + }; + } + ); const sortedTrackedentityAttr = resp.programTrackedEntityAttributes ? _( @@ -90,7 +100,7 @@ export class SurveyD2Repository implements SurveyRepository { undefined, trackedEntity, programDataElements, - resp.dataElements, + dataElementsWithSortOrder, sortedOptions, resp.programStages, resp.programStageSections, @@ -116,7 +126,7 @@ export class SurveyD2Repository implements SurveyRepository { event, undefined, programDataElements, - resp.dataElements, + dataElementsWithSortOrder, resp.options, resp.programStages, resp.programStageSections, @@ -140,7 +150,7 @@ export class SurveyD2Repository implements SurveyRepository { undefined, undefined, programDataElements, - resp.dataElements, + dataElementsWithSortOrder, resp.options, resp.programStages, resp.programStageSections, diff --git a/src/data/utils/questionHelper.ts b/src/data/utils/questionHelper.ts index 778e663c..e9ab8ba3 100644 --- a/src/data/utils/questionHelper.ts +++ b/src/data/utils/questionHelper.ts @@ -281,6 +281,7 @@ export const mapProgramDataElementToQuestions = ( }) ) .compact() + .sortBy(q => q.sortOrder) .value(); return questions; diff --git a/src/webapp/components/survey-questions/QuestionWidget.tsx b/src/webapp/components/survey-questions/QuestionWidget.tsx index 30357bb4..bce10e38 100644 --- a/src/webapp/components/survey-questions/QuestionWidget.tsx +++ b/src/webapp/components/survey-questions/QuestionWidget.tsx @@ -6,7 +6,6 @@ import TextWidget from "./widgets/TextWidget"; import YesNoWidget from "./widgets/YesNoWidget"; import DatePickerWidget from "./widgets/DatePickerWidget"; import { Maybe, assertUnreachable } from "../../../utils/ts-utils"; -import DropdownSelectWidget from "./widgets/DropdownSelectWidget"; import DateTimePickerWidget from "./widgets/DateTimePickerWidget"; import SearchableSelect from "./widgets/SearchableSelect"; import { @@ -28,18 +27,7 @@ export const QuestionWidget: React.FC = React.memo(props => switch (type) { case "select": { - if (question.options.length > 5 && question.options.length < 10) { - return ( - ) => - onChange(update(question, value)) - } - disabled={disabled} - /> - ); - } else if (question.options.length > 10) { + if (question.options.length > 5) { return ( op.id === question.value?.id) || null} From 1e7ee779bb36a64fb65c9a4021c10955d68080f1 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 22 May 2024 12:42:56 +0530 Subject: [PATCH 2/7] fix: remove repeatable ward stage fix --- src/CompositionRoot.ts | 4 +++ .../SurveyFormTestRepository.ts | 3 ++ src/data/utils/surveyFormMappers.ts | 4 +-- src/domain/repositories/SurveyRepository.ts | 1 + .../RemoveRepeatableProgramStageUseCase.ts | 28 +++++++++++++++++++ src/domain/usecases/SaveFormDataUseCase.ts | 2 +- .../components/survey/hook/useSurveyForm.ts | 16 +++++++---- 7 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/domain/usecases/RemoveRepeatableProgramStageUseCase.ts diff --git a/src/CompositionRoot.ts b/src/CompositionRoot.ts index d5ea4d3b..ae82f984 100644 --- a/src/CompositionRoot.ts +++ b/src/CompositionRoot.ts @@ -37,6 +37,7 @@ import { ASTGuidelinesRepository } from "./domain/repositories/ASTGuidelinesRepo import { GetASTGuidelinesUseCase } from "./domain/usecases/GetASTGuidelinesUseCase"; import { ASTGuidelinesD2Repository } from "./data/repositories/ASTGuidelinesD2Repository"; import { ASTGuidelinesTestRepository } from "./data/repositories/testRepositories/ASTGuidelinesTestRepository"; +import { RemoveRepeatableProgramStageUseCase } from "./domain/usecases/RemoveRepeatableProgramStageUseCase"; export type CompositionRoot = ReturnType; @@ -87,6 +88,9 @@ function getCompositionRoot(repositories: Repositories) { ), getChildCount: new GetChildCountUseCase(repositories.surveyFormRepository), applyInitialRules: new ApplyInitialRulesToSurveyUseCase(), + removeRepeatableStage: new RemoveRepeatableProgramStageUseCase( + repositories.surveyFormRepository + ), }, astGuidelines: { getGuidelines: new GetASTGuidelinesUseCase(repositories.astGuidelinesRepository), diff --git a/src/data/repositories/testRepositories/SurveyFormTestRepository.ts b/src/data/repositories/testRepositories/SurveyFormTestRepository.ts index af44be4f..e35a3712 100644 --- a/src/data/repositories/testRepositories/SurveyFormTestRepository.ts +++ b/src/data/repositories/testRepositories/SurveyFormTestRepository.ts @@ -11,6 +11,9 @@ import { ASTGUIDELINE_TYPES } from "../../../domain/entities/ASTGuidelines"; import { SurveyChildCountType } from "../../utils/surveyChildCountHelper"; export class SurveyTestRepository implements SurveyRepository { + deleteEventSurvey(_eventId: string, _orgUnitId: string, _programId: string): FutureData { + throw new Error("Method not implemented."); + } getSurveyNameAndASTGuidelineFromId( id: string, surveyFormType: SURVEY_FORM_TYPES diff --git a/src/data/utils/surveyFormMappers.ts b/src/data/utils/surveyFormMappers.ts index 47b135ba..adbc462b 100644 --- a/src/data/utils/surveyFormMappers.ts +++ b/src/data/utils/surveyFormMappers.ts @@ -212,7 +212,7 @@ const getRepeatedStageEvents = ( dataElements: ProgramDataElement[], options: Option[], programStageSections?: ProgramStageSection[] -) => { +): QuestionnaireStage[] | undefined => { const repeatedStageEvents = trackedEntity?.enrollments ?.at(0) ?.events.filter(e => e.programStage === stage.id); @@ -254,7 +254,7 @@ const getRepeatedStageEvents = ( instanceId: repeatedStageEvt.event, sortOrder: stage.sortOrder, repeatable: stage.repeatable, - userAdded: index === 0 ? false : true, + isAddedByUser: index === 0 ? false : true, }; }); }; diff --git a/src/domain/repositories/SurveyRepository.ts b/src/domain/repositories/SurveyRepository.ts index 78a1a1e5..3129ed2a 100644 --- a/src/domain/repositories/SurveyRepository.ts +++ b/src/domain/repositories/SurveyRepository.ts @@ -32,6 +32,7 @@ export interface SurveyRepository { ): FutureData; deleteSurvey(id: Id, orgUnitId: Id, programId: Id): FutureData; + deleteEventSurvey(eventId: Id, orgUnitId: Id, programId: Id): FutureData; getSurveyNameAndASTGuidelineFromId( id: Id, diff --git a/src/domain/usecases/RemoveRepeatableProgramStageUseCase.ts b/src/domain/usecases/RemoveRepeatableProgramStageUseCase.ts new file mode 100644 index 00000000..db9b9ece --- /dev/null +++ b/src/domain/usecases/RemoveRepeatableProgramStageUseCase.ts @@ -0,0 +1,28 @@ +import { FutureData } from "../../data/api-futures"; +import { PREVALENCE_FACILITY_LEVEL_FORM_ID } from "../../data/entities/D2Survey"; +import { Questionnaire } from "../entities/Questionnaire/Questionnaire"; +import { Future } from "../entities/generic/Future"; +import { SurveyRepository } from "../repositories/SurveyRepository"; + +export class RemoveRepeatableProgramStageUseCase { + constructor(private surveyRepository: SurveyRepository) {} + + execute(questionnaire: Questionnaire, stageId: string): FutureData { + //Repeatable Program Stages are only applicable to Prevalence Facility forms + + const eventId = questionnaire.stages.find(stage => stage.id === stageId)?.instanceId; + + if (!eventId) + return Future.error(new Error("Cannot find event Id correspoding to the stage")); + + return this.surveyRepository + .deleteEventSurvey(eventId, questionnaire.orgUnit.id, PREVALENCE_FACILITY_LEVEL_FORM_ID) + .flatMap(() => { + const updatedQuestionnaire = Questionnaire.removeProgramStage( + questionnaire, + stageId + ); + return Future.success(updatedQuestionnaire); + }); + } +} diff --git a/src/domain/usecases/SaveFormDataUseCase.ts b/src/domain/usecases/SaveFormDataUseCase.ts index f01a93b4..b8b55a49 100644 --- a/src/domain/usecases/SaveFormDataUseCase.ts +++ b/src/domain/usecases/SaveFormDataUseCase.ts @@ -34,7 +34,7 @@ export class SaveFormDataUseCase { surveyFormType === "PPSSurveyForm" && orgUnitId === "" ? GLOBAL_OU_ID : orgUnitId; //Do not allow creation of multiple Prevalence Facility Level Forms for the same facility. - if (surveyFormType === "PrevalenceFacilityLevelForm") { + if (!eventId && surveyFormType === "PrevalenceFacilityLevelForm") { return this.surveyReporsitory .getSurveys(surveyFormType, programId, ouId, false) .flatMap(surveys => { diff --git a/src/webapp/components/survey/hook/useSurveyForm.ts b/src/webapp/components/survey/hook/useSurveyForm.ts index 31fb349a..2cda00eb 100644 --- a/src/webapp/components/survey/hook/useSurveyForm.ts +++ b/src/webapp/components/survey/hook/useSurveyForm.ts @@ -177,14 +177,20 @@ export function useSurveyForm(formType: SURVEY_FORM_TYPES, eventId: string | und const removeProgramStage = useCallback( (stageId: Id) => { if (questionnaire) { - const updatedQuestionnaire = Questionnaire.removeProgramStage( - questionnaire, - stageId + setLoading(true); + compositionRoot.surveys.removeRepeatableStage.execute(questionnaire, stageId).run( + updatedQuestionnaire => { + setQuestionnaire(updatedQuestionnaire); + setLoading(false); + }, + err => { + setLoading(false); + setError(err.message); + } ); - setQuestionnaire(updatedQuestionnaire); } }, - [questionnaire] + [compositionRoot.surveys, questionnaire] ); return { From 76f99afd3fcf7c646a36c30530bdff8f9c0fab9f Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 22 May 2024 14:09:22 +0530 Subject: [PATCH 3/7] feat: hide program stage based on datastore survey rule --- src/domain/entities/AMRSurveyModule.ts | 2 +- .../entities/Questionnaire/Questionnaire.ts | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/domain/entities/AMRSurveyModule.ts b/src/domain/entities/AMRSurveyModule.ts index 472fd0ae..1324bee0 100644 --- a/src/domain/entities/AMRSurveyModule.ts +++ b/src/domain/entities/AMRSurveyModule.ts @@ -4,7 +4,7 @@ export type SURVEY_TYPE = "NationalSurvey" | "HospitalSurvey" | "SupranationalSu type UserGroups = { captureAccess: NamedRef[]; readAccess: NamedRef[]; adminAccess: NamedRef[] }; -type SurveyRuleType = "HIDEFIELD" | "HIDESECTION"; +type SurveyRuleType = "HIDEFIELD" | "HIDESECTION" | "HIDESTAGE"; type Rule = { id: Id; diff --git a/src/domain/entities/Questionnaire/Questionnaire.ts b/src/domain/entities/Questionnaire/Questionnaire.ts index 1e0fe441..f7a8b4b2 100644 --- a/src/domain/entities/Questionnaire/Questionnaire.ts +++ b/src/domain/entities/Questionnaire/Questionnaire.ts @@ -174,6 +174,9 @@ export class Questionnaire { const updatedStages = questionnaire.stages.map(stage => { return { ...stage, + isVisible: !surveyRule.rules.find(rule => + rule.toHide?.find(ruleStage => ruleStage === stage.id) + ), sections: stage.sections.map(section => { const currentSectionRule = surveyRule.rules.find(rule => rule.toHide?.find(de => de === section.code) @@ -208,6 +211,29 @@ export class Questionnaire { updatedStages ); + const hideEntityQuestionRule = surveyRule.rules.find( + rule => + rule.type === "HIDEFIELD" && + rule.toHide.find(id => + updatedQuestionnaire.entity?.questions.find(q => q.id === id) + ) + ); + if (hideEntityQuestionRule && questionnaire.entity) { + const updatedEntityQuestions: Question[] = questionnaire.entity.questions.map( + question => { + return { + ...question, + isVisible: hideEntityQuestionRule.toHide.find(id => id === question.id) + ? false + : true, + }; + } + ); + + const updatedEntity = { ...questionnaire.entity, questions: updatedEntityQuestions }; + return Questionnaire.updateQuestionnaireEntity(updatedQuestionnaire, updatedEntity); + } + return updatedQuestionnaire; } From 9464557232f17a481652ea4aeef43727d6169bdb Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 22 May 2024 14:25:32 +0530 Subject: [PATCH 4/7] fix: use dd-mm-yyy format --- .../components/survey-questions/widgets/DatePickerWidget.tsx | 1 + .../components/survey-questions/widgets/DateTimePickerWidget.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/webapp/components/survey-questions/widgets/DatePickerWidget.tsx b/src/webapp/components/survey-questions/widgets/DatePickerWidget.tsx index 2bcb511a..8922de3e 100644 --- a/src/webapp/components/survey-questions/widgets/DatePickerWidget.tsx +++ b/src/webapp/components/survey-questions/widgets/DatePickerWidget.tsx @@ -30,6 +30,7 @@ const DatePickerWidget: React.FC = props => { value={stateValue} disabled={props.disabled} onChange={newValue => notifyChange(newValue)} + format="dd-MM-yyyy" /> ); diff --git a/src/webapp/components/survey-questions/widgets/DateTimePickerWidget.tsx b/src/webapp/components/survey-questions/widgets/DateTimePickerWidget.tsx index ba4ad78a..8f53cb5b 100644 --- a/src/webapp/components/survey-questions/widgets/DateTimePickerWidget.tsx +++ b/src/webapp/components/survey-questions/widgets/DateTimePickerWidget.tsx @@ -32,6 +32,7 @@ const DateTimePickerWidget: React.FC = props => { disabled={props.disabled} onChange={newValue => notifyChange(newValue?.toISOString() ?? "")} ampm={false} + format="dd-MM-yyyy HH:mm" /> ); From ecb550e6d87bf620a96b2d20b53312ed5a38c871 Mon Sep 17 00:00:00 2001 From: Miquel Adell Date: Wed, 22 May 2024 14:26:10 +0200 Subject: [PATCH 5/7] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef4bfd2f..e6ed1d95 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "amr-surveys", "description": "AMR Surveys App", - "version": "0.2.0", + "version": "0.5.0", "license": "GPL-3.0", "author": "EyeSeeTea team", "homepage": ".", From eefc8231b808b500978b5b6e085480fec74bc684 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 22 May 2024 18:53:43 +0530 Subject: [PATCH 6/7] fix: do not redirect for HOSP survey type --- src/webapp/pages/survey-list/useRedirectHome.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/webapp/pages/survey-list/useRedirectHome.ts b/src/webapp/pages/survey-list/useRedirectHome.ts index 5bba2750..31fa0c43 100644 --- a/src/webapp/pages/survey-list/useRedirectHome.ts +++ b/src/webapp/pages/survey-list/useRedirectHome.ts @@ -30,9 +30,6 @@ export function useRedirectHome() { if ( (formType === "PPSCountryQuestionnaire" && !currentPPSSurveyForm) || - (hasAdminAccess && - formType === "PPSHospitalForm" && - !currentCountryQuestionnaire) || (formType === "PPSWardRegister" && !currentHospitalForm) || (formType === "PPSPatientRegister" && !currentWardRegister) || (hasAdminAccess && @@ -52,7 +49,6 @@ export function useRedirectHome() { currentModule, userGroups, currentPPSSurveyForm, - currentCountryQuestionnaire, currentHospitalForm, currentWardRegister, currentPrevalenceSurveyForm, From 40cbaec71c4918d4552d5059ac2ebfb5ac9274d2 Mon Sep 17 00:00:00 2001 From: 9sneha-n <9sneha.n@gmail.com> Date: Wed, 22 May 2024 18:54:41 +0530 Subject: [PATCH 7/7] chore: translations --- i18n/en.pot | 7 +++++-- i18n/es.po | 5 ++++- src/webapp/pages/survey-list/useRedirectHome.ts | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index d88c1ae8..1bbabe4e 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-04-30T16:29:46.275Z\n" -"PO-Revision-Date: 2024-04-30T16:29:46.275Z\n" +"POT-Creation-Date: 2024-05-22T13:24:01.336Z\n" +"PO-Revision-Date: 2024-05-22T13:24:01.336Z\n" msgid "Facilities" msgstr "" @@ -144,6 +144,9 @@ msgstr "" msgid "Org Unit" msgstr "" +msgid "Facility Code" +msgstr "" + msgid "Start Date" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index 8812065f..dfb8e5cc 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2024-05-14T07:10:22.779Z\n" +"POT-Creation-Date: 2024-05-22T13:24:01.336Z\n" "PO-Revision-Date: 2018-10-25T09:02:35.143Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -144,6 +144,9 @@ msgstr "" msgid "Org Unit" msgstr "" +msgid "Facility Code" +msgstr "" + msgid "Start Date" msgstr "" diff --git a/src/webapp/pages/survey-list/useRedirectHome.ts b/src/webapp/pages/survey-list/useRedirectHome.ts index 31fa0c43..dab11fcf 100644 --- a/src/webapp/pages/survey-list/useRedirectHome.ts +++ b/src/webapp/pages/survey-list/useRedirectHome.ts @@ -9,7 +9,6 @@ export function useRedirectHome() { const { currentPPSSurveyForm, currentPrevalenceSurveyForm, - currentCountryQuestionnaire, currentHospitalForm, currentWardRegister, currentFacilityLevelForm,