+
+ );
+}
diff --git a/app/src/views/AccountMyFormsEap/utils.ts b/app/src/views/AccountMyFormsEap/utils.ts
new file mode 100644
index 0000000000..4287a54b43
--- /dev/null
+++ b/app/src/views/AccountMyFormsEap/utils.ts
@@ -0,0 +1,34 @@
+import {
+ type EAP_TYPE_FULL,
+ type EAP_TYPE_SIMPLIFIED,
+} from '#utils/constants';
+import { type GoApiResponse } from '#utils/restRequest';
+
+type EapResponse = GoApiResponse<'/api/v2/eap-registration/'>;
+export type EapListItem = NonNullable[number];
+
+interface SimplifiedEapDetails {
+ eapType: typeof EAP_TYPE_SIMPLIFIED;
+ data: EapListItem['simplified_eap_details'][number];
+}
+
+interface FullEapDetails {
+ eapType: typeof EAP_TYPE_FULL;
+ data: EapListItem['full_eap_details'][number];
+}
+
+export type EapExpandedListItem = {
+ label: string;
+ lastUpdated?: string;
+ eap: EapListItem;
+ type: 'registration' | 'development' | 'review' | 'revision' | 'validated' | 'approved' | 'signed';
+ disabled?: boolean;
+
+ // Only applicable for development type
+ details: SimplifiedEapDetails | FullEapDetails | undefined;
+};
+
+export type EapExpandedItem = {
+ eap: EapListItem;
+ expandedItems: EapExpandedListItem[];
+};
diff --git a/app/src/views/AccountMyFormsLayout/i18n.json b/app/src/views/AccountMyFormsLayout/i18n.json
index 6b70856db7..c23cf7ce5b 100644
--- a/app/src/views/AccountMyFormsLayout/i18n.json
+++ b/app/src/views/AccountMyFormsLayout/i18n.json
@@ -4,6 +4,7 @@
"fieldReportTabTitle": "Field Report",
"perTabTitle": "PER",
"drefTabTitle": "DREF",
- "threeWTabTitle": "3W"
+ "threeWTabTitle": "3W",
+ "eapApplications": "EAP Applications"
}
}
\ No newline at end of file
diff --git a/app/src/views/AccountMyFormsLayout/index.tsx b/app/src/views/AccountMyFormsLayout/index.tsx
index 5364a38441..c7eaac05d2 100644
--- a/app/src/views/AccountMyFormsLayout/index.tsx
+++ b/app/src/views/AccountMyFormsLayout/index.tsx
@@ -35,6 +35,11 @@ export function Component() {
>
{strings.threeWTabTitle}
+
+ {strings.eapApplications}
+
diff --git a/app/src/views/DrefApplicationForm/index.tsx b/app/src/views/DrefApplicationForm/index.tsx
index 226d5a1c49..58b95680cd 100644
--- a/app/src/views/DrefApplicationForm/index.tsx
+++ b/app/src/views/DrefApplicationForm/index.tsx
@@ -308,6 +308,7 @@ export function Component() {
const loadResponseToFormValue = useCallback((response: GetDrefResponse) => {
handleDrefLoad(response);
+
const {
planned_interventions,
proposed_action,
diff --git a/app/src/views/DrefDetail/i18n.json b/app/src/views/DrefDetail/i18n.json
new file mode 100644
index 0000000000..47ce2fe4c4
--- /dev/null
+++ b/app/src/views/DrefDetail/i18n.json
@@ -0,0 +1,15 @@
+{
+ "namespace": "drefDetail",
+ "strings": {
+ "drefIntroHeading": "DREF Intro",
+ "drefIntroDetailOne": "Every year, small and medium-sized disasters occur in silence. Without media attention or international visibility, they can struggle to attract funding—putting affected communities at risk of being completely neglected.",
+ "drefIntroDetailTwo": "To support these smaller disasters, or to provide initial funding before launching an Emergency Appeal, we rapidly channel funding to Red Cross and Red Crescent Societies through the DREF—enabling them to deliver fast and effective local humanitarian action.",
+ "drefProcessHeading": "Dref Process",
+ "drefProcessSubHeading": "We provide funding in two ways:",
+ "drefProcessListOne": "A loan facility: start-up funding for the IFRC and National Societies to respond to large-scale disasters, which will later be reimbursed by donor contributions to an Emergency Appeal.",
+ "drefProcessListTwo": "A grant facility: funding for National Society responses to small- and medium-sized disasters. This is used when no Emergency Appeal will be launched or when support from other actors is not foreseen.",
+ "drefProcessDetailOne": "The fund is demand-driven and locally-owned. It is open to all 191 National Societies that submit funding applications and plans of action reflecting locally identified priorities and needs.",
+ "drefProcessDetailTwo": "On average, the DREF supports more than 100 responses to small and medium-sized disasters every year.",
+ "drefDrefApplication": "DREF Application"
+ }
+}
diff --git a/app/src/views/DrefDetail/index.tsx b/app/src/views/DrefDetail/index.tsx
new file mode 100644
index 0000000000..33869faf08
--- /dev/null
+++ b/app/src/views/DrefDetail/index.tsx
@@ -0,0 +1,58 @@
+import {
+ Container,
+ ListView,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+import SurgeContentContainer from '#components/domain/SurgeContentContainer';
+import Link from '#components/Link';
+
+import i18n from './i18n.json';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+
+
{strings.drefIntroDetailOne}
+
{strings.drefIntroDetailTwo}
+
+
+
{strings.drefProcessSubHeading}
+
+
+ {strings.drefProcessListOne}
+
+
+ {strings.drefProcessListTwo}
+
+
+
+ {strings.drefProcessDetailOne}
+
+
+ {strings.drefProcessDetailTwo}
+
+
+
+ {strings.drefDrefApplication}
+
+
+
+ );
+}
+
+Component.displayName = 'DrefDetail';
diff --git a/app/src/views/DrefProcess/i18n.json b/app/src/views/DrefProcess/i18n.json
new file mode 100644
index 0000000000..01904a6dda
--- /dev/null
+++ b/app/src/views/DrefProcess/i18n.json
@@ -0,0 +1,9 @@
+{
+ "namespace": "drefProcess",
+ "strings": {
+ "eapHeading": "Disaster Response Emergency Fund (DREF)",
+ "eapDescription": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action.",
+ "eapProcessDrefTab": "Response And Imminent Dref",
+ "eapProcessEapTab": "Early Action Protocols (EAP)"
+ }
+}
diff --git a/app/src/views/DrefProcess/index.tsx b/app/src/views/DrefProcess/index.tsx
new file mode 100644
index 0000000000..2ed605891a
--- /dev/null
+++ b/app/src/views/DrefProcess/index.tsx
@@ -0,0 +1,37 @@
+import { Outlet } from 'react-router-dom';
+import { NavigationTabList } from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+import NavigationTab from '#components/NavigationTab';
+import Page from '#components/Page';
+
+import i18n from './i18n.json';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+
+ {strings.eapProcessDrefTab}
+
+
+ {strings.eapProcessEapTab}
+
+
+
+
+ );
+}
+
+Component.displayName = 'DrefProcess';
diff --git a/app/src/views/EapFullForm/EAPSourceInformationInput/i18n.json b/app/src/views/EapFullForm/EAPSourceInformationInput/i18n.json
new file mode 100644
index 0000000000..fb51cf85e1
--- /dev/null
+++ b/app/src/views/EapFullForm/EAPSourceInformationInput/i18n.json
@@ -0,0 +1,8 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "eapSourceInformationNameLabel": "Name",
+ "eapSourceInformationLinkLabel": "Link",
+ "eapSourceInformationDeleteButton": "Delete Source Information"
+ }
+}
diff --git a/app/src/views/EapFullForm/EAPSourceInformationInput/index.tsx b/app/src/views/EapFullForm/EAPSourceInformationInput/index.tsx
new file mode 100644
index 0000000000..159f2dfd4b
--- /dev/null
+++ b/app/src/views/EapFullForm/EAPSourceInformationInput/index.tsx
@@ -0,0 +1,122 @@
+import { useCallback } from 'react';
+import { DeleteBinTwoLineIcon } from '@ifrc-go/icons';
+import {
+ Button,
+ TextInput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ isNotDefined,
+ randomString,
+} from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type PartialForm,
+ type SetValueArg,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import NonFieldError from '#components/NonFieldError';
+import { type components } from '#generated/types';
+
+import i18n from './i18n.json';
+
+type EAPSourceInformation = components['schemas']['EAPSourceInformation'] & { client_id: string };
+
+export type SourceInformationFormFields = PartialForm;
+
+interface Props {
+ value: SourceInformationFormFields;
+ error: ArrayError | undefined;
+ onChange: (
+ value: SetValueArg,
+ index: number
+ ) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ readOnly?: boolean;
+}
+
+function EAPSourceInformationInput(props: Props) {
+ const {
+ error: errorFromProps,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ readOnly,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const onFieldChange = useFormObject(index, onChange, () => ({
+ client_id: randomString(),
+ }));
+
+ const error = value && value.client_id && errorFromProps
+ ? getErrorObject(errorFromProps?.[value.client_id])
+ : undefined;
+
+ const handleSourceFieldChange = useCallback(
+ (newValue: string | undefined) => {
+ if (
+ isNotDefined(newValue)
+ || newValue.startsWith('http://')
+ || newValue.startsWith('https://')
+ || newValue === 'h'
+ || newValue === 'ht'
+ || newValue === 'htt'
+ || newValue === 'http'
+ || newValue === 'http:'
+ || newValue === 'http:/'
+ || newValue === 'https'
+ || newValue === 'https:'
+ || newValue === 'https:/'
+ ) {
+ onFieldChange(newValue, 'source_link');
+ return;
+ }
+
+ onFieldChange(`https://${newValue}`, 'source_link');
+ },
+ [onFieldChange],
+ );
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
+export default EAPSourceInformationInput;
diff --git a/app/src/views/EapFullForm/EapActivationProcess/i18n.json b/app/src/views/EapFullForm/EapActivationProcess/i18n.json
new file mode 100644
index 0000000000..b25e56db9a
--- /dev/null
+++ b/app/src/views/EapFullForm/EapActivationProcess/i18n.json
@@ -0,0 +1,44 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "activationProcessHeading": "EAP Activation Process",
+ "activationProcessTooltip": "It is crucial to select early actions that have the most potential to reduce the identified risks(s) and are feasible to implement given the lead time of the forecast. It is important to describe briefly: Who was involved? What data was consulted? Was research conducted? Were communities involved? For more guidance see FbF Manual, Chapter 4.2 Select Early Actions.",
+ "activationProcessTitle": "Early action implementation process",
+ "activationProcessDescription1": "Include a matrix/flowchart for a quick overview of the early action implementation process.",
+ "activationProcessDescription2": "Early Describe the step-by-step process from Day 1 to Day X for the implementation of the selected early actions. Indicate the day when the Stop Mechanism would occur. Include all critical and support tasks that are necessary for each of the steps. Each task should indicate the position of the person responsible (including when cash-based actions are planned liaison with the financial service provider)... implementation process",
+ "activationProcessDescriptionLabel": "Description",
+ "activationProcessExplanatoryLabel": "Explanatory Note",
+ "activationProcessRequiredPointsLabel": "Required Points",
+ "activationImplementationExplanatoryNote": "As a crucial component of the EAP, once the trigger has been reached, everyone involved should be knowledgeable about what will be done, where, when and by whom. The described implementation process shows that each step of the activation has been thought through and considered and that implementation in the lead time available is possible. The set of tasks described in this section should cover all activities from the moment the trigger is reached (Day 1) to the completion of post-impact surveys (Day X).",
+ "activationImplementationRequiredPoint1": "Include a matrix/flowchart for a quick overview of the early action implementation process.",
+ "activationImplementationRequiredPoint2": "Describe the step-by-step process from Day 1 to Day X for the implementation of the selected early actions. Indicate the day when the Stop Mechanism would occur. Include all critical and support tasks that are necessary for each of the steps. Each task should indicate the position of the person responsible (including when cash-based actions are planned liaison with the financial service provider).",
+ "activationImplementationRequiredPoint3": "For each action, include at which level it will take place (HQ, branch, community).",
+ "activationImplementationRequiredPoint4": "Each NS should have a detailed version of this process, including communication flows, for each task and the name of the person responsible with their contact information. This document should be regularly updated.",
+ "activationProcessUploadLabel": "Upload",
+ "activationTriggerTitle": "Trigger activation system",
+ "activationTriggerDescription1": "Describe the automatic system used to monitor the forecasts, generate the intervention map and send the alert message when the trigger is reached.",
+ "activationTriggerDescription2": "If this automatic system does not yet exist, explain how forecasts will be monitored, intervention maps generated and how the relevant actors will be informed that the trigger has been reached.",
+ "activationTriggerDescription3": "Indicate who gives the signal to start the activation.",
+ "activationTriggerExplanatoryNote": "The activation process starts with the message that the trigger has been reached (on Day 1). Ideally, there is a system in place to automatically monitor the forecasts and send an automatic message of alert to relevant actors as soon as a trigger is reached. It is expected that this will be executed by the national meteorological office and/or national DRM authority. If this automatic system does not exist, a mechanism needs to be in place to monitor the forecasts and alert relevant actors as soon as a trigger is reached to initiate the early actions.",
+ "activationTriggerRequiredPoint1": "Describe the automatic system used to monitor the forecasts, generate the intervention map and send the alert message when the trigger is reached.",
+ "activationTriggerRequiredPoint2": "If this automatic system does not yet exist, explain how forecasts will be monitored, intervention maps generated and how the relevant actors will be informed that the trigger has been reached.",
+ "activationTriggerRequiredPoint3": "Indicate who gives the signal to start the activation.",
+ "activationPeopleTargetedTitle": "People Targeted",
+ "activationPeopleTargetedDescription": "Specify number of people targeted",
+ "activationSelectionPopulationTitle": "Selection of target population",
+ "activationSelectionDescription1": "Provide a short summary of the target population, (the number, location etc.)",
+ "activationSelectionDescription2": "Describe how the target population will be selected, with a special focus on feasibility in the short period of time between forecast and event",
+ "activationSelectionDescription3": "If the EAP is intending to use Social Protection systems or other government beneficiary databases, indicate how the potential number of targeted households be selected",
+ "activationSelectionExplanatoryNote": "FbF aims to protect the most vulnerable from the impact of extreme weather events. Based on the analysis on vulnerability and exposure (in section 3) and on the described mechanism for identifying intervention areas/communities (in section 4- Intervention area), it needs to be clear, how vulnerability criteria and impact forecasts will be applied to determine who will be targeted.",
+ "activationStopMechanismTitle": "Stop Mechanism",
+ "activationStopMechanismDescription1": "Indicate on which day of activation the stop mechanism is foreseen, and who is responsible to give the signal to stop.",
+ "activationStopMechanismDescription2": "Describe when the stop mechanism begins and whether in-kind/cash distribution would be stopped or not. For cash actions cancelled, how would this be coordinated with the financial service provider? For in-kind distribution, what would happen with the perishable items?",
+ "activationStopMechanismDescription3": "Explain how it would be communicated to communities and stakeholders that the activities are being stopped.",
+ "activationStopMechanismExplanatoryNote": "For forecast triggers with a lead time of more than three days, the EAP should include the description of a stop mechanism. This means that if a later forecast – prior to the start of activities (related to the early action(s)) shows that the event is no longer likely to occur, the activation of the EAP will be stopped to avoid generating further use of resources. For example, if the 6-day forecast on Day 1 indicates high risk of heavy rainfall and thereby triggers the activation and the new 6-day-forecast released on Day 3 shows that the risk has significantly lowered, the trigger level is no longer reached. If the start of distributions was planned for Day 4, activation should be stopped. Items that have been purchased based on the trigger being reached and are not distributed due to the stop mechanism should be stored in the warehouse for a future activation. For forecast triggers with a lead time of less than 3 days, the EAP should include the description of what the National Society would do if the forecast changes in strength or location within the last three days before the event.",
+ "activationAttachFilesTitle": "Attach Relevant Files",
+ "activationAttachFilesDescription": "Attach any additional maps, documentation, files, images, etc.",
+ "activationSourceOfInformationTitle": "Sources of Information",
+ "activationSourceOfInformationAddNewLabel": "Add New Source of Information",
+ "activationSourceOfInformationDescription": "Add the description of the sources one at a time. If the source has a link, add in the second field."
+ }
+}
diff --git a/app/src/views/EapFullForm/EapActivationProcess/index.tsx b/app/src/views/EapFullForm/EapActivationProcess/index.tsx
new file mode 100644
index 0000000000..67338ab9a6
--- /dev/null
+++ b/app/src/views/EapFullForm/EapActivationProcess/index.tsx
@@ -0,0 +1,338 @@
+import { useCallback } from 'react';
+import {
+ Button,
+ Heading,
+ InfoPopup,
+ InputSection,
+ ListView,
+ NumberInput,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+ useFormArray,
+} from '@togglecorp/toggle-form';
+
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import MultiImageWithCaptionInput from '#components/domain/MultiImageWithCaptionInput';
+import NonFieldError from '#components/NonFieldError';
+import TabPage from '#components/TabPage';
+
+import EAPSourceInformationInput, { type SourceInformationFormFields } from '../EAPSourceInformationInput';
+import { type PartialEapFullFormType } from '../schema';
+
+import i18n from './i18n.json';
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+}
+
+function EapActivationProcess(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const error = getErrorObject(formError);
+
+ const {
+ setValue: onRiskSourceInformationChange,
+ removeValue: onRiskSourceInformationRemove,
+ } = useFormArray<
+ 'activation_process_source_of_information',
+ SourceInformationFormFields
+ >('activation_process_source_of_information', setFieldValue);
+
+ const handleSourceInformationAdd = useCallback(() => {
+ const newSourceInformationItem: SourceInformationFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: SourceInformationFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newSourceInformationItem,
+ ],
+ 'activation_process_source_of_information' as const,
+ );
+ }, [setFieldValue]);
+
+ return (
+
+
+
+ {strings.activationProcessHeading}
+
+
+
+
+
+
{strings.activationImplementationRequiredPoint1}
+
{strings.activationImplementationRequiredPoint2}
+
{strings.activationImplementationRequiredPoint3}
+
{strings.activationImplementationRequiredPoint4}
+
+ )}
+ />
+
+ )}
+ description={(
+
+
{strings.activationProcessDescription1}
+
{strings.activationProcessDescription2}
+
+ )}
+ withAsteriskOnTitle
+ >
+
+
+
+
+
+
+
{strings.activationTriggerRequiredPoint1}
+
{strings.activationTriggerRequiredPoint2}
+
{strings.activationTriggerRequiredPoint3}
+
+ )}
+ />
+
+ )}
+ description={(
+
+
{strings.activationTriggerDescription1}
+
{strings.activationTriggerDescription2}
+
{strings.activationTriggerDescription3}
+
+ )}
+ >
+
+
+
+
+
+
+
+
+
+
{strings.activationSelectionDescription1}
+
{strings.activationSelectionDescription2}
+
{strings.activationSelectionDescription3}
+
+ )}
+ />
+
+ )}
+ description={(
+
+
{strings.activationSelectionDescription1}
+
{strings.activationSelectionDescription2}
+
{strings.activationSelectionDescription3}
+
+ )}
+ >
+
+
+
+
+
+
{strings.activationStopMechanismDescription1}
+
{strings.activationStopMechanismDescription2}
+
{strings.activationStopMechanismDescription3}
+
+ )}
+ />
+
+ )}
+ description={(
+
+
{strings.activationStopMechanismDescription1}
+
{strings.activationStopMechanismDescription2}
+
{strings.activationStopMechanismDescription3}
+
+ )}
+ >
+
+
+
+
+ {strings.activationProcessUploadLabel}
+
+
+
+
+ {value?.activation_process_source_of_information?.map(
+ (source, index) => (
+
+ ),
+ )}
+
+
+
+
+ );
+}
+
+export default EapActivationProcess;
diff --git a/app/src/views/EapFullForm/FinanceLogistics/i18n.json b/app/src/views/EapFullForm/FinanceLogistics/i18n.json
new file mode 100644
index 0000000000..a4ada3d230
--- /dev/null
+++ b/app/src/views/EapFullForm/FinanceLogistics/i18n.json
@@ -0,0 +1,41 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "financeHeading": "Finance and Logistics",
+ "financeBudgetTitle": "Budget",
+ "financeBudgetDescription1": "Provide the EAP budget as a separate annex using the IFRC standard budgeting template for Early Action Protocol and following the same order (and output codes) as in the operational matrix filled in the EAP activation process section.",
+ "financeBudgetDescription2": "In the budget, make sure to indicate who (Host National Society, PNS, IFRC) will be responsible for each expenditure according to the roles and responsibilities in the EAP.",
+ "financeBudgetDescription3": "The budget groups in the budget template are meant to be a guidance and the most suitable one should be identified and used.",
+ "financeBudgetDescription4": "Avoid using lumpsums as unit measure.",
+ "financeTotalBudgetLabel": "Total Budget",
+ "financeDescriptionLabel": "Description",
+ "financeExplanatoryNoteLabel": "Explanatory Note",
+ "financeRequiredPointsLabel": "Required Points",
+ "financeExplanatoryNote": "The EAP budget consists of all the costs linked to the activation of the EAP as well as readiness and pre-positioning costs. The budget cannot include costs for the development of the EAP and the setting up of the FbF system in a country (e.g. initial trainings of volunteers, etc.). This process should be financed by other sources of longer-term funding. The maximum amount of funding available for each EAP from the DREF is 500,000 Swiss francs. The budget will have to include the IFRC indirect costs of 6,5%. The National Society may include administrative costs as well in the EAP which should not be more than 5% of the early action budget. If the 5% rate is not used the National Society will need to list out the each of the admin cost individually. The M&E budget should be maximum 5% of overall the budget.",
+ "financeUploadButtonLabel": "Upload",
+ "financeDownloadDescription": "Download full budget template",
+ "financeUploadBudgetLabel": "Upload Budget",
+ "financeReadinessCostTitle": "Readiness Cost",
+ "financeReadinessCostExplanatoryNote": "Readiness costs cover those costs related to the upkeep/maintenance of the FbF system in-country, once it has been established and the EAP has been developed. This refers to the required costs to ensure that the NS is “ready” to implement the EAP at any point during the five-year lifecycle of the EAP. These could include, for example, costs for refresher trainings, warehouses, updating data, staff, costs for markets monitoring, costs for updating the cash transfer value etc. Readiness combined with pre-positioning costs are limited to 65% of the total EAP budget over the EAP’s lifecycle and are disbursed by the DREF on an annual basis through the IFRC Operational Plan for that specific country.",
+ "financeReadinessCostDescription1": "For each item of readiness costs in the budget, explain why these are necessary for the upkeep of the EAP and how these were calculated.",
+ "financeReadinessCostDescription2": "Indicate who will manage these funds and describe how it will be ensured that they are only used for the indicated purposes.",
+ "financeReadinessBudgetLabel": "Readiness Budget",
+ "financePrePositioningTitle": "Pre-positioning Cost",
+ "financePrePositioningExplanatoryNote": "In order to ensure the feasibility of the rapid distribution of items in the short timeframe between forecast and event, pre-positioning of goods might be necessary. They should normally have a lifetime of at least the lifecycle of the EAP and should only be replenished after an activation. The DREF covers these costs, combined with readiness, to a maximum amount of 65% of the EAP budget (combined with the readiness activities). Please note that costs that are not for the procurement of the items but related to the maintenance of the stock, such as warehousing, are part of the readiness costs of an EAP (see section 9.2.)",
+ "financePrePositioningDescription1": "If funds for pre-positioning are requested from the DREF, explain for which items and why no other option is possible. Explain why standard response stocks cannot be used.",
+ "financePrePositioningDescription2": "Expiry date of the items should not be prior to the end of the lifecycle of the EAP",
+ "financePrePositioningDescription3": "Provide information about the location of the storage facilities and costs of storage, etc.",
+ "financePrePositioningBudgetLabel": "Pre-Positioning Budget",
+ "financeEarlyActionCostTitle": "Early Action Cost",
+ "financeEarlyActionBudgetLabel": "Early Actions Budget",
+ "financeEarlyActionCostDescription1": "In the budget, list all these costs under the section early action costs.",
+ "financeEarlyActionCostDescription2": "Indicate activation procedures once the trigger is reached, clearly define the funds release procedures including who initiates the funds request, approval chain/procedures and process of disbursement including time frames from the source of funds to HQ and branches.",
+ "financeEarlyActionCostDescription3": "For the items included in the early action budget, indicate how they will be procured in the short activation period (e.g. Are there pre-disaster agreements made with suppliers? Are items readily available in the needed quantities with the identified suppliers? Are agreements with financial service providers ready for activation?) Or will you use the early action funds to replenish items that are already in stock?",
+ "financeEarlyActionCostDescription4": "Indicate if other sources of funding were used for the initial purchase of relief items for an activation (in this case the DREF could fund the replenishment of stock only if they are used for the early actions).",
+ "financeEarlyActionCostExplanatoryNote": "Early Action costs cover all expenditures that are linked to the activation of the EAP, once the trigger has been reached. This can cover identification of target populations; CVA; distribution of items and/or cash, and provision of services; deployment of volunteers and staff; reporting and M & E, such as implementation monitoring; and impact survey data collection and analysis.",
+ "financeEapEndorsementHeading": "EAP endorsement/Approval",
+ "financeEapEndorsementTitle": "EAP endorsement",
+ "financeEapEndorsementExplanatoryNote": "It should be ensured that at the point of the trigger being reached no further permissions are needed. Thus, the EAP should have prior approval from all relevant stakeholders. The EAP must be endorsed by the leadership of the submitting NS. The EAP should also be endorsed by other key relevant stakeholders, such as the NHMS and the respective DRM authorities. If technical working groups have been created for FbF, their members should also endorse the final version of the EAP before submission.",
+ "financeEapEndorsementDescription": "Describe by whom, how and when the EAP was agreed and endorsed."
+ }
+}
diff --git a/app/src/views/EapFullForm/FinanceLogistics/index.tsx b/app/src/views/EapFullForm/FinanceLogistics/index.tsx
new file mode 100644
index 0000000000..ac4a142d6a
--- /dev/null
+++ b/app/src/views/EapFullForm/FinanceLogistics/index.tsx
@@ -0,0 +1,278 @@
+import {
+ Heading,
+ InputSection,
+ ListView,
+ NumberInput,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+} from '@togglecorp/toggle-form';
+
+import GoSingleFileInput from '#components/domain/GoSingleFileInput';
+import TabPage from '#components/TabPage';
+
+import { type PartialEapFullFormType } from '../schema';
+
+import i18n from './i18n.json';
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+}
+
+function FinanceLogistics(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const error = getErrorObject(formError);
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+ {strings.financeHeading}
+
+ )}
+ description={(
+
+ )}
+ withAsteriskOnTitle
+ >
+
+
+
+ {strings.financeEapEndorsementHeading}
+
+ )}
+ description={strings.financeEapEndorsementDescription}
+ withAsteriskOnTitle
+ >
+
+
+
+
+ );
+}
+
+export default FinanceLogistics;
diff --git a/app/src/views/EapFullForm/Meal/i18n.json b/app/src/views/EapFullForm/Meal/i18n.json
new file mode 100644
index 0000000000..3a816917eb
--- /dev/null
+++ b/app/src/views/EapFullForm/Meal/i18n.json
@@ -0,0 +1,21 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "mealHeading": "Monitoring, Evaluation, Accountability Learning (Meal)",
+ "mealTitle": "Meal",
+ "mealDescription1": "Following the guidance of the FbF Manual, describe the M&E plan for this EAP. Including:",
+ "mealDescription11": "EAP Monitoring (between the trigger moment and the implementation of the actions)",
+ "mealDescription12": "Impact evaluation plan: how, when and by whom will the robust impact evaluation to assess how early actions reduced the humanitarian impact of the extreme event be conducted. Please note that the IFRC DREF...",
+ "mealDescription13": "Trigger evaluation by whom, when and how the trigger evaluation will be conducted)",
+ "mealDescription14": "Learning (when, who and how the learning will take place. E.g workshop, interviews etc). ",
+ "mealDescription2": "If a more detailed M&E plan is available add it as an annex. ",
+ "mealDescription3": "Describe how the FbF M&E plan is linked to the existing PMER system of the National Society. If the NS does not have a PMER system, explain how the EAP will be used to strengthen this area prior to activation",
+ "mealDescriptionLabel": "Description",
+ "mealExplanatoryNoteLabel": "Explanatory Note",
+ "mealRequiredPointsLabel": "Required Points",
+ "mealExplanatoryNote": "Building evidence about the impact of FbF systems is a priority. Therefore, the EAP should include an M&E plan to 1) assess the impact of the early actions and the extreme event after each activation and 2) identify if all activities were carried out as planned and document how early actions were implemented 3) learn from the process to improve the system in the future. The chapters 4.3 Design M&E plan and 6. Activate, Monitor, Evaluate in the FbF Manual, provide guidance on the set-up and implementation of the monitoring, evaluation, learning tools. Ideally, the M&E system should be set up to allow comparison of impacts between communities that received early actions and those that didn´t (please refer to FbF manual for more information). This M&E plan should be harmonized with the existing IFRC PMER guidance and tools, available on FedNet.",
+ "mealAttachRelevantFilesTitle": "Attach relevant files",
+ "mealAttachRelevantFilesDescription": "Attach any additional maps, documentation, files, images, etc.",
+ "mealAttachRelevantFilesUploadLabel": "Upload"
+ }
+}
diff --git a/app/src/views/EapFullForm/Meal/index.tsx b/app/src/views/EapFullForm/Meal/index.tsx
new file mode 100644
index 0000000000..b2af41547a
--- /dev/null
+++ b/app/src/views/EapFullForm/Meal/index.tsx
@@ -0,0 +1,131 @@
+import {
+ Heading,
+ InputSection,
+ ListView,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+} from '@togglecorp/toggle-form';
+
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import TabPage from '#components/TabPage';
+
+import { type PartialEapFullFormType } from '../schema';
+
+import i18n from './i18n.json';
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch>>;
+}
+
+function Meal(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const error = getErrorObject(formError);
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+
+ {strings.mealHeading}
+
+
+
+
+
{strings.mealDescription1}
+
+
{strings.mealDescription11}
+
{strings.mealDescription12}
+
{strings.mealDescription13}
+
{strings.mealDescription14}
+
+
{strings.mealDescription2}
+
{strings.mealDescription3}
+
+ )}
+ />
+
+ )}
+ description={(
+
+
{strings.mealDescription1}
+
+
{strings.mealDescription11}
+
{strings.mealDescription12}
+
{strings.mealDescription13}
+
+
{strings.mealDescription2}
+
{strings.mealDescription3}
+
+ )}
+ withAsteriskOnTitle
+ >
+
+
+
+
+ {strings.mealAttachRelevantFilesUploadLabel}
+
+
+
+
+ );
+}
+
+export default Meal;
diff --git a/app/src/views/EapFullForm/NationalSocietyCapacity/i18n.json b/app/src/views/EapFullForm/NationalSocietyCapacity/i18n.json
new file mode 100644
index 0000000000..ea1798505a
--- /dev/null
+++ b/app/src/views/EapFullForm/NationalSocietyCapacity/i18n.json
@@ -0,0 +1,23 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "capacityHeading": "National Society Capacity",
+ "capacityHeadingTooltip": "Capacity to deliver early action is a key aspect of the FbF system. To have access to the DREF the NS should describe why and how it will be able to implement the early actions proposed in this protocol within the lead time and reaching all of the targeted population. This section could make reference to NS’s experience with previous DREFs (types of disasters, quantity of operations, planned operations implemented, among others). If a National Society has already gone through a Preparedness for Effective Response (PER) assessment process the results of these assessments should be referred to in this section as they provide National Societies with systematic, evidence-based information on their ability to conduct timely early action (looking also at support areas).",
+ "capacityOperationalTitle": "Operational, thematic and administrative capacity",
+ "capacityOperationalDescription1": "Describe how the National Society has operative and administrative capacity to implement the EAPs. Describe the National Society’s experience in the implementation of the selected early actions (Livelihoods, including Cash and Voucher Assistance; WASH: Food Security; Shelter, etc.). If the NS does not have experience in these areas, indicate the steps taken to improve its capacity in the respective sector to implement the EAP effectively and efficiently.",
+ "capacityOperationalDescription2": "If a feasibility study on FbF was conducted, indicate the findings in relation to the capacity of the NS to implement FbF.",
+ "capacityOperationalDescription3": "Indicate the number of staff and volunteers available for a potential activation. Explain how they have been trained on FbF/ activation.",
+ "capacityOperationalDescription4": "Explain if special structures are foreseen for EAP activation, e.g. NDRTs and specially trained volunteers per branch.",
+ "capacityDescriptionLabel": "Description",
+ "capacityRequiredPointsLabel": "Required Points",
+ "capacityExplanatoryNoteLabel": "Explanatory Note",
+ "capacityExplanatoryNote": "While the funds for the readiness and pre-positioning will be transferred as soon as the EAP is approved and the legal agreement has been signed, the funds for the early action activation will only be transferred once the trigger has been met and the trigger notification has been received by IFRC. Please not that while this allocation is done immediately upon notification it may still take a few days for the funds to arrive in country. Therefore, especially for short lead time EAPs it is crucial for the National Society and their partners to plan accordingly.",
+ "capacityStrategiesPlansTitle": "Strategies and plans",
+ "capacityStrategiesPlansDescription": "Describe how the EAP is aligned with the Disaster Risk Management strategy of the National Society (e.g. in the existing contingency plan, DRR plan etc.).",
+ "capacityFinancialCapacityTitle": "Financial capacity to advance funds",
+ "capacityFinancialCapacityDescription": "Indicate whether the NS (and/or PNS in country) has the capacity to advance funds, to start early actions, in the short duration between trigger and funds from the DREF arriving.",
+ "capacityNationalRelevantFilesTitle": "Attach relevant files",
+ "capacityNationalRelevantFilesDescription": "Attach any additional maps, documentation, files, images, etc.",
+ "capacityNationalRelevantFilesUploadLabel": "Upload"
+ }
+}
diff --git a/app/src/views/EapFullForm/NationalSocietyCapacity/index.tsx b/app/src/views/EapFullForm/NationalSocietyCapacity/index.tsx
new file mode 100644
index 0000000000..6702af1bd2
--- /dev/null
+++ b/app/src/views/EapFullForm/NationalSocietyCapacity/index.tsx
@@ -0,0 +1,146 @@
+import {
+ Heading,
+ InfoPopup,
+ InputSection,
+ ListView,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+} from '@togglecorp/toggle-form';
+
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import TabPage from '#components/TabPage';
+
+import { type PartialEapFullFormType } from '../schema';
+
+import i18n from './i18n.json';
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+}
+function NationalSocietyCapacity(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const error = getErrorObject(formError);
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+
+ {strings.capacityHeading}
+
+
+
+
+
+ )}
+ />
+
+ )}
+ description={strings.capacityFinancialCapacityDescription}
+ withAsteriskOnTitle
+ >
+
+
+
+
+ {strings.capacityNationalRelevantFilesUploadLabel}
+
+
+
+
+ );
+}
+
+export default NationalSocietyCapacity;
diff --git a/app/src/views/EapFullForm/Overview/KeyActorsInput/i18n.json b/app/src/views/EapFullForm/Overview/KeyActorsInput/i18n.json
new file mode 100644
index 0000000000..9c62c218c1
--- /dev/null
+++ b/app/src/views/EapFullForm/Overview/KeyActorsInput/i18n.json
@@ -0,0 +1,8 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "overviewKeyActorsSelectPartnerLabel": "Select Partner",
+ "overviewKeyActorsDescriptionLabel": "Description",
+ "overviewKeyActorsDeleteButton": "Delete Actor"
+ }
+}
diff --git a/app/src/views/EapFullForm/Overview/KeyActorsInput/index.tsx b/app/src/views/EapFullForm/Overview/KeyActorsInput/index.tsx
new file mode 100644
index 0000000000..a912e659c8
--- /dev/null
+++ b/app/src/views/EapFullForm/Overview/KeyActorsInput/index.tsx
@@ -0,0 +1,88 @@
+import { DeleteBinTwoLineIcon } from '@ifrc-go/icons';
+import {
+ Button,
+ TextArea,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type SetValueArg,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import NationalSocietySelectInput from '#components/domain/NationalSocietySelectInput';
+import { type PartialEapFullFormType } from '#views/EapFullForm/schema';
+
+import i18n from './i18n.json';
+
+type KeyActorsFormFields = NonNullable[number];
+
+interface Props {
+ value: KeyActorsFormFields;
+ error: ArrayError | undefined;
+ onChange: (value: SetValueArg, index: number) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ readOnly?: boolean;
+}
+
+function KeyActorsInput(props: Props) {
+ const {
+ value,
+ onChange,
+ onRemove,
+ index,
+ disabled,
+ readOnly,
+ error: errorFromProps,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const onFieldChange = useFormObject(
+ index,
+ onChange,
+ () => ({
+ client_id: randomString(),
+ }),
+ );
+
+ const error = (value && value.client_id && errorFromProps)
+ ? getErrorObject(errorFromProps?.[value.client_id])
+ : undefined;
+
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
+export default KeyActorsInput;
diff --git a/app/src/views/EapFullForm/Overview/i18n.json b/app/src/views/EapFullForm/Overview/i18n.json
new file mode 100644
index 0000000000..04825796f9
--- /dev/null
+++ b/app/src/views/EapFullForm/Overview/i18n.json
@@ -0,0 +1,88 @@
+{
+ "namespace": "form",
+ "strings": {
+ "overviewHeading": "Details",
+ "nationalSociety": "National Society (NS)",
+ "nationalSocietyDescription": "Select National Society that is planning to apply for the EAP",
+ "formCountry": "Country",
+ "formCountryDescription": "The country will be pre-populated based on the NS selection, but can be adapted as needed.",
+ "disasterType": "Disaster Type",
+ "disasterTypeDescription": "Select the disaster type for which the EAP is needed.",
+ "formUploadCoverImage": "Cover Photo",
+ "formUploadCoverImageDescription": "Upload a image for the cover page of the publicly published DREF application.",
+ "formUploadAnImageLabel": "Select an Image",
+ "formExpectedSubmissionTimeTitle": "Expected Time of Submission",
+ "formExpectedSubmissionTimeDescription": "Include the propose time of submission, accounting for the time it will take to deliver the application.",
+ "objectiveTitle": "Objective",
+ "objectiveDescription": "Please provide an objective statement that describes the main goal of the intervention.",
+ "formContacts": "Contacts",
+ "nationalHeader": "National",
+ "delegationHeader": "Delegation",
+ "regionalHeader": "Regional and global",
+ "stakeholderHeader": "Stakeholder",
+ "nSContact": "National Society Contact",
+ "nSContactDescription": "National Society contact responsible for the EAP process",
+ "nSName": "Name",
+ "nSTitle": "Title",
+ "nSEmail": "Email",
+ "nSPhoneNumber": "Phone Number",
+ "partnerNS": "Partner NS",
+ "partnerNSDescription": "Partner National Society contact",
+ "partnerNSName": "Name",
+ "partnerNSTitle": "Title",
+ "partnerNSEmail": "Email",
+ "partnerNSPhoneNumber": "Phone Number",
+ "formFocalPoint": "IFRC Delegation AA Focal Point",
+ "formFocalPointName": "Name",
+ "formFocalPointTitle": "Title",
+ "formFocalPointEmail": "Email",
+ "formFocalPointPhoneNumber": "Phone Number",
+ "delegation": "IFRC Head of Delegation",
+ "delegationName": "Name",
+ "delegationTitle": "Title",
+ "delegationEmail": "Email",
+ "delegationPhoneNumber": "Phone Number",
+ "drefFocalPoint": "DREF Focal Point",
+ "drefFocalPointDescription": "The DREF contact person fro IFRC",
+ "drefFocalPointName": "Name",
+ "drefFocalPointTitle": "Title",
+ "drefFocalPointEmail": "Email",
+ "drefFocalPointPhoneNumber": "Phone Number",
+ "regionalFocalPoint": "IFRC Regional AA Focal Point",
+ "regionalFocalPointName": "Name",
+ "regionalFocalPointTitle": "Title",
+ "regionalFocalPointEmail": "Email",
+ "regionalFocalPointPhoneNumber": "Phone Number",
+ "regionalManager": "IFRC Regional Ops Manager",
+ "regionalManagerName": "Name",
+ "regionalManagerTitle": "Title",
+ "regionalManagerEmail": "Email",
+ "regionalManagerPhoneNumber": "Phone Number",
+ "regionalHead": "IFRC Regional Head of DCC",
+ "regionalHeadName": "Name",
+ "regionalHeadTitle": "Title",
+ "regionalHeadEmail": "Email",
+ "regionalHeadPhoneNumber": "Phone Number",
+ "regionalCoordinator": "IFRC Global Ops Coordinator",
+ "regionalCoordinatorName": "Name",
+ "regionalCoordinatorTitle": "Title",
+ "regionalCoordinatorEmail": "Email",
+ "regionalCoordinatorPhoneNumber": "Phone Number",
+ "keyActorsAddButton": "Add new actor",
+ "workWithGovernmentTitle": "Did you work with the government and other relevant actors in the development of this EAP?",
+ "workWithGovernmentDescription": "Please briefly describe the process",
+ "overviewExplanatoryNoteLabel": "Explanatory Note",
+ "overviewRequiredPointsLabel": "Required Points",
+ "overviewRequiredPoint1": "Name the external actors and Movement components that have been involved in the development of this EAP. Include international, national, regional and local actors, if applicable.",
+ "overviewRequiredPoint2": "In case there are technical working groups for the development of the FbF system in country, indicate which organizations participate in these groups.",
+ "overviewRequiredPoint3": "If stakeholders other than RC are involved in implementation/activation of EAP, indicate in one bullet point per organization, their role and list the formal agreement document.",
+ "workExplanatoryNote": "In order to avoid creating parallel systems and to minimize additional discussions on permissions, etc. when a trigger occurs, all relevant key stakeholders in the country should be involved in the development, and when necessary, the approval, of the EAP. If stakeholders other than the National Society are involved in implementation of the EAP, roles and responsibilities should be determined in MoUs or other appropriate documents. It is key to highlight the importance of involving the IFRC at the country, cluster and/ or regional level early in the EAP development process as these offices can provide technical support.",
+ "actorsExplanatoryNote": "In order to avoid creating parallel systems and to minimize additional discussions on permissions, etc. when a trigger occurs, all relevant key stakeholders in the country should be involved in the development, and when necessary, the approval, of the EAP. If stakeholders other than the National Society are involved in implementation of the EAP, roles and responsibilities should be determined in MoUs or other appropriate documents. It is key to highlight the importance of involving the IFRC at the country, cluster and/ or regional level early in the EAP development process as these offices can provide technical support. ",
+ "workWithGovernmentDescriptionLabel": "Description",
+ "keyActorsTitle": "Key actors",
+ "keyActorsDescription": "Name the external actors and Movement components that have been involved in the development of this EAP. Include international, national, regional and local actors, if applicable.",
+ "technicalWorkingGroupsTitle": "Technical working groups in place?",
+ "technicalWorkingGroupDescription": "In case there are technical working groups for the development of the FbF system in country, indicate which organizations participate in these groups. Use the \"Add another actor\" button to list all the actors involved and explain their role.",
+ "technicalWorkingGroupsTitleLabel": "Title"
+ }
+}
diff --git a/app/src/views/EapFullForm/Overview/index.tsx b/app/src/views/EapFullForm/Overview/index.tsx
new file mode 100644
index 0000000000..8d7a01814e
--- /dev/null
+++ b/app/src/views/EapFullForm/Overview/index.tsx
@@ -0,0 +1,698 @@
+import { useCallback } from 'react';
+import {
+ BooleanInput,
+ Button,
+ Heading,
+ InputSection,
+ ListView,
+ TextArea,
+ TextInput,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ type PartialForm,
+ useFormArray,
+} from '@togglecorp/toggle-form';
+
+import CountrySelectInput from '#components/domain/CountrySelectInput';
+import DisasterTypeSelectInput from '#components/domain/DisasterTypeSelectInput';
+import ImageWithCaptionInput from '#components/domain/ImageWithCaptionInput';
+import NationalSocietySelectInput from '#components/domain/NationalSocietySelectInput';
+import TabPage from '#components/TabPage';
+import { type GoApiBody } from '#utils/restRequest';
+
+import { type PartialEapFullFormType } from '../schema';
+import KeyActorsInput from './KeyActorsInput';
+
+import i18n from './i18n.json';
+
+type EapRegisterRequestBody = GoApiBody<'/api/v2/eap-registration/', 'POST'>;
+type RegistrationFormFields = PartialForm;
+type KeyActorsFormFields = NonNullable<
+ PartialEapFullFormType['key_actors']
+>[number];
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+ eapRegistrationDetail?: RegistrationFormFields;
+}
+
+function Overview(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ eapRegistrationDetail,
+ } = props;
+
+ const strings = useTranslation(i18n);
+ const error = getErrorObject(formError);
+ const noop = () => { };
+
+ const { setValue: onKeyActorsChange, removeValue: onKeyActorsRemove } = useFormArray<'key_actors', KeyActorsFormFields>(
+ 'key_actors',
+ setFieldValue,
+ );
+
+ const handleKeyActorsAdd = useCallback(() => {
+ const newKeyActorsItem: KeyActorsFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: KeyActorsFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newKeyActorsItem,
+ ],
+ 'key_actors' as const,
+ );
+ }, [setFieldValue]);
+
+ return (
+
+
+
+ {strings.overviewHeading}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {strings.formContacts}
+
+
+ {strings.nationalHeader}
+
+
+
+
+
+
+
+
+
+
+
+
+ {strings.delegationHeader}
+
+
+
+
+
+
+
+
+
+
+
+
+ {strings.regionalHeader}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {strings.stakeholderHeader}
+
+ )}
+ description={strings.workWithGovernmentDescription}
+ withAsteriskOnTitle
+ >
+
+
+
+
+
+
+
{strings.overviewRequiredPoint1}
+
{strings.overviewRequiredPoint2}
+
{strings.overviewRequiredPoint3}
+
+ )}
+ />
+
+ )}
+ description={strings.keyActorsDescription}
+ withAsteriskOnTitle
+ >
+ {value.key_actors?.map((actor, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Overview;
diff --git a/app/src/views/EapFullForm/RiskAnalysis/PrioritisedImpactInput/index.tsx b/app/src/views/EapFullForm/RiskAnalysis/PrioritisedImpactInput/index.tsx
new file mode 100644
index 0000000000..d75b758f95
--- /dev/null
+++ b/app/src/views/EapFullForm/RiskAnalysis/PrioritisedImpactInput/index.tsx
@@ -0,0 +1,78 @@
+import { DeleteBinTwoLineIcon } from '@ifrc-go/icons';
+import {
+ Button,
+ ListView,
+ TextInput,
+} from '@ifrc-go/ui';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type SetValueArg,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import NonFieldError from '#components/NonFieldError';
+import { type PartialEapFullFormType } from '#views/EapFullForm/schema';
+
+type PrioritisedImpactFormFields = NonNullable<
+ PartialEapFullFormType['prioritized_impacts']
+>[number];
+
+interface Props {
+ value: PrioritisedImpactFormFields;
+ error: ArrayError | undefined;
+ onChange: (value: SetValueArg, index: number) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ readOnly?: boolean;
+}
+
+function PrioritisedImpactInput(props: Props) {
+ const {
+ error: errorFromProps,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ readOnly,
+ } = props;
+
+ const onFieldChange = useFormObject(index, onChange, () => ({
+ client_id: randomString(),
+ }));
+
+ const error = value && value.client_id && errorFromProps
+ ? getErrorObject(errorFromProps?.[value.client_id])
+ : undefined;
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+export default PrioritisedImpactInput;
diff --git a/app/src/views/EapFullForm/RiskAnalysis/i18n.json b/app/src/views/EapFullForm/RiskAnalysis/i18n.json
new file mode 100644
index 0000000000..1671b74330
--- /dev/null
+++ b/app/src/views/EapFullForm/RiskAnalysis/i18n.json
@@ -0,0 +1,44 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "eapFullFormRiskAnalysisHeading": "Risk Analysis",
+ "eapFullFormHazardSelectionTitle": "Hazard selection",
+ "eapFullFormRiskDescriptionLabel": "Description",
+ "eapFullFormHazardSelectionDescription1": "Provide a brief rationale about the selection of the hazard for the FbF system.",
+ "eapFullFormHazardSelectionDescription2": "Explain the selection of the hazard based on an analysis of historical disaster impacts (using the events registered in the below-mentioned table).",
+ "eapFullFormHazardSelectionDescription3": "Describe the extent to which this hazard has produced and will produce negative impacts on lives, livelihoods, well-being and other developmental aspects.",
+ "eapFullFormHazardSelectionDescription4": "Ensure to address these key questions: What are the impacts of this hazard? How are people most affected? What are the largest daily challenges related to this disaster that will jeopardize their well-being and development? What are the most affected sectors?",
+ "eapFullFormHazardSelectionExplanatoryNote": "Which hazard needs to be addressed by FbF in the country as a priority? Provide an explanation on the reasons that the selected hazard was chosen for this EAP and why it is a major problem in the country.The DREF allocates funding for EAPs to reduce the impacts of extreme events of a strength or magnitude that in the past have required humanitarian assistance. In order to demonstrate that the selected hazard has caused extreme humanitarian impacts in the past, information on the previous impacts of the selected hazard in the country should be provided. This can be gathered from interviews with RC or DRM authorities, archives, records, etc. Other potential sources of information could be National disaster registries, Post Disaster Needs Assessment databases, Desinventar, EMDat, PreventionWeb, etc. For more guidance see the FbF Manual (Chapter 4.1 Set the Trigger)",
+ "eapFullFormHazardSelectionRequiredPoint1": "Provide a brief rationale about the selection of the hazard for the FbF system.",
+ "eapFullFormHazardSelectionRequiredPoint2": "Explain the selection of the hazard based on an analysis of historical disaster impacts (using the events registered in the below-mentioned table).",
+ "eapFullFormHazardSelectionRequiredPoint3": "Include a table with the most severe disasters caused by the selected hazard over the past 50 years ",
+ "eapFullFormHazardSelectionRequiredPoint31": "Consider the following columns: a) Year and Date b) type of disaster with name (if applicable); c) Strength of event if available (e.g. windspeed on landfall); d) potential cascading hazards (e.g floods induced by hurricanes, landslides induced by extreme rainfall) e) Regions affected; f) Number of people affected; g) Most affected sectors; h) Most severe impacts in key words (e.g. 10000 houses destroyed, cholera epidemic with 2000 confirmed cases etc.)",
+ "eapFullFormHazardSelectionRequiredPoint4": "Describe the extent to which this hazard has produced and will produce negative impacts on lives, livelihoods, well-being and other developmental aspects. Ensure to address these key questions: What are the impacts of this hazard? How are people most affected? What are the largest daily challenges related to this disaster that will jeopardize their well-being and development? What are the most affected sectors?",
+ "eapFullFormExposeElementTitle": "Exposed elements and their vulnerability factors",
+ "eapFullFormExposeElementDescription1": "Explain which people are most likely to experience the impacts of this hazard? Where do they live, and why are they vulnerable? Note: This will inform the early action selection.",
+ "eapFullFormExposeElementDescription2": "Based on the analysis of past impacts, provide a brief overview which population, infrastructure, natural resources, markets, assets (others) were and/or are likely to be exposed to the selected hazard and where they are located.",
+ "eapFullFormExposeElementDescription3": "Based on past impact and exposure, describe the key factors of vulnerability of the specific population, infrastructure, natural resources, assets (others) that are likely to be impacted.",
+ "eapFullFormExposeElementDescription4": "Please explain how specific population groups (e.g elderly, children, people with disabilities, IDPs, Refugees, etc.) are most likely to be affected.",
+ "eapFullFormExposeElementDescription5": "Note: this exposure and vulnerability analysis will be the basis for the selection of indicators used for the trigger model (section 4.4).",
+ "eapFullFormExposeElementExplanatoryNote": "An analysis of exposure is required to determine who and what is located in the area where the hazard might occur. This will help to determine who and what is likely to be impacted. In line with the impact-based forecasting logic, it is important to identify the main exposed elements on which the FbF intervention will focus. For example, if the prioritized impact of floods is the mortality of children under 5 due to water-borne diseases, then the exposed element will be the population of children under 5: or if the most frequently recurring and largest impact due to tropical storms is the damage to houses built with light materials, then the exposed element will be houses built with light materials. A thorough understanding of the levels of vulnerability (of the exposed elements) will help identify the main risks and ensure that Forecast-based actions are well suited. For instance, if children under 5 are susceptible to death or sickness due to floods, describe the underlying causes of the problem. For more guidance see the FbF Manual (Chapter 4.1 Set the Trigger)",
+ "eapFullFormExposeElementRequiredPoint1": "Explain which people are most likely to experience the impacts of this hazard? Where do they live, and why are they vulnerable? Note: This will inform the early action selection.",
+ "eapFullFormExposeElementRequiredPoint2": "Based on the analysis of past impacts, provide a brief overview which population, infrastructure, natural resources, markets, assets (others) were and/or are likely to be exposed to the selected hazard and where are they located.",
+ "eapFullFormExposeElementRequiredPoint3": "Based on past impact and exposure, describe the key factors of vulnerability of the specific population, infrastructure, natural resources, assets (others) that are likely to be impacted.",
+ "eapFullFormExposeElementRequiredPoint4": "Please explain how specific population groups (e.g elderly, children, people with disabilities, IDPs, Refugees, etc.) are most likely to be affected.",
+ "eapFullFormExposeElementRequiredPoint5": "Note: this exposure and vulnerability analysis will be the basis for the selection of indicators used for the trigger model (section 4.4).",
+ "eapFullFormPrioritisedImpactTitle": "Prioritised impact",
+ "eapFullFormPrioritisedImpactsLabel": "Prioritised impacts",
+ "eapFullFormPrioritisedImpactDescription": "Add the list of prioritised impacts. Explain which priority impacts the EAP will address and why (e.g mortality of alpacas due to cold waves, Internal Displacement due to floods, malnutrition of children under 5 due to drought etc.).",
+ "eapFullFormPrioritisedImpactExplanatoryNote": "Recognizing that an FbF system will not be able to address all risks and potential impacts, based on the analysis of past impact, exposure and vulnerability (sections 3.1. to 3.2) and the results of the joint identification conducted with key stakeholders, indicate which disaster impacts were prioritized, explaining how and why they were prioritized. For more guidance see the FbF Manual (Chapters 4.1 Set the Trigger and 4.2 Select Early Actions)",
+ "eapFullFormAttachFilesTitle": "Attach relevant files",
+ "eapFullFormAttachFilesDescription": "Attach any additional documentation, files, images, etc.",
+ "eapFullFormAttachFilesSelectImagesLabel": "Select Images",
+ "eapFullFormAttachFilesUploadLabel": "Upload",
+ "eapFullFormImpactAddButtonLabel": "Add",
+ "eapFullFormSourceOfInformationTitle": "Sources of information",
+ "eapFullFormSourceOfInformationDescription": "Add the description of the sources one at a time. If the source has a link, add in the second field.",
+ "eapFullFormSourceOfInformationAddNewLabel": "Add New Source Information",
+ "eapFullFormRiskExplanatoryNoteLabel": "Explanatory Note",
+ "eapFullFormRiskRequiredPointsLabel": "Required Points"
+ }
+}
diff --git a/app/src/views/EapFullForm/RiskAnalysis/index.tsx b/app/src/views/EapFullForm/RiskAnalysis/index.tsx
new file mode 100644
index 0000000000..62994faace
--- /dev/null
+++ b/app/src/views/EapFullForm/RiskAnalysis/index.tsx
@@ -0,0 +1,343 @@
+import { useCallback } from 'react';
+import {
+ Button,
+ Heading,
+ InputSection,
+ ListView,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+ useFormArray,
+} from '@togglecorp/toggle-form';
+
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import MultiImageWithCaptionInput from '#components/domain/MultiImageWithCaptionInput';
+import NonFieldError from '#components/NonFieldError';
+import TabPage from '#components/TabPage';
+
+import EAPSourceInformationInput, { type SourceInformationFormFields } from '../EAPSourceInformationInput';
+import { type PartialEapFullFormType } from '../schema';
+import PrioritisedImpactInput from './PrioritisedImpactInput';
+
+import i18n from './i18n.json';
+
+type PrioritisedImpactsFormFields = NonNullable<
+ PartialEapFullFormType['prioritized_impacts']
+>[number];
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+}
+
+function RiskAnalysis(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const error = getErrorObject(formError);
+ const {
+ setValue: onRiskSourceInformationChange,
+ removeValue: onRiskSourceInformationRemove,
+ } = useFormArray<
+ 'risk_analysis_source_of_information',
+ SourceInformationFormFields
+ >('risk_analysis_source_of_information', setFieldValue);
+
+ const { setValue: onPrioritizedChange, removeValue: onPrioritizedRemove } = useFormArray<'prioritized_impacts', PrioritisedImpactsFormFields>(
+ 'prioritized_impacts',
+ setFieldValue,
+ );
+
+ const handleSourceInformationAdd = useCallback(() => {
+ const newSourceInformationItem: SourceInformationFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: SourceInformationFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newSourceInformationItem,
+ ],
+ 'risk_analysis_source_of_information' as const,
+ );
+ }, [setFieldValue]);
+
+ const handlePrioritizedImpactAdd = useCallback(() => {
+ const newPrioritizedImpactItem: PrioritisedImpactsFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: PrioritisedImpactsFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newPrioritizedImpactItem,
+ ],
+ 'prioritized_impacts' as const,
+ );
+ }, [setFieldValue]);
+
+ return (
+
+
+
+ {strings.eapFullFormRiskAnalysisHeading}
+
+
+
+
+
+ )}
+ withAsteriskOnTitle
+ >
+
+
+
+
+ )}
+ description={strings.eapFullFormPrioritisedImpactDescription}
+ withAsteriskOnTitle
+ >
+
+ {value?.prioritized_impacts?.map((impact, index) => (
+
+ ))}
+
+
+
+
+
+
+ {strings.eapFullFormAttachFilesUploadLabel}
+
+
+
+
+ {value.risk_analysis_source_of_information?.map((source, index) => (
+
+ ))}
+
+
+
+
+ );
+}
+
+export default RiskAnalysis;
diff --git a/app/src/views/EapFullForm/SelectionActions/ApproachesInput/i18n.json b/app/src/views/EapFullForm/SelectionActions/ApproachesInput/i18n.json
new file mode 100644
index 0000000000..284b6e8347
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/ApproachesInput/i18n.json
@@ -0,0 +1,19 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "approachBudget": "Budget",
+ "approachApCode": "AP Code",
+ "approachRemoveButton": "Remove",
+ "approachAddActivityButton": "Add Activity",
+ "approachIndicators": "Indicators",
+ "approachAddIndicatorsButtonLabel": "Add Indicators",
+ "approachNoIndicatorsMessage": "No indicators yet",
+ "approachReadinessActivities": "Readiness Activities",
+ "approachReadinessActivitiesDescription": "Readiness activities are done year on year to ensure that the National Society is ready to conduct the early actions. These are activities that will happen irrespective of an activation. Readiness activities may include refresher training, coordination meetings with government, readiness meetings, simulations, etc. Under readiness they can include any ongoing costs and services (human resources and logistics) that are deemed indispensable for subsequent trigger-based early action activities. If, during the simplified EAP development process the National Society finds some areas for improvement to deliver on their selected early actions, these could be addressed with activities included under readiness.",
+ "approachPrepositioningActivities": "Pre-positioning Activities",
+ "approachPrepositioningActivitiesDescription": "The National Society should preposition the materials needed to undertake the early action, especially those that may require a longer procurement process. For example, prepositioned stocks could include shelter kits (for house reinforcement), sandbags (for protecting infrastructure), or tarpaulins (for protecting water sources), etc. Food, medicine and other items with a shelf life of less than two years are not eligible as pre-positioning, they will have to be procured as part of the early actions. Pre-positioning activities are one-off and done in the first year following approval of the simplified EAP.",
+ "approachEarlyActionActivities": "Early Action Activities",
+ "approachEarlyActionActivitiesDescription": "Early action activities are implemented once a trigger is reached and before the impact of the hazard. Early actions seek to reduce or mitigate the impact of the hazard. Consider selecting only a few early actions, especially for sudden onset events, as they will have to be implemented within a short timeframe. The early actions will be unique to each hazard and context, but may be activities such as evacuation of at-risk communities and/or livestock, early harvest of crops, cash transfer, shelter strengthening, provision of water treatment, hygiene kits or mosquito nets, etc. For more examples of early action activities, visit the early action database on the Anticipation Hub.",
+ "approachNoActivitiesMessage": "No activities added yet"
+ }
+}
diff --git a/app/src/views/EapFullForm/SelectionActions/ApproachesInput/index.tsx b/app/src/views/EapFullForm/SelectionActions/ApproachesInput/index.tsx
new file mode 100644
index 0000000000..5685d945cc
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/ApproachesInput/index.tsx
@@ -0,0 +1,408 @@
+import { useCallback } from 'react';
+import {
+ AddLineIcon,
+ DeleteBinTwoLineIcon,
+} from '@ifrc-go/icons';
+import {
+ Button,
+ Container,
+ ExpandableContainer,
+ InfoPopup,
+ ListView,
+ NumberInput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ isNotDefined,
+ randomString,
+} from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type SetValueArg,
+ useFormArray,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import OperationActivityInput from '#components/domain/OperationActivityInput';
+import NonFieldError from '#components/NonFieldError';
+
+import { type PartialEapFullFormType } from '../../schema';
+import IndicatorInput from '../IndicatorInput';
+
+import i18n from './i18n.json';
+
+type EnableApproachesFormFields = NonNullable[number];
+type EarlyActionFormFields = NonNullable[number];
+type PrepositioningFormFields = NonNullable[number];
+type ReadinessFormFields = NonNullable[number];
+type IndicatorFormFields = NonNullable[number];
+
+const defaultApproachValue: EnableApproachesFormFields = {
+ approach: 10,
+};
+
+interface Props {
+ value: EnableApproachesFormFields;
+ error: ArrayError | undefined;
+ onChange: (value: SetValueArg, index: number) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ approachTitle?: React.ReactNode;
+}
+
+function ApproachesInput(props: Props) {
+ const {
+ error: errorFromProps,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ approachTitle,
+ } = props;
+
+ const strings = useTranslation(i18n);
+ const onFieldChange = useFormObject(index, onChange, defaultApproachValue);
+
+ const error = (value && value.approach && errorFromProps)
+ ? getErrorObject(errorFromProps?.[value.approach])
+ : undefined;
+
+ const {
+ setValue: onEarlyActionChange,
+ removeValue: onEarlyActionRemove,
+ } = useFormArray<'early_action_activities', EarlyActionFormFields>(
+ 'early_action_activities' as const,
+ onFieldChange,
+ );
+ const {
+ setValue: onPrepositioningChange,
+ removeValue: onPrepositioningRemove,
+ } = useFormArray<'prepositioning_activities', PrepositioningFormFields>(
+ 'prepositioning_activities' as const,
+ onFieldChange,
+ );
+ const {
+ setValue: onReadinessChange,
+ removeValue: onReadinessRemove,
+ } = useFormArray<'readiness_activities', ReadinessFormFields>(
+ 'readiness_activities' as const,
+ onFieldChange,
+ );
+
+ const {
+ setValue: onIndicatorChange,
+ removeValue: onIndicatorRemove,
+ } = useFormArray<'indicators', IndicatorFormFields>(
+ 'indicators' as const,
+ onFieldChange,
+ );
+
+ const handleEarlyActionAddButtonClick = useCallback(
+ () => {
+ const newActionItem: EarlyActionFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: EarlyActionFormFields[] | undefined) => (
+ [...(oldValue ?? []), newActionItem]
+ ),
+ 'early_action_activities' as const,
+ );
+ },
+ [onFieldChange],
+ );
+
+ const handlePrepositioningAddButtonClick = useCallback(
+ () => {
+ const newActionItem: PrepositioningFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: PrepositioningFormFields[] | undefined) => (
+ [...(oldValue ?? []), newActionItem]
+ ),
+ 'prepositioning_activities' as const,
+ );
+ },
+ [onFieldChange],
+ );
+
+ const handleReadinessAddButtonClick = useCallback(
+ () => {
+ const newActionItem: ReadinessFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: ReadinessFormFields[] | undefined) => (
+ [...(oldValue ?? []), newActionItem]
+ ),
+ 'readiness_activities' as const,
+ );
+ },
+ [onFieldChange],
+ );
+
+ const handleIndicatorAddButtonClick = useCallback(
+ () => {
+ const newIndicator: IndicatorFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: IndicatorFormFields[] | undefined) => (
+ [...(oldValue ?? []), newIndicator]
+ ),
+ 'indicators' as const,
+ );
+ },
+ [onFieldChange],
+ );
+
+ return (
+
+
+
+ )}
+ withPadding
+ withBackground
+ initiallyExpanded
+ >
+
+
+
+
+
+
+ }
+ >
+ {strings.approachAddIndicatorsButtonLabel}
+
+ )}
+ empty={isNotDefined(value.indicators) || value.indicators.length === 0}
+ emptyMessage={strings.approachNoIndicatorsMessage}
+ >
+
+ {value.indicators?.map((indicator, i) => (
+
+ ))}
+
+
+
+ {strings.approachReadinessActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.approachAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={isNotDefined(value.readiness_activities)
+ || value.readiness_activities.length === 0}
+ emptyMessage={strings.approachNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.readiness_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+ {strings.approachPrepositioningActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.approachAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={isNotDefined(value.prepositioning_activities)
+ || value.prepositioning_activities.length === 0}
+ emptyMessage={strings.approachNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.prepositioning_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+ {strings.approachEarlyActionActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.approachAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={isNotDefined(value.early_action_activities)
+ || value.early_action_activities.length === 0}
+ emptyMessage={strings.approachNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.early_action_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+
+
+ );
+}
+
+export default ApproachesInput;
diff --git a/app/src/views/EapFullForm/SelectionActions/EarlyActionsInput/index.tsx b/app/src/views/EapFullForm/SelectionActions/EarlyActionsInput/index.tsx
new file mode 100644
index 0000000000..738a37c913
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/EarlyActionsInput/index.tsx
@@ -0,0 +1,78 @@
+import { DeleteBinTwoLineIcon } from '@ifrc-go/icons';
+import {
+ Button,
+ ListView,
+ TextInput,
+} from '@ifrc-go/ui';
+import { randomString } from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type SetValueArg,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import NonFieldError from '#components/NonFieldError';
+import { type PartialEapFullFormType } from '#views/EapFullForm/schema';
+
+type EarlyActionsFormFields = NonNullable<
+ PartialEapFullFormType['early_actions']
+>[number];
+
+interface Props {
+ value: EarlyActionsFormFields;
+ error: ArrayError | undefined;
+ onChange: (value: SetValueArg, index: number) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ readOnly?: boolean;
+}
+
+function EarlyActionsInput(props: Props) {
+ const {
+ error: errorFromProps,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ readOnly,
+ } = props;
+
+ const onFieldChange = useFormObject(index, onChange, () => ({
+ client_id: randomString(),
+ }));
+
+ const error = value && value.client_id && errorFromProps
+ ? getErrorObject(errorFromProps?.[value.client_id])
+ : undefined;
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+export default EarlyActionsInput;
diff --git a/app/src/views/EapFullForm/SelectionActions/IndicatorInput/i18n.json b/app/src/views/EapFullForm/SelectionActions/IndicatorInput/i18n.json
new file mode 100644
index 0000000000..00573e5d72
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/IndicatorInput/i18n.json
@@ -0,0 +1,8 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "eapFullIndicatorRemoveTitle": "Remove",
+ "eapFullIndicatorTitleLabel": "Title",
+ "eapFullIndicatorTargetLabel": "Target"
+ }
+}
diff --git a/app/src/views/EapFullForm/SelectionActions/IndicatorInput/index.tsx b/app/src/views/EapFullForm/SelectionActions/IndicatorInput/index.tsx
new file mode 100644
index 0000000000..7295b6e68c
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/IndicatorInput/index.tsx
@@ -0,0 +1,97 @@
+import { DeleteBinTwoLineIcon } from '@ifrc-go/icons';
+import {
+ Button,
+ InlineLayout,
+ ListView,
+ NumberInput,
+ TextInput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ type ArrayError,
+ getErrorObject,
+ type PartialForm,
+ type SetValueArg,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import { type components } from '#generated/types';
+
+import i18n from './i18n.json';
+
+type Indicator = components['schemas']['Indicator'] & { client_id: string };
+type IndicatorFormFields = PartialForm;
+
+const defaultIndicatorValue: IndicatorFormFields = {
+ client_id: '-1',
+};
+
+interface Props {
+ value: IndicatorFormFields;
+ error: ArrayError | undefined;
+ onChange: (value: SetValueArg, index: number) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ readOnly?: boolean;
+}
+
+function IndicatorInput(props: Props) {
+ const {
+ error: errorFromProps,
+ readOnly,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const onFieldChange = useFormObject(index, onChange, defaultIndicatorValue);
+
+ const error = value && value.client_id && errorFromProps
+ ? getErrorObject(errorFromProps?.[value.client_id])
+ : undefined;
+
+ return (
+
+
+
+ )}
+ spacing="sm"
+ >
+
+
+
+
+
+ );
+}
+
+export default IndicatorInput;
diff --git a/app/src/views/EapFullForm/SelectionActions/OperationInput/i18n.json b/app/src/views/EapFullForm/SelectionActions/OperationInput/i18n.json
new file mode 100644
index 0000000000..719cf05937
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/OperationInput/i18n.json
@@ -0,0 +1,20 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "selectionActionsPlannedOperationPeopleTargeted": "People Targeted",
+ "selectionActionsPlannedOperationBudget": "Budget",
+ "selectionActionsPlannedOperationApCode": "AP Code",
+ "selectionActionsPlannedOperationRemoveButton": "Remove",
+ "selectionActionsPlannedOperationAddActivityButton": "Add activity",
+ "selectionActionsPlannedOperationIndicators": "Indicators",
+ "addIndicatorsButtonLabel": "Add Indicators",
+ "noIndicatorsMessage": "No indicators yet",
+ "selectionActionsReadinessActivities": "Readiness Activities",
+ "selectionActionsReadinessActivitiesDescription": "Readiness activities are done year on year to ensure that the National Society is ready to conduct the early actions. These are activities that will happen irrespective of an activation. Readiness activities may include refresher training, coordination meetings with government, readiness meetings, simulations, etc. Under readiness they can include any ongoing costs and services (human resources and logistics) that are deemed indispensable for subsequent trigger-based early action activities. If, during the simplified EAP development process the National Society finds some areas for improvement to deliver on their selected early actions, these could be addressed with activities included under readiness.",
+ "selectionActionsPrepositioningActivities": "Pre-positioning Activities",
+ "selectionActionsPrepositioningActivitiesDescription": "The National Society should preposition the materials needed to undertake the early action, especially those that may require a longer procurement process. For example, prepositioned stocks could include shelter kits (for house reinforcement), sandbags (for protecting infrastructure), or tarpaulins (for protecting water sources), etc. Food, medicine and other items with a shelf life of less than two years are not eligible as pre-positioning, they will have to be procured as part of the early actions. Pre-positioning activities are one-off and done in the first year following approval of the simplified EAP.",
+ "selectionActionsEarlyActionActivities": "Early Action Activities",
+ "selectionActionsEarlyActionActivitiesDescription": "Early action activities are implemented once a trigger is reached and before the impact of the hazard. Early actions seek to reduce or mitigate the impact of the hazard. Consider selecting only a few early actions, especially for sudden onset events, as they will have to be implemented within a short timeframe. The early actions will be unique to each hazard and context, but may be activities such as evacuation of at-risk communities and/or livestock, early harvest of crops, cash transfer, shelter strengthening, provision of water treatment, hygiene kits or mosquito nets, etc. For more examples of early action activities, visit the early action database on the Anticipation Hub.",
+ "selectionActionsNoActivitiesMessage": "No activities added yet"
+ }
+}
diff --git a/app/src/views/EapFullForm/SelectionActions/OperationInput/index.tsx b/app/src/views/EapFullForm/SelectionActions/OperationInput/index.tsx
new file mode 100644
index 0000000000..41c553ab6f
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/OperationInput/index.tsx
@@ -0,0 +1,421 @@
+import { useCallback } from 'react';
+import {
+ AddLineIcon,
+ DeleteBinTwoLineIcon,
+} from '@ifrc-go/icons';
+import {
+ Button,
+ Container,
+ ExpandableContainer,
+ InfoPopup,
+ ListView,
+ NumberInput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ isNotDefined,
+ randomString,
+} from '@togglecorp/fujs';
+import {
+ type ArrayError,
+ getErrorObject,
+ type SetValueArg,
+ useFormArray,
+ useFormObject,
+} from '@togglecorp/toggle-form';
+
+import OperationActivityInput from '#components/domain/OperationActivityInput';
+import NonFieldError from '#components/NonFieldError';
+
+import { type PartialEapFullFormType } from '../../schema';
+import IndicatorInput from '../IndicatorInput';
+
+import i18n from './i18n.json';
+
+type PlannedOperationFormFields = NonNullable<
+ PartialEapFullFormType['planned_operations']
+>[number];
+type EarlyActionFormFields = NonNullable<
+ PlannedOperationFormFields['early_action_activities']
+>[number];
+type PrepositioningFormFields = NonNullable<
+ PlannedOperationFormFields['prepositioning_activities']
+>[number];
+type ReadinessFormFields = NonNullable<
+ PlannedOperationFormFields['readiness_activities']
+>[number];
+type IndicatorFormFields = NonNullable<
+ PlannedOperationFormFields['indicators']
+>[number];
+
+const defaultOperationValue: PlannedOperationFormFields = {
+ sector: 101,
+};
+
+interface Props {
+ value: PlannedOperationFormFields;
+ error: ArrayError | undefined;
+ onChange: (
+ value: SetValueArg,
+ index: number
+ ) => void;
+ onRemove: (index: number) => void;
+ index: number;
+ disabled?: boolean;
+ operationTitle?: React.ReactNode;
+}
+
+function OperationsInput(props: Props) {
+ const {
+ error: errorFromProps,
+ onChange,
+ value,
+ index,
+ onRemove,
+ disabled,
+ operationTitle,
+ } = props;
+
+ const strings = useTranslation(i18n);
+ const onFieldChange = useFormObject(index, onChange, defaultOperationValue);
+
+ const error = value && value.sector && errorFromProps
+ ? getErrorObject(errorFromProps?.[value.sector])
+ : undefined;
+
+ const { setValue: onEarlyActionChange, removeValue: onEarlyActionRemove } = useFormArray<'early_action_activities', EarlyActionFormFields>(
+ 'early_action_activities' as const,
+ onFieldChange,
+ );
+ const {
+ setValue: onPrepositioningChange,
+ removeValue: onPrepositioningRemove,
+ } = useFormArray<'prepositioning_activities', PrepositioningFormFields>(
+ 'prepositioning_activities' as const,
+ onFieldChange,
+ );
+ const { setValue: onReadinessChange, removeValue: onReadinessRemove } = useFormArray<'readiness_activities', ReadinessFormFields>(
+ 'readiness_activities' as const,
+ onFieldChange,
+ );
+
+ const { setValue: onIndicatorChange, removeValue: onIndicatorRemove } = useFormArray<'indicators', IndicatorFormFields>(
+ 'indicators' as const,
+ onFieldChange,
+ );
+
+ const handleEarlyActionAddButtonClick = useCallback(() => {
+ const newActionItem: EarlyActionFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: EarlyActionFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newActionItem,
+ ],
+ 'early_action_activities' as const,
+ );
+ }, [onFieldChange]);
+
+ const handlePrepositioningAddButtonClick = useCallback(() => {
+ const newActionItem: PrepositioningFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: PrepositioningFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newActionItem,
+ ],
+ 'prepositioning_activities' as const,
+ );
+ }, [onFieldChange]);
+
+ const handleReadinessAddButtonClick = useCallback(() => {
+ const newActionItem: ReadinessFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: ReadinessFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newActionItem,
+ ],
+ 'readiness_activities' as const,
+ );
+ }, [onFieldChange]);
+
+ const handleIndicatorAddButtonClick = useCallback(() => {
+ const newIndicator: IndicatorFormFields = {
+ client_id: randomString(),
+ };
+
+ onFieldChange(
+ (oldValue: IndicatorFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newIndicator,
+ ],
+ 'indicators' as const,
+ );
+ }, [onFieldChange]);
+
+ return (
+
+
+
+ )}
+ withPadding
+ withBackground
+ initiallyExpanded
+ withHeaderBorder
+ // FIXME: add non field error and error indicator
+ >
+
+
+
+
+
+
+
+ }
+ >
+ {strings.addIndicatorsButtonLabel}
+
+ )}
+ empty={
+ isNotDefined(value.indicators) || value.indicators.length === 0
+ }
+ emptyMessage={strings.noIndicatorsMessage}
+ >
+
+ {value.indicators?.map((indicator, i) => (
+
+ ))}
+
+
+
+ {strings.selectionActionsReadinessActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.selectionActionsPlannedOperationAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={
+ isNotDefined(value.readiness_activities)
+ || value.readiness_activities.length === 0
+ }
+ emptyMessage={strings.selectionActionsNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.readiness_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+ {strings.selectionActionsPrepositioningActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.selectionActionsPlannedOperationAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={
+ isNotDefined(value.prepositioning_activities)
+ || value.prepositioning_activities.length === 0
+ }
+ emptyMessage={strings.selectionActionsNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.prepositioning_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+ {strings.selectionActionsEarlyActionActivities}
+
+ >
+ )}
+ headingLevel={5}
+ footerActions={(
+ }
+ >
+ {strings.selectionActionsPlannedOperationAddActivityButton}
+
+ )}
+ withCompactMessage
+ empty={
+ isNotDefined(value.early_action_activities)
+ || value.early_action_activities.length === 0
+ }
+ emptyMessage={strings.selectionActionsNoActivitiesMessage}
+ headerDescription={(
+
+ )}
+ >
+
+ {value?.early_action_activities?.map((activity, i) => (
+
+ ))}
+
+
+
+
+
+ );
+}
+
+export default OperationsInput;
diff --git a/app/src/views/EapFullForm/SelectionActions/i18n.json b/app/src/views/EapFullForm/SelectionActions/i18n.json
new file mode 100644
index 0000000000..9559759233
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/i18n.json
@@ -0,0 +1,48 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "selectionActionsHeading": "Selection of actions section",
+ "selectionActionsTooltipDescription": "It is crucial to select early actions that have the most potential to reduce the identified risks(s) and are feasible to implement given the lead time of the forecast. It is important to describe briefly: Who was involved? What data was consulted? Was research conducted? Were communities involved? For more guidance see FbF Manual, Chapter 4.2 Select Early Actions.",
+ "selectionProcessTitle": "Early action selection process",
+ "selectionProcessDescription1": "Add the list of early actions",
+ "selectionProcessDescription2": "Based on the prioritized impacts/risks of section 3, provide a brief rationale (e.g. your criteria) for the selection of action(s), also indicating which actions were considered but not chosen.",
+ "selectionProcessDescription3": "Describe the process used to select the actions: Who was consulted? Which assessments/research were carried out?",
+ "selectionProcessDescription4": "Does the FbF activation intend to use government social protection systems? Other State institutions’ databases and/or sources? Provide an explanation of potential number of target population to be selected.",
+ "selectionProcessDescription5": "If CVA is included, has a cash feasibility assessment been conducted (including needs and affected population preference, markets, financial service providers and National Society capacity assessments)?",
+ "selectionProcessExplanatoryNote": "It is crucial to select early actions that have the most potential to reduce the identified risks(s) and are feasible to implement given the lead time of the forecast. It is important to describe briefly: Who was involved? What data was consulted? Was research conducted? Were communities involved? For more guidance see FbF Manual, Chapter 4.2 Select Early Actions.",
+ "selectionProcessRequiredPoint1": "Based on the prioritized impacts/risks, provide a brief rationale (e.g. your criteria) for the selection of action(s), also indicating which actions were considered but not chosen (max. 1000 words)",
+ "selectionProcessRequiredPoint2": "Describe the process used to select the actions: Who was consulted? Which assessments/research were carried out? (max 1000 words)",
+ "selectionProcessRequiredPoint3": "Show how the selected action aims to reduce the expected humanitarian impact, by filling out the Theory of Change (ToC) table.",
+ "selectionProcessRequiredPoint4": "Does the activation intend to use government social protection systems? Other State institutions’ databases and/or sources? Provide an explanation of potential number of target population to be selected.",
+ "selectionProcessRequiredPoint5": "If CVA is included, has a cash feasibility assessment been conducted (including needs and affected population preference, markets, financial service providers and National Society capacity assessments)?",
+ "selectionActionDescriptionLabel": "Description",
+ "selectionActionExplanatoryNoteLabel": "Explanatory Note",
+ "selectionActionRequiredPointsLabel": "Required Points",
+ "earlyActionsOutputValue": "Early Actions",
+ "earlyActionsAddButtonLabel": "Add",
+ "selectionActionUploadLabel": "Upload",
+ "selectionActionUploadTableLabel": "Upload Table",
+ "evidenceBaseTitle": "Evidence Base",
+ "evidenceBaseDescription": "Explain how the selected actions will reduce the expected disaster impacts with a reference to academic research, empirical studies, interviews with key informants/experts, among other sources of evidence.",
+ "evidenceBaseExplanatoryNote": "It is important to provide evidence-based information showing that the early action(s) selected are likely to reduce the humanitarian impact of the event.",
+ "selectionActionPlannedOperationHeading": "IFRC Planned Operations",
+ "selectionActionPlannedOperationHeadingDescription": "Organize the actions according to the IFRC Plan and Budget, 2021 - 2025 sets out objectives for the IFRC Secretariat in support of National Societies and will guide the IFRC in the implementation Strategy 2030 and the Agenda for Renewal. These indicate the thematic areas in which the IFRC provides support to National Societies and where consolidated results are measured. Support on the IFRC programming and budgeting structure can be obtained from the IFRC focal point for Anticipation at country or regional level, regional disaster manager, Finance unit and/or Planning, Monitoring, Evaluation and Reporting (PMER) unit.",
+ "plannedOperationTitle": "Planned Operation",
+ "plannedOperationDescription": "Select sectors which are used in this Early Action Protocol.",
+ "enablingApproachesTitle": "Enabling Approaches",
+ "enablingApproachesDescription": "Select approaches which are used in this Early Action Protocol.",
+ "selectionAttachFilesTitle": "Attach relevant files",
+ "selectionAttachFilesDescription": "Attach any additional documentation, files, images, etc.",
+ "selectionSourceOfInformationTitle": "Sources of information",
+ "selectionSourceOfInformationDescription": "Add the description of the sources one at a time. If the source has a link, add in the second field.",
+ "selectionSourceOfInformationAddNewLabel": "Add New Source Information",
+ "feasibilityTitle": "Feasibility",
+ "feasibilityDescription": "Indicate how feasible it is to implement the proposed early actions in the planned timeframe. Has it been tested? Have similar actions been carried out by the NS in past operations and/or in as short a time with similar resources? If not, was a simulation conducted? If Cash and Voucher Assistance (CVA) is chosen as an early action, describe how necessary information for disbursement is collected in the short period of time and how national legislative requirements are met.",
+ "feasibilityExplanatoryNote": "In this section please describe why it is feasible to implement the selected actions, based on: time to implement the action, capacity of the National Society to implement, available resources (human, logistics, materials, etc.) and access considerations (see FbF Manual Chapter 4.2 Select Early Actions on criteria.)",
+ "feasibilityRequiredPoint1": "Indicate how feasible it is to implement the proposed early actions in the planned timeframe. Has it been tested? Have similar actions been carried out by the NS in past operations and/or in as short a time with similar resources? If not, was a simulation conducted?",
+ "feasibilityRequiredPoint2": "If Cash and Voucher Assistance (CVA) is chosen as an early action, describe how necessary information for disbursement is collected in the short period of time and how national legislative requirements are met.",
+ "useFullnessActionsTitle": "Usefulness of actions in case of non-occurring event",
+ "useFullnessActionsDescription": "Describe how your selected actions will contribute to the well-being of the population even if the expected event does not materialize. Include a description of the measures taken to ensure that the actions taken will be of maximum use for the targeted population in a future event.",
+ "useFullnessActionsExplanatoryNote": "In cases where the expected event does not materialize, the early actions implemented by the National Society (funded by the DREF) should still contribute to risk reduction and resiliency building."
+ }
+}
diff --git a/app/src/views/EapFullForm/SelectionActions/index.tsx b/app/src/views/EapFullForm/SelectionActions/index.tsx
new file mode 100644
index 0000000000..e53357c19f
--- /dev/null
+++ b/app/src/views/EapFullForm/SelectionActions/index.tsx
@@ -0,0 +1,546 @@
+import {
+ useCallback,
+ useMemo,
+} from 'react';
+import {
+ Button,
+ Checklist,
+ Container,
+ Heading,
+ InfoPopup,
+ InputSection,
+ ListView,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { stringValueSelector } from '@ifrc-go/ui/utils';
+import {
+ listToMap,
+ randomString,
+} from '@togglecorp/fujs';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+ useFormArray,
+} from '@togglecorp/toggle-form';
+
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import GoSingleFileInput from '#components/domain/GoSingleFileInput';
+import MultiImageWithCaptionInput from '#components/domain/MultiImageWithCaptionInput';
+import NonFieldError from '#components/NonFieldError';
+import TabPage from '#components/TabPage';
+import { type components } from '#generated/types';
+import useGlobalEnums from '#hooks/domain/useGlobalEnums';
+
+import EAPSourceInformationInput, { type SourceInformationFormFields } from '../EAPSourceInformationInput';
+import { type PartialEapFullFormType } from '../schema';
+import ApproachesInput from './ApproachesInput';
+import EarlyActionsInput from './EarlyActionsInput';
+import OperationsInput from './OperationInput';
+
+import i18n from './i18n.json';
+
+type EapSector = components['schemas']['EapSectorEnumKey'];
+type EapSectorOption = components['schemas']['EapSectorEnum'];
+
+type EapApproach = components['schemas']['EapApproachEnumKey'];
+type EapApproachOption = components['schemas']['EapApproachEnum'];
+
+type EnablingApproachesFormFields = NonNullable<
+ PartialEapFullFormType['enable_approaches']
+>[number];
+
+type PlannedOperationFormFields = NonNullable<
+ PartialEapFullFormType['planned_operations']
+>[number];
+
+type EarlyActionsFormFields = NonNullable<
+ PartialEapFullFormType['early_actions']
+>[number];
+
+function sectorKeySelector(option: EapSectorOption) {
+ return option.key;
+}
+
+function approachesKeySelector(option: EapApproachOption) {
+ return option.key;
+}
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+}
+
+function SelectionActions(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ } = props;
+
+ const error = getErrorObject(formError);
+ const strings = useTranslation(i18n);
+ const { eap_sector: eapSectorOptions, eap_approach: eapApproachOptions } = useGlobalEnums();
+
+ const eapSectorLabelMapping = useMemo(
+ () => listToMap(
+ eapSectorOptions,
+ ({ key }) => key,
+ ({ value: label }) => label,
+ ),
+ [eapSectorOptions],
+ );
+
+ const { setValue: onOperationChange, removeValue: onOperationRemove } = useFormArray<'planned_operations', PlannedOperationFormFields>(
+ 'planned_operations',
+ setFieldValue,
+ );
+
+ const handleOperationChecklistChange = useCallback(
+ (sectors: EapSector[] | undefined) => {
+ setFieldValue(
+ (previousValue: PlannedOperationFormFields[] | undefined) => {
+ const previousValueMapping = listToMap(
+ previousValue,
+ ({ sector }) => sector,
+ );
+
+ return sectors?.map((sector) => {
+ const prevSectorValue = previousValueMapping?.[sector];
+
+ if (prevSectorValue) {
+ return prevSectorValue;
+ }
+
+ return {
+ sector,
+ } satisfies PlannedOperationFormFields;
+ });
+ },
+ 'planned_operations',
+ );
+ },
+ [setFieldValue],
+ );
+
+ const selectedSectors = value?.planned_operations?.map(
+ ({ sector }) => sector,
+ );
+
+ const eapApproachLabelMapping = useMemo(
+ () => listToMap(
+ eapApproachOptions,
+ ({ key }) => key,
+ ({ value: label }) => label,
+ ),
+ [eapApproachOptions],
+ );
+
+ const { setValue: onApproachChange, removeValue: onApproachRemove } = useFormArray<'enable_approaches', EnablingApproachesFormFields>(
+ 'enable_approaches',
+ setFieldValue,
+ );
+
+ const handleApproachChecklistChange = useCallback(
+ (approaches: EapApproach[] | undefined) => {
+ setFieldValue(
+ (previousValue: EnablingApproachesFormFields[] | undefined) => {
+ const previousValueMapping = listToMap(
+ previousValue,
+ ({ approach }) => approach,
+ );
+
+ return approaches?.map((approach) => {
+ const prevApproachValue = previousValueMapping?.[approach];
+
+ if (prevApproachValue) {
+ return prevApproachValue;
+ }
+
+ return {
+ approach,
+ } satisfies EnablingApproachesFormFields;
+ });
+ },
+ 'enable_approaches',
+ );
+ },
+ [setFieldValue],
+ );
+
+ const selectedApproaches = value?.enable_approaches?.map(
+ ({ approach }) => approach,
+ );
+
+ const {
+ setValue: onSourceInformationChange,
+ removeValue: onSourceInformationRemove,
+ } = useFormArray<
+ 'evidence_base_source_of_information',
+ SourceInformationFormFields
+ >('evidence_base_source_of_information', setFieldValue);
+
+ const handleSourceInformationAdd = useCallback(() => {
+ const newSourceInformationItem: SourceInformationFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: SourceInformationFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newSourceInformationItem,
+ ],
+ 'evidence_base_source_of_information' as const,
+ );
+ }, [setFieldValue]);
+
+ const { setValue: onEarlyActionsChange, removeValue: onEarlyActionsRemove } = useFormArray<'early_actions', EarlyActionsFormFields>(
+ 'early_actions',
+ setFieldValue,
+ );
+
+ const handleEarlyActionsAdd = useCallback(() => {
+ const newEarlyActionsItem: EarlyActionsFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: EarlyActionsFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newEarlyActionsItem,
+ ],
+ 'early_actions' as const,
+ );
+ }, [setFieldValue]);
+
+ return (
+
+
+
+ {strings.selectionActionsHeading}
+
+
+
+
+
+
+
+ )}
+ />
+
+ )}
+ withAsteriskOnTitle
+ >
+
+
+
+
+
+ );
+}
+
+export default SelectionActions;
diff --git a/app/src/views/EapFullForm/TriggerModel/i18n.json b/app/src/views/EapFullForm/TriggerModel/i18n.json
new file mode 100644
index 0000000000..14515b7366
--- /dev/null
+++ b/app/src/views/EapFullForm/TriggerModel/i18n.json
@@ -0,0 +1,52 @@
+{
+ "namespace": "eapFullForm",
+ "strings": {
+ "triggerModelHeading": "Trigger Model",
+ "triggerModelTooltipDescription": "The work for the identification of triggers can be very technical and require expert resources. For this process, the National Society can get help from technical experts, Hydro-met services or specialist institutions. The chapter 4.1 Set the Trigger in the FbF Manual can be used for guidance.",
+ "triggerExplanatoryNoteLabel": "Explanatory Note",
+ "triggerRequiredPointsLabel": "Required Points",
+ "triggerStatementTitle": "Trigger Statement",
+ "triggerStatementDescription": "State in one sentence what exactly the trigger of your EAP will be, for example: When [source] issues a forecast of at least [probability of magnitude of event or impact], then we will act. We expect the lead-time to be [xxx].",
+ "triggerStatementExplanatoryNote": "The work for the identification of triggers can be very technical and require expert resources. For this process, the National Society can get help from technical experts, Hydro-met services or specialist institutions. The chapter 4.1 Set the Trigger in the FbF Manual can be used for guidance.",
+ "triggerModelDescriptionLabel": "Description",
+ "triggerLeadTimeTitle": "Lead Time",
+ "sourcesForecastTitle": "Sources of forecast",
+ "addNewSourcesForecastLabel": "Add New Source of Forecast",
+ "sourcesForecastDescription": "Add respective source(s) for the forecast and the link to the website, if applicable.",
+ "forecastExplanatoryNote": "In order for the DREF to approve funding when a trigger occurs, there must be a certain probability the extreme event will take place. To safeguard this, it is crucial to select those forecasts that have a certain “skill” level (certain level of confidence). If observations are used, these can also be included in the table. Note that this information does not need to be calculated by the National Society but can be obtained by working with hydro-meteorological services, research institutions, experts etc.",
+ "forecastSelectionTitle": "Forecast selection",
+ "forecastTableLabel": "Forecast Table",
+ "forecastRequiredPoint1": "State clearly which forecast(s) and observations will be used and why they were chosen.",
+ "forecastRequiredPoint2": "Include a table with all available forecasts for your hazard. The table must include: Name of forecast, Lead time, Source, False Alarm Ratio, Number of times the forecast has been issued for this hazard in the last 10 years ",
+ "forecastSelectionDescription": "State clearly which forecast(s) and observations will be used and why they were chosen. Include a table with all available forecasts for your hazard. The table must include: Name of forecast, Lead time, Source, False Alarm Ratio, Number of times the forecast has been issued for this hazard in the last 10 years.",
+ "definitionJustificationTitle": "Definition and justification of impact level",
+ "definitionJustificationDescription1": "Why did you select a certain magnitude of event?",
+ "definitionJustificationDescription2": "Explain how your impact level was defined.",
+ "definitionJustificationDescription3": "Explain how much impact can be expected based on the strength of the event.",
+ "definitionJustificationDescription4": "Indicate to which return period the selected impact-level corresponds (minimum: 1-in-5 years.)",
+ "definitionJustificationDescription5": "Explain how the return period was calculated",
+ "definitionJustificationExplanatoryNote": "The DREF provides funding for early action for events of a strength that has caused significant humanitarian impact in the past. Explain how a certain magnitude was selected and how the impact level was defined (see guidance in the FbF manual chapter 4.1 Set the Trigger (particularly Steps 6-8)). Define the relationship between impact (utilizing the prioritized impact/s section 3.3) and hazard magnitude to establish which impact can be expected given specific hazard magnitudes.",
+ "definitionJustificationRequiredPoint1": "Why did you select a certain magnitude of event?",
+ "definitionJustificationRequiredPoint2": "Explain how your impact level was defined. Explain how much impact can be expected based on the strength of the event.",
+ "definitionJustificationRequiredPoint3": "Indicate to which return period the selected impact-level corresponds (minimum: 1-in-5 years.)",
+ "definitionJustificationRequiredPoint4": "Explain how the return period was calculated",
+ "identificationInterventionTitle": "Identification of the intervention area",
+ "identificationInterventionDescription1": "Building on the analysis in Prioritised impact (in the previous section), list the vulnerability and exposure indicators/maps that will be used to identify which are the areas likely to be most impacted. Indicate data source and administrative level for each indicator, as well as state how you will update the data.",
+ "identificationInterventionDescription2": "Describe how you will combine the forecast maps with vulnerability/exposure indicators.",
+ "identificationInterventionDescription3": "Provide an example using a past event (it could be using a sample intervention map).",
+ "identificationInterventionExplanatoryNote": "When an impact level is reached, vulnerability and exposure information is combined with the real-time forecast to identify which areas are likely to be most impacted. In the most advanced form, the forecast would be digitally combined with vulnerability and exposure information, to show which areas are predicted to be most severely impacted. This will provide a map-based tool or a list of prioritized districts villages, municipalities or other geographical areas where the early actions will be activated. Where no digital system is available, the combination of forecast and vulnerability/exposure indicators could also be done manually, e.g. if flooding is forecasted for a certain area, the most vulnerable and exposed communities in that area are selected (for example the poorest if that indicator is used). If different weighted indicators are used to calculate a vulnerability index, check on the index which of the communities in the area for which the event is forecasted scores highest. Ultimately the objective is to know which areas are likely to be impacted and how you will determine which will be targeted.",
+ "identificationInterventionRequiredPoint1": "Building on the analysis in 3.3. list the vulnerability and exposure indicators/maps that will be used to identify which are the areas likely to be most impacted. Indicate data source and administrative level for each indicator, as well as state how you will update the data.",
+ "identificationInterventionRequiredPoint2": "Describe how you will combine the forecast maps with vulnerability/exposure indicators.",
+ "identificationInterventionRequiredPoint3": "Provide an example using past event (it could be using a sample intervention map).",
+ "attachRelevantFilesTitle": "Attach relevant files",
+ "attachRelevantFilesDescription": "Attach any additional maps, documentation, files, images, etc.",
+ "attachRelevantFilesUploadLabel": "Upload",
+ "triggerUploadTableLabel": "Upload Table",
+ "triggerSelectImagesLabel": "Select Images",
+ "sourceInformationTitle": "Sources of Information",
+ "selectRegionTitle": "Select region on a map",
+ "selectRegionDescription": "Select the respective regions on a map by clicking the link to the right",
+ "sourceInformationDescription": "Add the description of the sources one at a time. If the source has a link, add in the second field.",
+ "addNewSourceInformationLabel": "Add New Source of Information"
+ }
+}
diff --git a/app/src/views/EapFullForm/TriggerModel/index.tsx b/app/src/views/EapFullForm/TriggerModel/index.tsx
new file mode 100644
index 0000000000..804d5fdf5e
--- /dev/null
+++ b/app/src/views/EapFullForm/TriggerModel/index.tsx
@@ -0,0 +1,415 @@
+import { useCallback } from 'react';
+import {
+ Button,
+ Heading,
+ InfoPopup,
+ InputSection,
+ ListView,
+ NumberInput,
+ TextArea,
+ TextOutput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ isDefined,
+ randomString,
+} from '@togglecorp/fujs';
+import {
+ type EntriesAsList,
+ type Error,
+ getErrorObject,
+ getErrorString,
+ useFormArray,
+} from '@togglecorp/toggle-form';
+
+import Admin2Input from '#components/domain/Admin2Input';
+import GoMultiFileInput from '#components/domain/GoMultiFileInput';
+import GoSingleFileInput from '#components/domain/GoSingleFileInput';
+import MultiImageWithCaptionInput from '#components/domain/MultiImageWithCaptionInput';
+import NonFieldError from '#components/NonFieldError';
+import TabPage from '#components/TabPage';
+import { type GoApiResponse } from '#utils/restRequest';
+
+import EAPSourceInformationInput, { type SourceInformationFormFields } from '../EAPSourceInformationInput';
+import { type PartialEapFullFormType } from '../schema';
+
+import i18n from './i18n.json';
+
+interface Props {
+ value: PartialEapFullFormType;
+ setFieldValue: (...entries: EntriesAsList) => void;
+ error: Error | undefined;
+ disabled?: boolean;
+ fileIdToUrlMap: Record;
+ setFileIdToUrlMap?: React.Dispatch<
+ React.SetStateAction>
+ >;
+ eapRegistrationDetail?: GoApiResponse<'/api/v2/eap-registration/{id}/'>;
+}
+
+function TriggerModel(props: Props) {
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ disabled,
+ fileIdToUrlMap,
+ setFileIdToUrlMap,
+ eapRegistrationDetail,
+ } = props;
+
+ const error = getErrorObject(formError);
+ const strings = useTranslation(i18n);
+
+ const {
+ setValue: onSourcesForecastChange,
+ removeValue: onSourcesForecastRemove,
+ } = useFormArray<
+ 'trigger_statement_source_of_information',
+ SourceInformationFormFields
+ >('trigger_statement_source_of_information', setFieldValue);
+
+ const handleSourcesForecastAdd = useCallback(() => {
+ const newSourceInformationItem: SourceInformationFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: SourceInformationFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newSourceInformationItem,
+ ],
+ 'trigger_statement_source_of_information' as const,
+ );
+ }, [setFieldValue]);
+
+ const {
+ setValue: onSourceInformationChange,
+ removeValue: onSourceInformationRemove,
+ } = useFormArray<
+ 'trigger_model_source_of_information',
+ SourceInformationFormFields
+ >('trigger_model_source_of_information', setFieldValue);
+
+ const handleSourceInformationAdd = useCallback(() => {
+ const newSourceInformationItem: SourceInformationFormFields = {
+ client_id: randomString(),
+ };
+
+ setFieldValue(
+ (oldValue: SourceInformationFormFields[] | undefined) => [
+ ...(oldValue ?? []),
+ newSourceInformationItem,
+ ],
+ 'trigger_model_source_of_information' as const,
+ );
+ }, [setFieldValue]);
+
+ return (
+
+
+
+ {strings.triggerModelHeading}
+
+
+
+ )}
+ description={strings.triggerStatementDescription}
+ withAsteriskOnTitle
+ >
+
+
+
+
+
+
+
+ {value?.trigger_statement_source_of_information?.map(
+ (source, index) => (
+
+ ),
+ )}
+
+
+
+
+
+