diff --git a/i18n/en.pot b/i18n/en.pot index 057dc5b..348dcb1 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-11-22T15:21:43.931Z\n" -"PO-Revision-Date: 2024-11-22T15:21:43.931Z\n" +"POT-Creation-Date: 2024-11-27T21:40:09.970Z\n" +"PO-Revision-Date: 2024-11-27T21:40:09.970Z\n" msgid "Low" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index b440624..01086e1 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-11-22T15:21:43.931Z\n" +"POT-Creation-Date: 2024-11-27T21:40:09.970Z\n" "PO-Revision-Date: 2018-10-25T09:02:35.143Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/src/data/repositories/IncidentActionD2Repository.ts b/src/data/repositories/IncidentActionD2Repository.ts index 20c8187..1d2d9bd 100644 --- a/src/data/repositories/IncidentActionD2Repository.ts +++ b/src/data/repositories/IncidentActionD2Repository.ts @@ -134,7 +134,8 @@ export class IncidentActionD2Repository implements IncidentActionRepository { saveIncidentAction( formData: ActionPlanFormData | ResponseActionFormData | SingleResponseActionFormData, - diseaseOutbreakId: Id + diseaseOutbreakId: Id, + formOptionsToDelete?: Id[] ): FutureData { const programStageId = this.getProgramStageByFormType(formData.type); @@ -178,6 +179,10 @@ export class IncidentActionD2Repository implements IncidentActionRepository { if (saveResponse.status === "ERROR" || !diseaseOutbreakId) { return Future.error(new Error(`Error saving Incident Action`)); } else { + if (formOptionsToDelete && formOptionsToDelete.length > 0) { + return this.deleteIncidentResponseAction(formOptionsToDelete); + } + return Future.success(undefined); } }); @@ -185,6 +190,27 @@ export class IncidentActionD2Repository implements IncidentActionRepository { }); } + private deleteIncidentResponseAction(events: Id[]): FutureData { + const d2Events: D2TrackerEvent[] = events.map(event => ({ + event: event, + status: "COMPLETED", + program: RTSL_ZEBRA_PROGRAM_ID, + orgUnit: RTSL_ZEBRA_ORG_UNIT_ID, + occurredAt: "", + dataValues: [], + })); + + return apiToFuture( + this.api.tracker.post({ importStrategy: "DELETE" }, { events: d2Events }) + ).flatMap(response => { + if (response.status === "ERROR") { + return Future.error(new Error(`Error deleting Response Action`)); + } else { + return Future.success(undefined); + } + }); + } + updateIncidentResponseAction(options: UpdateIncidentResponseActionOptions): FutureData { const { diseaseOutbreakId, eventId, responseAction } = options; diff --git a/src/data/repositories/RiskAssessmentD2Repository.ts b/src/data/repositories/RiskAssessmentD2Repository.ts index ec42d6f..048fed6 100644 --- a/src/data/repositories/RiskAssessmentD2Repository.ts +++ b/src/data/repositories/RiskAssessmentD2Repository.ts @@ -261,7 +261,8 @@ export class RiskAssessmentD2Repository implements RiskAssessmentRepository { | RiskAssessmentGradingFormData | RiskAssessmentSummaryFormData | RiskAssessmentQuestionnaireFormData, - diseaseOutbreakId: Id + diseaseOutbreakId: Id, + formOptionsToDelete?: Id[] ): FutureData { if (formData.type === "risk-assessment-questionnaire") { const { stdQuestionnaireStageId, customQuestionnaireStageId } = @@ -295,7 +296,8 @@ export class RiskAssessmentD2Repository implements RiskAssessmentRepository { customQuestionnaireDataElements, formData, diseaseOutbreakId, - customQuestionnaireStageId + customQuestionnaireStageId, + formOptionsToDelete ); } ); @@ -336,7 +338,8 @@ export class RiskAssessmentD2Repository implements RiskAssessmentRepository { | RiskAssessmentSummaryFormData | RiskAssessmentQuestionnaireFormData, diseaseOutbreakId: Id, - programStageId: Id + programStageId: Id, + formOptionsToDelete?: Id[] ): FutureData { //Get the enrollment Id for the disease outbreak return apiToFuture( @@ -368,11 +371,37 @@ export class RiskAssessmentD2Repository implements RiskAssessmentRepository { if (saveResponse.status === "ERROR" || !diseaseOutbreakId) { return Future.error(new Error(`Error Risk Assessment Grading`)); } else { + if (formOptionsToDelete && formOptionsToDelete.length > 0) { + return this.deleteCustomQuestion(formOptionsToDelete); + } + return Future.success(undefined); } }); }); } + + private deleteCustomQuestion(events: Id[]): FutureData { + const d2Events: D2TrackerEvent[] = events.map(event => ({ + event: event, + status: "COMPLETED", + program: RTSL_ZEBRA_PROGRAM_ID, + orgUnit: RTSL_ZEBRA_ORG_UNIT_ID, + occurredAt: "", + dataValues: [], + })); + + return apiToFuture( + this.api.tracker.post({ importStrategy: "DELETE" }, { events: d2Events }) + ).flatMap(response => { + if (response.status === "ERROR") { + return Future.error(new Error(`Error deleting Custom Question`)); + } else { + return Future.success(undefined); + } + }); + } + private getProgramStageByFormType(formType: string) { switch (formType) { case "risk-assessment-grading": diff --git a/src/data/repositories/test/IncidentActionTestRepository.ts b/src/data/repositories/test/IncidentActionTestRepository.ts index 77cab7f..e93caa5 100644 --- a/src/data/repositories/test/IncidentActionTestRepository.ts +++ b/src/data/repositories/test/IncidentActionTestRepository.ts @@ -21,7 +21,11 @@ export class IncidentActionTestRepository implements IncidentActionRepository { throw new Error("Method not implemented."); } - saveIncidentAction(_formData: any, _diseaseOutbreakId: Id): FutureData { + saveIncidentAction( + _formData: any, + _diseaseOutbreakId: Id, + _formOptionsToDelete?: Id[] + ): FutureData { throw new Error("Method not implemented."); } diff --git a/src/domain/repositories/IncidentActionRepository.ts b/src/domain/repositories/IncidentActionRepository.ts index 1ef27f3..3a1858a 100644 --- a/src/domain/repositories/IncidentActionRepository.ts +++ b/src/domain/repositories/IncidentActionRepository.ts @@ -18,7 +18,8 @@ export interface IncidentActionRepository { ): FutureData>; saveIncidentAction( formData: ActionPlanFormData | ResponseActionFormData | SingleResponseActionFormData, - diseaseOutbreakId: Id + diseaseOutbreakId: Id, + formOptionsToDelete?: Id[] ): FutureData; updateIncidentResponseAction(options: UpdateIncidentResponseActionOptions): FutureData; } diff --git a/src/domain/repositories/RiskAssessmentRepository.ts b/src/domain/repositories/RiskAssessmentRepository.ts index bb5dc54..ce311cb 100644 --- a/src/domain/repositories/RiskAssessmentRepository.ts +++ b/src/domain/repositories/RiskAssessmentRepository.ts @@ -25,6 +25,7 @@ export interface RiskAssessmentRepository { | RiskAssessmentGradingFormData | RiskAssessmentSummaryFormData | RiskAssessmentQuestionnaireFormData, - diseaseOutbreakId: Id + diseaseOutbreakId: Id, + formOptionsToDelete?: Id[] ): FutureData; } diff --git a/src/domain/usecases/SaveEntityUseCase.ts b/src/domain/usecases/SaveEntityUseCase.ts index 9d96465..b1f581a 100644 --- a/src/domain/usecases/SaveEntityUseCase.ts +++ b/src/domain/usecases/SaveEntityUseCase.ts @@ -28,7 +28,8 @@ export class SaveEntityUseCase { public execute( formData: ConfigurableForm, - configurations: Configurations + configurations: Configurations, + formOptionsToDelete?: Id[] ): FutureData { if (!formData || !formData.entity) return Future.error(new Error("No form data found")); switch (formData.type) { @@ -49,14 +50,16 @@ export class SaveEntityUseCase { case "risk-assessment-questionnaire": return this.options.riskAssessmentRepository.saveRiskAssessment( formData, - formData.eventTrackerDetails.id + formData.eventTrackerDetails.id, + formOptionsToDelete ); case "incident-action-plan": case "incident-response-actions": case "incident-response-action": return this.options.incidentActionRepository.saveIncidentAction( formData, - formData.eventTrackerDetails.id + formData.eventTrackerDetails.id, + formOptionsToDelete ); case "incident-management-team-member-assignment": { const isIncidentManager = formData.entity.teamRoles?.find( diff --git a/src/domain/usecases/utils/risk-assessment/GetRiskAssessmentById.ts b/src/domain/usecases/utils/risk-assessment/GetRiskAssessmentById.ts index 4299982..83762bb 100644 --- a/src/domain/usecases/utils/risk-assessment/GetRiskAssessmentById.ts +++ b/src/domain/usecases/utils/risk-assessment/GetRiskAssessmentById.ts @@ -196,19 +196,19 @@ function getRiskSummarySelections( configurations.selectableOptions; const riskAssessor1 = riskSummaryConfig.riskAssessors.find( - assessor => assessor.id === summaryDataValues?.riskAssessor1 + assessor => assessor.username === summaryDataValues?.riskAssessor1 ); const riskAssessor2 = riskSummaryConfig.riskAssessors.find( - assessor => assessor.id === summaryDataValues?.riskAssessor2 + assessor => assessor.username === summaryDataValues?.riskAssessor2 ); const riskAssessor3 = riskSummaryConfig.riskAssessors.find( - assessor => assessor.id === summaryDataValues?.riskAssessor3 + assessor => assessor.username === summaryDataValues?.riskAssessor3 ); const riskAssessor4 = riskSummaryConfig.riskAssessors.find( - assessor => assessor.id === summaryDataValues?.riskAssessor4 + assessor => assessor.username === summaryDataValues?.riskAssessor4 ); const riskAssessor5 = riskSummaryConfig.riskAssessors.find( - assessor => assessor.id === summaryDataValues?.riskAssessor5 + assessor => assessor.username === summaryDataValues?.riskAssessor5 ); const overallRiskGlobal = riskSummaryConfig.overallRiskGlobal.find( risk => risk.id === summaryDataValues?.overallRiskGlobal diff --git a/src/webapp/components/form/Form.tsx b/src/webapp/components/form/Form.tsx index 5263297..8493665 100644 --- a/src/webapp/components/form/Form.tsx +++ b/src/webapp/components/form/Form.tsx @@ -14,10 +14,12 @@ export type FormProps = { onSave: () => void; onCancel?: () => void; handleAddNew?: () => void; + handleRemove?: (id: string) => void; }; export const Form: React.FC = React.memo(props => { - const { formState, onFormChange, onSave, onCancel, errorLabels, handleAddNew } = props; + const { formState, onFormChange, onSave, onCancel, errorLabels, handleAddNew, handleRemove } = + props; const { formLocalState, handleUpdateFormField } = useLocalForm(formState, onFormChange); return ( @@ -49,6 +51,8 @@ export const Form: React.FC = React.memo(props => { errorLabels={errorLabels} handleAddNew={handleAddNew} addNewField={section.addNewField} + handleRemove={handleRemove} + removeOption={section.removeOption} /> ); })} diff --git a/src/webapp/components/form/FormSection.tsx b/src/webapp/components/form/FormSection.tsx index 5e0380e..e183d1c 100644 --- a/src/webapp/components/form/FormSection.tsx +++ b/src/webapp/components/form/FormSection.tsx @@ -8,6 +8,7 @@ import { FieldWidget } from "./FieldWidget"; import { AddNewFieldState, FormFieldState } from "./FormFieldsState"; import { FormSectionState } from "./FormSectionsState"; import { AddNewOption } from "../add-new-option/AddNewOption"; +import { Button } from "../button/Button"; type FormSectionProps = { id: string; @@ -22,6 +23,8 @@ type FormSectionProps = { errorLabels?: Record; handleAddNew?: () => void; addNewField?: AddNewFieldState; + handleRemove?: (id: string) => void; + removeOption?: boolean; }; export const FormSection: React.FC = React.memo( @@ -38,6 +41,8 @@ export const FormSection: React.FC = React.memo( errorLabels, handleAddNew, addNewField, + handleRemove, + removeOption = false, }) => { return ( @@ -87,6 +92,12 @@ export const FormSection: React.FC = React.memo( ); })} + + {removeOption && handleRemove && ( + + + + )} ) : null} @@ -226,3 +237,9 @@ const FieldContainer = styled.div<{ width?: string; maxWidth?: string }>` width: 100%; } `; + +const ButtonContainer = styled.div` + width: 100%; + display: flex; + justify-content: end; +`; diff --git a/src/webapp/components/form/FormSectionsState.ts b/src/webapp/components/form/FormSectionsState.ts index 43aacd6..9ee8828 100644 --- a/src/webapp/components/form/FormSectionsState.ts +++ b/src/webapp/components/form/FormSectionsState.ts @@ -22,6 +22,7 @@ export type FormSectionState = { subsections?: FormSectionState[]; onClickInfo?: (id: string) => void; addNewField?: AddNewFieldState; + removeOption?: boolean; }; // HELPERS: diff --git a/src/webapp/pages/form-page/FormPage.tsx b/src/webapp/pages/form-page/FormPage.tsx index 39ab385..5408a88 100644 --- a/src/webapp/pages/form-page/FormPage.tsx +++ b/src/webapp/pages/form-page/FormPage.tsx @@ -33,6 +33,7 @@ export const FormPage: React.FC = React.memo(() => { onPrimaryButtonClick, onCancelForm, handleAddNew, + handleRemove, } = useForm(formType, id); useEffect(() => { @@ -53,6 +54,7 @@ export const FormPage: React.FC = React.memo(() => { onCancel={onCancelForm} errorLabels={formLabels?.errors} handleAddNew={handleAddNew} + handleRemove={handleRemove} /> ) : ( formState.message && {formState.message} diff --git a/src/webapp/pages/form-page/incident-action/mapIncidentActionToInitialFormState.ts b/src/webapp/pages/form-page/incident-action/mapIncidentActionToInitialFormState.ts index 1a41477..2578fd8 100644 --- a/src/webapp/pages/form-page/incident-action/mapIncidentActionToInitialFormState.ts +++ b/src/webapp/pages/form-page/incident-action/mapIncidentActionToInitialFormState.ts @@ -300,6 +300,7 @@ export function mapSingleIncidentResponseActionToInitialFormState( verificationOptions: verificationOptions, }, isIncidentManager: isIncidentManager, + isSingleIncidentResponseAction: true, index: 0, }); @@ -307,9 +308,8 @@ export function mapSingleIncidentResponseActionToInitialFormState( id: eventTrackerDetails.id ?? "", title: "Incident Action Plan", subtitle: eventTrackerDetails.name, - titleDescripton: "Step 2:", - subtitleDescripton: "Edit response action", - saveButtonLabel: "Save plan", + titleDescripton: "Edit response action", + saveButtonLabel: "Save response action", isValid: incidentResponseAction ? true : false, sections: [responseActionSection], }; @@ -324,8 +324,15 @@ function getResponseActionSection(options: { }; isIncidentManager: boolean; index: number; + isSingleIncidentResponseAction?: boolean; }) { - const { incidentResponseAction, options: formOptions, index, isIncidentManager } = options; + const { + incidentResponseAction, + options: formOptions, + index, + isIncidentManager, + isSingleIncidentResponseAction, + } = options; const { searchAssignROOptions, statusOptions, verificationOptions } = formOptions; const responseActionSection: FormSectionState = { @@ -421,6 +428,7 @@ function getResponseActionSection(options: { disabled: false, }, ], + removeOption: isSingleIncidentResponseAction ? false : true, }; return responseActionSection; diff --git a/src/webapp/pages/form-page/mapFormStateToEntityData.ts b/src/webapp/pages/form-page/mapFormStateToEntityData.ts index 4092ea0..8f360a0 100644 --- a/src/webapp/pages/form-page/mapFormStateToEntityData.ts +++ b/src/webapp/pages/form-page/mapFormStateToEntityData.ts @@ -557,22 +557,24 @@ function mapFormStateToIncidentResponseActions( const incidentResponseActions: ResponseAction[] = formState.sections .filter(section => !section.id.includes("addNewResponseActionSection")) - .map((_, index): ResponseAction => { + .map((section): ResponseAction => { + const sectionIndex = extractIndex(section.id); + const mainTask = allFields.find(field => - field.id.includes(`${responseActionConstants.mainTask}_${index}`) + field.id.includes(`${responseActionConstants.mainTask}_${sectionIndex}`) )?.value as string; const subActivities = allFields.find(field => - field.id.includes(`${responseActionConstants.subActivities}_${index}`) + field.id.includes(`${responseActionConstants.subActivities}_${sectionIndex}`) )?.value as string; const subPillar = allFields.find(field => - field.id.includes(`${responseActionConstants.subPillar}_${index}`) + field.id.includes(`${responseActionConstants.subPillar}_${sectionIndex}`) )?.value as string; const dueDate = allFields.find(field => - field.id.includes(`${responseActionConstants.dueDate}_${index}`) + field.id.includes(`${responseActionConstants.dueDate}_${sectionIndex}`) )?.value as Date; const searchAssignROValue = allFields.find(field => - field.id.includes(`${responseActionConstants.searchAssignRO}_${index}`) + field.id.includes(`${responseActionConstants.searchAssignRO}_${sectionIndex}`) )?.value as string; const searchAssignRO = formData.options.searchAssignRO.find( option => option.id === searchAssignROValue @@ -580,13 +582,13 @@ function mapFormStateToIncidentResponseActions( if (!searchAssignRO) throw new Error("Responsible officer not found"); const statusValue = allFields.find(field => - field.id.includes(`${responseActionConstants.status}_${index}`) + field.id.includes(`${responseActionConstants.status}_${sectionIndex}`) )?.value as string; const status = formData.options.status.find(option => option.id === statusValue); if (!status) throw new Error("Status not found"); const verificationValue = allFields.find(field => - field.id.includes(`${responseActionConstants.verification}_${index}`) + field.id.includes(`${responseActionConstants.verification}_${sectionIndex}`) )?.value as string; const verification = formData.options.verification.find( option => option.id === verificationValue @@ -596,8 +598,13 @@ function mapFormStateToIncidentResponseActions( }; if (!verification) throw new Error("Verification not found"); + const selectedEntityData = + sectionIndex !== undefined ? formData.entity[sectionIndex] : undefined; + const isResponseActionValid = selectedEntityData !== undefined; + const responseActionId = isResponseActionValid ? selectedEntityData.id : ""; + const responseAction = new ResponseAction({ - id: formData.entity?.[index]?.id ?? "", + id: responseActionId, mainTask: mainTask, subActivities: subActivities, subPillar: subPillar, @@ -748,3 +755,11 @@ function mapFormStateToIncidentManagementTeamMember( status: teamMemberAssigned?.status, }); } + +function extractIndex(input: string): number | undefined { + const parts = input.split("_"); + const lastPart = parts[parts.length - 1]; + const index = Number(lastPart); + + return isNaN(index) ? undefined : index; +} diff --git a/src/webapp/pages/form-page/risk-assessment/mapRiskAssessmentToInitialFormState.ts b/src/webapp/pages/form-page/risk-assessment/mapRiskAssessmentToInitialFormState.ts index 26c7913..e809eac 100644 --- a/src/webapp/pages/form-page/risk-assessment/mapRiskAssessmentToInitialFormState.ts +++ b/src/webapp/pages/form-page/risk-assessment/mapRiskAssessmentToInitialFormState.ts @@ -834,7 +834,7 @@ function getRiskAssessmentCustomQuestionSection( width: "100%", }, ], - + removeOption: true, direction: "row", subsections: [], }; diff --git a/src/webapp/pages/form-page/useForm.ts b/src/webapp/pages/form-page/useForm.ts index 384ac0f..a340bd2 100644 --- a/src/webapp/pages/form-page/useForm.ts +++ b/src/webapp/pages/form-page/useForm.ts @@ -3,7 +3,7 @@ import { Maybe } from "../../../utils/ts-utils"; import i18n from "../../../utils/i18n"; import { useAppContext } from "../../contexts/app-context"; import { Id } from "../../../domain/entities/Ref"; -import { FormState } from "../../components/form/FormState"; +import { FormState, isValidForm } from "../../components/form/FormState"; import { RouteName, useRoutes } from "../../hooks/useRoutes"; import { mapFormStateToEntityData } from "./mapFormStateToEntityData"; import { updateAndValidateFormState } from "./utils/updateDiseaseOutbreakEventFormState"; @@ -25,6 +25,7 @@ import { useCheckWritePermission } from "../../hooks/useHasCurrentUserCaptureAcc import { useSnackbar } from "@eyeseetea/d2-ui-components"; import { usePerformanceOverview } from "../dashboard/usePerformanceOverview"; import { useIncidentActionPlan } from "../incident-action-plan/useIncidentActionPlan"; +import { RiskAssessmentQuestionnaire } from "../../../domain/entities/risk-assessment/RiskAssessmentQuestionnaire"; export type GlobalMessage = { text: string; @@ -56,27 +57,33 @@ type State = { onPrimaryButtonClick: () => void; onCancelForm: () => void; handleAddNew: () => void; + handleRemove: (id: string) => void; }; export function useForm(formType: FormType, id?: Id): State { const { compositionRoot, currentUser, configurations } = useAppContext(); const { goTo } = useRoutes(); + const { getCurrentEventTracker } = useCurrentEventTracker(); - const [globalMessage, setGlobalMessage] = useState>(); - const [formState, setFormState] = useState({ kind: "loading" }); - const [configurableForm, setConfigurableForm] = useState(); - const [formLabels, setFormLabels] = useState(); - const [isLoading, setIsLoading] = useState(false); const currentEventTracker = getCurrentEventTracker(); const { existingEventTrackerTypes } = useExistingEventTrackerTypes(); const { dataPerformanceOverview } = usePerformanceOverview(); const { isIncidentManager } = useIncidentActionPlan(currentEventTracker?.id ?? ""); - useCheckWritePermission(formType); const snackbar = useSnackbar(); + useCheckWritePermission(formType); + + const [globalMessage, setGlobalMessage] = useState>(); + const [formState, setFormState] = useState({ kind: "loading" }); + const [configurableForm, setConfigurableForm] = useState(); + const [formLabels, setFormLabels] = useState(); + const [isLoading, setIsLoading] = useState(false); + const [formSectionsToDelete, setFormSectionsToDelete] = useState([]); + const [entityData, setEntityData] = useState(); const allDataPerformanceEvents = dataPerformanceOverview?.map( event => event.hazardType || event.suspectedDisease ); + const existingEventTrackers = existingEventTrackerTypes.length === 0 ? allDataPerformanceEvents @@ -104,6 +111,7 @@ export function useForm(formType: FormType, id?: Id): State { isIncidentManager: isIncidentManager, }), }); + setEntityData(formData); }, error => { setFormState({ @@ -226,6 +234,85 @@ export function useForm(formType: FormType, id?: Id): State { } }, [configurableForm, configurations, formState.kind, isIncidentManager]); + const handleRemove = useCallback( + (id: string) => { + if (formState.kind !== "loaded" || !entityData) return; + + switch (entityData.type) { + case "risk-assessment-questionnaire": { + const sectionIndexToDelete = formState.data.sections + .filter(section => section.title?.includes("Custom Question")) + .findIndex(section => section.id === id); + + const entityId = entityData.entity?.additionalQuestions?.find( + (_, index) => index === sectionIndexToDelete + )?.id; + + if (entityId) { + setFormSectionsToDelete(prevState => [...prevState, entityId]); + + const updatedEntityData: ConfigurableForm = { + ...entityData, + entity: { + ...entityData.entity, + additionalQuestions: entityData.entity?.additionalQuestions?.filter( + (_, index) => index !== sectionIndexToDelete + ), + } as RiskAssessmentQuestionnaire, + }; + + setEntityData(updatedEntityData); + } + break; + } + case "incident-response-actions": { + const sectionIndexToDelete = formState.data.sections.findIndex( + section => section.id === id + ); + + const entityId = entityData.entity?.find( + (_, index) => index === sectionIndexToDelete + )?.id; + + if (entityId) { + setFormSectionsToDelete(prevState => [...prevState, entityId]); + + const updatedEntityData: ConfigurableForm = { + ...entityData, + entity: entityData.entity.filter( + (_, index) => index !== sectionIndexToDelete + ), + }; + setEntityData(updatedEntityData); + } + break; + } + default: + break; + } + + setFormState(prevState => { + if (prevState.kind === "loaded") { + const formSections = prevState.data.sections.filter( + section => section.id !== id + ); + + return { + kind: "loaded", + data: { + ...prevState.data, + sections: formSections, + isValid: isValidForm(formSections), + }, + }; + } else { + return prevState; + } + }); + }, + [entityData, formState] + ); + const handleFormChange = useCallback( (updatedField: FormFieldState) => { setFormState(prevState => { @@ -236,7 +323,7 @@ export function useForm(formType: FormType, id?: Id): State { configurableForm ); return { - kind: "loaded", + kind: "loaded" as const, data: updatedData, }; } else { @@ -259,7 +346,7 @@ export function useForm(formType: FormType, id?: Id): State { configurableForm ); - compositionRoot.save.execute(formData, configurations).run( + compositionRoot.save.execute(formData, configurations, formSectionsToDelete).run( diseaseOutbreakEventId => { setIsLoading(false); @@ -370,7 +457,9 @@ export function useForm(formType: FormType, id?: Id): State { formState, configurableForm, currentUser.username, - compositionRoot, + formSectionsToDelete, + compositionRoot.save, + compositionRoot.diseaseOutbreakEvent.mapDiseaseOutbreakEventToAlerts, currentEventTracker?.id, goTo, ]); @@ -410,5 +499,6 @@ export function useForm(formType: FormType, id?: Id): State { onPrimaryButtonClick, onCancelForm, handleAddNew, + handleRemove, }; }