From 02dd537e2a4e943dcfa437e1680b8fe06365e10d Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Mon, 13 Oct 2025 11:42:11 +0545
Subject: [PATCH 01/15] global(add-global-page): Add a global page
---
app/src/App/routes/index.tsx | 30 +++++++++
app/src/components/Navbar/i18n.json | 1 +
app/src/views/EapRegistration/i18n.json | 7 ++
app/src/views/EapRegistration/index.tsx | 21 ++++++
app/src/views/EarlyActionProtocols/i18n.json | 17 +++++
app/src/views/EarlyActionProtocols/index.tsx | 66 +++++++++++++++++++
.../EarlyActionProtocols/styles.module.css | 5 ++
go-api | 2 +-
8 files changed, 148 insertions(+), 1 deletion(-)
create mode 100644 app/src/views/EapRegistration/i18n.json
create mode 100644 app/src/views/EapRegistration/index.tsx
create mode 100644 app/src/views/EarlyActionProtocols/i18n.json
create mode 100644 app/src/views/EarlyActionProtocols/index.tsx
create mode 100644 app/src/views/EarlyActionProtocols/styles.module.css
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index b25ad826a..76a6bb6cc 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -701,6 +701,19 @@ const accountMyFormsDref = customWrapRoute({
},
});
+const earlyActionProtocols = customWrapRoute({
+ parent: rootLayout,
+ path: 'eap',
+ component: {
+ render: () => import('#views/EarlyActionProtocols'),
+ props: {},
+ },
+ context: {
+ title: 'Early Action Protocols',
+ visibility: 'anything',
+ },
+});
+
const accountMyFormsThreeW = customWrapRoute({
parent: accountMyFormsLayout,
path: 'three-w',
@@ -1146,6 +1159,21 @@ const newPerOverviewForm = customWrapRoute({
},
});
+const eapDevelopmentRegistration = customWrapRoute({
+ parent: rootLayout,
+ path: 'eap-registration/new',
+ component: {
+ render: () => import('#views/EapRegistration'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'EAP Development Registration',
+ visibility: 'is-authenticated',
+ permissions: ({ isGuestUser }) => !isGuestUser,
+ },
+});
+
const perOverviewForm = customWrapRoute({
parent: perProcessLayout,
path: ':perId/overview',
@@ -1353,6 +1381,7 @@ const wrappedRoutes = {
termsAndConditions,
operationalLearning,
montandonLandingPage,
+ eapDevelopmentRegistration,
...regionRoutes,
...countryRoutes,
...surgeRoutes,
@@ -1363,6 +1392,7 @@ const wrappedRoutes = {
// Redirects
preparednessOperationalLearning,
obsoleteFieldReportDetails,
+ earlyActionProtocols,
};
export const unwrappedRoutes = unwrapRoute(Object.values(wrappedRoutes));
diff --git a/app/src/components/Navbar/i18n.json b/app/src/components/Navbar/i18n.json
index 0132def3c..e0ed399ed 100644
--- a/app/src/components/Navbar/i18n.json
+++ b/app/src/components/Navbar/i18n.json
@@ -40,6 +40,7 @@
"userMenuDrefProcessDescription":"Disaster Response Emergency Fund (DREF) is the quickest way of getting funding directly to local humanitarian actors. Use one of the links below to submit a DREF Application or an update.",
"userMenuCreateDrefApplication":"Create DREF Application",
"myDrefApplications": "My DREF Applications",
+ "earlyActionProtocols": "Early Action Protocols (EAP)",
"userMenuSurge":"The section displays the summary of deployments within current and ongoing emergencies. Login to see available details",
"userMenuSurgeGlobalOverview":"Surge Global Overview",
"userMenuOperationalToolbox":"Operational Toolbox",
diff --git a/app/src/views/EapRegistration/i18n.json b/app/src/views/EapRegistration/i18n.json
new file mode 100644
index 000000000..9b7a06dd0
--- /dev/null
+++ b/app/src/views/EapRegistration/i18n.json
@@ -0,0 +1,7 @@
+{
+ "namespace": "eapRegistration",
+ "strings": {
+ "eapRegistrationHeading": "EAP Development Registration",
+ "eapRegistrationDescription": "The purpose of this form is for you to notify the IFRC team of the start of your EAP process. If you need assistance with the initiation of the process, send us a message."
+ }
+}
diff --git a/app/src/views/EapRegistration/index.tsx b/app/src/views/EapRegistration/index.tsx
new file mode 100644
index 000000000..31698b3c5
--- /dev/null
+++ b/app/src/views/EapRegistration/index.tsx
@@ -0,0 +1,21 @@
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+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 (
+
+ {/* TODO: Add the form */}
+ Application Details
+
+ );
+}
diff --git a/app/src/views/EarlyActionProtocols/i18n.json b/app/src/views/EarlyActionProtocols/i18n.json
new file mode 100644
index 000000000..93b0362f8
--- /dev/null
+++ b/app/src/views/EarlyActionProtocols/i18n.json
@@ -0,0 +1,17 @@
+{
+ "namespace": "earlyActionProtocols",
+ "strings": {
+ "eapHeading": "Disaster Response Emergency Fund (DREF)",
+ "eapDescription": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action.",
+ "eapTitle": "Early Action Protocols (EAP)",
+ "eapRegistrationLink": "EAP in Progress? Let Us Know",
+ "eapContent": "What is an EAP?",
+ "eapContentHeading": "Early Action Protocols (EAPs) are a core mechanism of the IFRC's Forecast-based Financing (FbF) approach, designed to ensure that humanitarian action happens before a disaster strikes, rather than only responding afterwards.",
+ "eapContentSubHeadingOne": "An EAP is a pre-agreed plan developed by a Nation Society together with partners, which outlines:",
+ "eapDescriptionOne": "The triggers (based on scientific forecasts and risk analysis) that indicate when a hazard is likely to impact communities.",
+ "eapDescriptionTwo": "The early actions to be implemented once those triggers are met - practical, life-saving measures that reduce the impacts of the forecasted disaster.",
+ "eapDescriptionThree": "The roles, responsibilities, and budget required to carry out these actions quickly and effectively.",
+ "eapContentSubHeadingTwo": "Why are the EAPs Important?",
+ "eapContentSubHeadingThree": "What is the EAP Application Process?"
+ }
+}
diff --git a/app/src/views/EarlyActionProtocols/index.tsx b/app/src/views/EarlyActionProtocols/index.tsx
new file mode 100644
index 000000000..7688ff66a
--- /dev/null
+++ b/app/src/views/EarlyActionProtocols/index.tsx
@@ -0,0 +1,66 @@
+import {
+ Container,
+ ExpandableContainer,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+import Link from '#components/Link';
+import Page from '#components/Page';
+
+import i18n from './i18n.json';
+import styles from './styles.module.css';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ const strings = useTranslation(i18n);
+
+ return (
+
+
+ {strings.eapRegistrationLink}
+
+ )}
+ childrenContainerClassName={styles.earlyActionProtocols}
+ >
+
+
+ {strings.eapContentHeading}
+
+
+ {strings.eapContentSubHeadingOne}
+
+ -
+ {strings.eapDescriptionOne}
+
+ -
+ {strings.eapDescriptionTwo}
+
+ -
+ {strings.eapDescriptionThree}
+
+
+
+
+ {/* TODO: Add remaining content */}
+
+
+
+
+ );
+}
diff --git a/app/src/views/EarlyActionProtocols/styles.module.css b/app/src/views/EarlyActionProtocols/styles.module.css
new file mode 100644
index 000000000..8ec3f610f
--- /dev/null
+++ b/app/src/views/EarlyActionProtocols/styles.module.css
@@ -0,0 +1,5 @@
+.early-action-protocols {
+ display: flex;
+ flex-direction: column;
+ gap: var(--go-ui-spacing-lg);
+}
diff --git a/go-api b/go-api
index fb6d466e4..83be9dfcf 160000
--- a/go-api
+++ b/go-api
@@ -1 +1 @@
-Subproject commit fb6d466e42b2c46f25b908cc78878c74311400f8
+Subproject commit 83be9dfcfc5a1dfc63a8496171db755a4c51787b
From 916cd73153ecd074a782535a2138b2af9a8ba850 Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Tue, 14 Oct 2025 13:29:53 +0545
Subject: [PATCH 02/15] eap(add-eap-link): Add EAP Tab in account page
---
app/src/App/routes/index.tsx | 47 +++++++++++++++++++
app/src/views/AccountMyFormsLayout/i18n.json | 3 +-
app/src/views/AccountMyFormsLayout/index.tsx | 5 ++
app/src/views/EapApplications/i18n.json | 8 ++++
app/src/views/EapApplications/index.tsx | 39 +++++++++++++++
.../views/EapApplications/styles.module.css | 6 +++
app/src/views/EapFullForm/index.tsx | 12 +++++
app/src/views/SimplifiedEapForm/index.tsx | 12 +++++
8 files changed, 131 insertions(+), 1 deletion(-)
create mode 100644 app/src/views/EapApplications/i18n.json
create mode 100644 app/src/views/EapApplications/index.tsx
create mode 100644 app/src/views/EapApplications/styles.module.css
create mode 100644 app/src/views/EapFullForm/index.tsx
create mode 100644 app/src/views/SimplifiedEapForm/index.tsx
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index 76a6bb6cc..593597780 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -728,6 +728,50 @@ const accountMyFormsThreeW = customWrapRoute({
},
});
+const accountMyFormsEap = customWrapRoute({
+ parent: accountMyFormsLayout,
+ path: 'eap-applications',
+ component: {
+ render: () => import('#views/EapApplications'),
+ props: {},
+ },
+ context: {
+ title: 'Account - EAP Applications',
+ visibility: 'is-authenticated',
+ permissions: ({ isGuestUser }) => !isGuestUser,
+ },
+});
+
+const eapFullForm = customWrapRoute({
+ parent: rootLayout,
+ path: 'eap-full-form',
+ component: {
+ render: () => import('#views/EapFullForm'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'EAP Full Forms',
+ visibility: 'is-authenticated',
+ permissions: ({ isGuestUser }) => !isGuestUser,
+ },
+});
+
+const simplifiedEapForm = customWrapRoute({
+ parent: rootLayout,
+ path: 'simplified-eap-form',
+ component: {
+ render: () => import('#views/SimplifiedEapForm'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'Simplified EAP Forms',
+ visibility: 'is-authenticated',
+ permissions: ({ isGuestUser }) => !isGuestUser,
+ },
+});
+
const accountNotifications = customWrapRoute({
parent: accountLayout,
path: 'notifications',
@@ -1345,6 +1389,7 @@ const wrappedRoutes = {
accountMyFormsPer,
accountMyFormsDref,
accountMyFormsThreeW,
+ accountMyFormsEap,
resources,
search,
allThreeWProject,
@@ -1382,6 +1427,8 @@ const wrappedRoutes = {
operationalLearning,
montandonLandingPage,
eapDevelopmentRegistration,
+ eapFullForm,
+ simplifiedEapForm,
...regionRoutes,
...countryRoutes,
...surgeRoutes,
diff --git a/app/src/views/AccountMyFormsLayout/i18n.json b/app/src/views/AccountMyFormsLayout/i18n.json
index 6b70856db..c23cf7ce5 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 5364a3844..c7eaac05d 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/EapApplications/i18n.json b/app/src/views/EapApplications/i18n.json
new file mode 100644
index 000000000..a48b9dee3
--- /dev/null
+++ b/app/src/views/EapApplications/i18n.json
@@ -0,0 +1,8 @@
+{
+ "namespace": "eapApplication",
+ "strings": {
+ "eapRegistrationLink": "EAP In Process? Let Us Know",
+ "eapFormLink": "Start Full EAP",
+ "simplifiedEapLink": "Start sEAP"
+ }
+}
diff --git a/app/src/views/EapApplications/index.tsx b/app/src/views/EapApplications/index.tsx
new file mode 100644
index 000000000..dd9f788b5
--- /dev/null
+++ b/app/src/views/EapApplications/index.tsx
@@ -0,0 +1,39 @@
+import { Container } from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+import Link from '#components/Link';
+
+import i18n from './i18n.json';
+import styles from './styles.module.css';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ const strings = useTranslation(i18n);
+
+ return (
+
+ {/* FIXME: Add eap registration link */}
+
+ {strings.eapRegistrationLink}
+
+
+ {strings.eapFormLink}
+
+
+ {strings.simplifiedEapLink}
+
+
+ );
+}
diff --git a/app/src/views/EapApplications/styles.module.css b/app/src/views/EapApplications/styles.module.css
new file mode 100644
index 000000000..c111ea1e6
--- /dev/null
+++ b/app/src/views/EapApplications/styles.module.css
@@ -0,0 +1,6 @@
+.eap-form-links {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--go-ui-spacing-sm);
+}
\ No newline at end of file
diff --git a/app/src/views/EapFullForm/index.tsx b/app/src/views/EapFullForm/index.tsx
new file mode 100644
index 000000000..e6d0317fe
--- /dev/null
+++ b/app/src/views/EapFullForm/index.tsx
@@ -0,0 +1,12 @@
+import Page from '#components/Page';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ return (
+
+ {/* TODO: Add EAP form */}
+ Full EAP Form
+
+ );
+}
diff --git a/app/src/views/SimplifiedEapForm/index.tsx b/app/src/views/SimplifiedEapForm/index.tsx
new file mode 100644
index 000000000..57bcf2b6c
--- /dev/null
+++ b/app/src/views/SimplifiedEapForm/index.tsx
@@ -0,0 +1,12 @@
+import Page from '#components/Page';
+
+/** @knipignore */
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ return (
+
+ {/* TODO: Add Simplified EAP form */}
+ Simplified EAP form
+
+ );
+}
From 9a765b7a423796cf840290d4c1347927a20843fd Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Mon, 27 Oct 2025 11:01:56 +0545
Subject: [PATCH 03/15] eap(eap-translation): Add EAP translations
---
.../000053-1761542116137.json | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 translationMigrations/000053-1761542116137.json
diff --git a/translationMigrations/000053-1761542116137.json b/translationMigrations/000053-1761542116137.json
new file mode 100644
index 000000000..e18c829ed
--- /dev/null
+++ b/translationMigrations/000053-1761542116137.json
@@ -0,0 +1,119 @@
+{
+ "parent": "000052-1758547474974.json",
+ "actions": [
+ {
+ "action": "add",
+ "key": "eapApplications",
+ "namespace": "accountMyFormsLayout",
+ "value": "EAP Applications"
+ },
+ {
+ "action": "add",
+ "key": "earlyActionProtocols",
+ "namespace": "common",
+ "value": "Early Action Protocols (EAP)"
+ },
+ {
+ "action": "add",
+ "key": "eapFormLink",
+ "namespace": "eapApplication",
+ "value": "Start Full EAP"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationLink",
+ "namespace": "eapApplication",
+ "value": "EAP In Process? Let Us Know"
+ },
+ {
+ "action": "add",
+ "key": "simplifiedEapLink",
+ "namespace": "eapApplication",
+ "value": "Start sEAP"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationDescription",
+ "namespace": "eapRegistration",
+ "value": "The purpose of this form is for you to notify the IFRC team of the start of your EAP process. If you need assistance with the initiation of the process, send us a message."
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationHeading",
+ "namespace": "eapRegistration",
+ "value": "EAP Development Registration"
+ },
+ {
+ "action": "add",
+ "key": "eapContent",
+ "namespace": "earlyActionProtocols",
+ "value": "What is an EAP?"
+ },
+ {
+ "action": "add",
+ "key": "eapContentHeading",
+ "namespace": "earlyActionProtocols",
+ "value": "Early Action Protocols (EAPs) are a core mechanism of the IFRC's Forecast-based Financing (FbF) approach, designed to ensure that humanitarian action happens before a disaster strikes, rather than only responding afterwards."
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingOne",
+ "namespace": "earlyActionProtocols",
+ "value": "An EAP is a pre-agreed plan developed by a Nation Society together with partners, which outlines:"
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingThree",
+ "namespace": "earlyActionProtocols",
+ "value": "What is the EAP Application Process?"
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingTwo",
+ "namespace": "earlyActionProtocols",
+ "value": "Why are the EAPs Important?"
+ },
+ {
+ "action": "add",
+ "key": "eapDescription",
+ "namespace": "earlyActionProtocols",
+ "value": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action."
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionOne",
+ "namespace": "earlyActionProtocols",
+ "value": "The triggers (based on scientific forecasts and risk analysis) that indicate when a hazard is likely to impact communities."
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionThree",
+ "namespace": "earlyActionProtocols",
+ "value": "The roles, responsibilities, and budget required to carry out these actions quickly and effectively."
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionTwo",
+ "namespace": "earlyActionProtocols",
+ "value": "The early actions to be implemented once those triggers are met - practical, life-saving measures that reduce the impacts of the forecasted disaster."
+ },
+ {
+ "action": "add",
+ "key": "eapHeading",
+ "namespace": "earlyActionProtocols",
+ "value": "Disaster Response Emergency Fund (DREF)"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationLink",
+ "namespace": "earlyActionProtocols",
+ "value": "EAP in Progress? Let Us Know"
+ },
+ {
+ "action": "add",
+ "key": "eapTitle",
+ "namespace": "earlyActionProtocols",
+ "value": "Early Action Protocols (EAP)"
+ }
+ ]
+}
\ No newline at end of file
From 39f97201874f72db341ed3815f485363ae85838a Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Wed, 5 Nov 2025 11:34:02 +0545
Subject: [PATCH 04/15] dref-process(tabs): Add tabs in dref process link
---
app/src/App/routes/index.tsx | 61 ++++++++++---
app/src/components/Navbar/index.tsx | 10 ++-
app/src/views/DrefDetail/i18n.json | 15 ++++
app/src/views/DrefDetail/index.tsx | 56 ++++++++++++
app/src/views/DrefDetail/styles.module.css | 11 +++
app/src/views/DrefProcess/i18n.json | 9 ++
app/src/views/DrefProcess/index.tsx | 37 ++++++++
app/src/views/EapApplications/i18n.json | 2 +-
app/src/views/EarlyActionProtocols/i18n.json | 5 +-
app/src/views/EarlyActionProtocols/index.tsx | 87 +++++++++----------
.../EarlyActionProtocols/styles.module.css | 10 ++-
11 files changed, 236 insertions(+), 67 deletions(-)
create mode 100644 app/src/views/DrefDetail/i18n.json
create mode 100644 app/src/views/DrefDetail/index.tsx
create mode 100644 app/src/views/DrefDetail/styles.module.css
create mode 100644 app/src/views/DrefProcess/i18n.json
create mode 100644 app/src/views/DrefProcess/index.tsx
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index 593597780..3c4c91523 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -319,6 +319,50 @@ const emergencyAdditionalInfo = customWrapRoute({
},
});
+type DefaultDrefDetailChild = 'dref-detail';
+const drefProcessLayout = customWrapRoute({
+ parent: rootLayout,
+ path: 'dref-process',
+ forwardPath: 'dref-detail' satisfies DefaultDrefDetailChild,
+ component: {
+ render: () => import('#views/DrefProcess'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'DREF Process',
+ visibility: 'anything',
+ },
+});
+
+const drefDetail = customWrapRoute({
+ parent: drefProcessLayout,
+ path: 'dref-detail' satisfies DefaultDrefDetailChild,
+ component: {
+ render: () => import('#views/DrefDetail'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'Response and Imminent DREF',
+ visibility: 'anything',
+ },
+});
+
+const eapDetail = customWrapRoute({
+ parent: drefProcessLayout,
+ path: 'eap-detail',
+ component: {
+ render: () => import('#views/EarlyActionProtocols'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'Early Action Protocols',
+ visibility: 'anything',
+ },
+});
+
type DefaultPreparednessChild = 'global-summary';
const preparednessLayout = customWrapRoute({
parent: rootLayout,
@@ -701,19 +745,6 @@ const accountMyFormsDref = customWrapRoute({
},
});
-const earlyActionProtocols = customWrapRoute({
- parent: rootLayout,
- path: 'eap',
- component: {
- render: () => import('#views/EarlyActionProtocols'),
- props: {},
- },
- context: {
- title: 'Early Action Protocols',
- visibility: 'anything',
- },
-});
-
const accountMyFormsThreeW = customWrapRoute({
parent: accountMyFormsLayout,
path: 'three-w',
@@ -1439,7 +1470,9 @@ const wrappedRoutes = {
// Redirects
preparednessOperationalLearning,
obsoleteFieldReportDetails,
- earlyActionProtocols,
+ drefDetail,
+ eapDetail,
+ drefProcessLayout,
};
export const unwrappedRoutes = unwrapRoute(Object.values(wrappedRoutes));
diff --git a/app/src/components/Navbar/index.tsx b/app/src/components/Navbar/index.tsx
index 1e6a86e6d..02e05cd38 100644
--- a/app/src/components/Navbar/index.tsx
+++ b/app/src/components/Navbar/index.tsx
@@ -368,12 +368,20 @@ function Navbar(props: Props) {
{strings.myDrefApplications}
+
+ {strings.earlyActionProtocols}
+
+
+ {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/DrefDetail/styles.module.css b/app/src/views/DrefDetail/styles.module.css
new file mode 100644
index 000000000..c850c0ee2
--- /dev/null
+++ b/app/src/views/DrefDetail/styles.module.css
@@ -0,0 +1,11 @@
+.dref-detail {
+ display: flex;
+ flex-direction: column;
+ padding: var(--go-ui-spacing-2xl) 0;
+
+ .content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--go-ui-spacing-xl);
+ }
+}
diff --git a/app/src/views/DrefProcess/i18n.json b/app/src/views/DrefProcess/i18n.json
new file mode 100644
index 000000000..01904a6dd
--- /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 000000000..2ed605891
--- /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/EapApplications/i18n.json b/app/src/views/EapApplications/i18n.json
index a48b9dee3..1d3fbee8c 100644
--- a/app/src/views/EapApplications/i18n.json
+++ b/app/src/views/EapApplications/i18n.json
@@ -1,7 +1,7 @@
{
"namespace": "eapApplication",
"strings": {
- "eapRegistrationLink": "EAP In Process? Let Us Know",
+ "eapRegistrationLink": "Register Your EAP",
"eapFormLink": "Start Full EAP",
"simplifiedEapLink": "Start sEAP"
}
diff --git a/app/src/views/EarlyActionProtocols/i18n.json b/app/src/views/EarlyActionProtocols/i18n.json
index 93b0362f8..9472e2952 100644
--- a/app/src/views/EarlyActionProtocols/i18n.json
+++ b/app/src/views/EarlyActionProtocols/i18n.json
@@ -1,10 +1,7 @@
{
"namespace": "earlyActionProtocols",
"strings": {
- "eapHeading": "Disaster Response Emergency Fund (DREF)",
- "eapDescription": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action.",
- "eapTitle": "Early Action Protocols (EAP)",
- "eapRegistrationLink": "EAP in Progress? Let Us Know",
+ "eapRegistrationLink": "Register your EAP",
"eapContent": "What is an EAP?",
"eapContentHeading": "Early Action Protocols (EAPs) are a core mechanism of the IFRC's Forecast-based Financing (FbF) approach, designed to ensure that humanitarian action happens before a disaster strikes, rather than only responding afterwards.",
"eapContentSubHeadingOne": "An EAP is a pre-agreed plan developed by a Nation Society together with partners, which outlines:",
diff --git a/app/src/views/EarlyActionProtocols/index.tsx b/app/src/views/EarlyActionProtocols/index.tsx
index 7688ff66a..3cd1d79d4 100644
--- a/app/src/views/EarlyActionProtocols/index.tsx
+++ b/app/src/views/EarlyActionProtocols/index.tsx
@@ -5,7 +5,6 @@ import {
import { useTranslation } from '@ifrc-go/ui/hooks';
import Link from '#components/Link';
-import Page from '#components/Page';
import i18n from './i18n.json';
import styles from './styles.module.css';
@@ -16,51 +15,49 @@ export function Component() {
const strings = useTranslation(i18n);
return (
-
+ {strings.eapRegistrationLink}
+
+ )}
>
-
- {strings.eapRegistrationLink}
-
- )}
- childrenContainerClassName={styles.earlyActionProtocols}
+
-
-
- {strings.eapContentHeading}
-
-
- {strings.eapContentSubHeadingOne}
-
- -
- {strings.eapDescriptionOne}
-
- -
- {strings.eapDescriptionTwo}
-
- -
- {strings.eapDescriptionThree}
-
-
-
-
- {/* TODO: Add remaining content */}
-
-
-
-
+
+ {strings.eapContentHeading}
+
+
+ {strings.eapContentSubHeadingOne}
+
+ -
+ {strings.eapDescriptionOne}
+
+ -
+ {strings.eapDescriptionTwo}
+
+ -
+ {strings.eapDescriptionThree}
+
+
+
+
+ {/* TODO: Add remaining content */}
+
+
+
);
}
+
+Component.displayName = 'EarlyActionProtocols';
diff --git a/app/src/views/EarlyActionProtocols/styles.module.css b/app/src/views/EarlyActionProtocols/styles.module.css
index 8ec3f610f..4df12fe2b 100644
--- a/app/src/views/EarlyActionProtocols/styles.module.css
+++ b/app/src/views/EarlyActionProtocols/styles.module.css
@@ -1,5 +1,11 @@
-.early-action-protocols {
+.eap-detail {
display: flex;
flex-direction: column;
- gap: var(--go-ui-spacing-lg);
+ padding: var(--go-ui-spacing-2xl) 0;
+
+ .content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--go-ui-spacing-lg);
+ }
}
From c7b0488e1cc2c9c842a77cd73ea9d14e7cbd756b Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Mon, 10 Nov 2025 16:54:31 +0545
Subject: [PATCH 05/15] eap-table(table): Add eap development table
---
.../views/EapApplications/Filters/i18n.json | 6 +
.../views/EapApplications/Filters/index.tsx | 47 +++++
app/src/views/EapApplications/i18n.json | 1 +
app/src/views/EapApplications/index.tsx | 178 ++++++++++++++++--
.../views/EapApplications/styles.module.css | 12 +-
5 files changed, 221 insertions(+), 23 deletions(-)
create mode 100644 app/src/views/EapApplications/Filters/i18n.json
create mode 100644 app/src/views/EapApplications/Filters/index.tsx
diff --git a/app/src/views/EapApplications/Filters/i18n.json b/app/src/views/EapApplications/Filters/i18n.json
new file mode 100644
index 000000000..9aab9233d
--- /dev/null
+++ b/app/src/views/EapApplications/Filters/i18n.json
@@ -0,0 +1,6 @@
+{
+ "namespace": "accountMyFormsEap",
+ "strings": {
+ "filterStatusPlaceholder": "Select Status"
+ }
+}
diff --git a/app/src/views/EapApplications/Filters/index.tsx b/app/src/views/EapApplications/Filters/index.tsx
new file mode 100644
index 000000000..8ebee1036
--- /dev/null
+++ b/app/src/views/EapApplications/Filters/index.tsx
@@ -0,0 +1,47 @@
+import { SelectInput } from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { stringValueSelector } from '@ifrc-go/ui/utils';
+import { type EntriesAsList } from '@togglecorp/toggle-form';
+
+import { type components } from '#generated/types';
+import useGlobalEnums from '#hooks/domain/useGlobalEnums';
+
+import i18n from './i18n.json';
+
+type TypeOfEapStatus = components<'read'>['schemas']['EapEapStatusEnumKey'];
+function typeOfEapStatusKeySelector({ key } : { key: TypeOfEapStatus }) {
+ return key;
+}
+
+export interface FilterValue {
+ status?: TypeOfEapStatus | undefined;
+}
+
+interface Props {
+ value: FilterValue;
+ onChange: (...args: EntriesAsList) => void;
+}
+
+function Filters(props: Props) {
+ const {
+ value,
+ onChange,
+ } = props;
+
+ const strings = useTranslation(i18n);
+ const { eap_eap_status: eapStatusTypeOptions } = useGlobalEnums();
+
+ return (
+
+ );
+}
+
+export default Filters;
diff --git a/app/src/views/EapApplications/i18n.json b/app/src/views/EapApplications/i18n.json
index 1d3fbee8c..72be7b0f2 100644
--- a/app/src/views/EapApplications/i18n.json
+++ b/app/src/views/EapApplications/i18n.json
@@ -2,6 +2,7 @@
"namespace": "eapApplication",
"strings": {
"eapRegistrationLink": "Register Your EAP",
+ "eapApplicationsHeading": "EAP Application",
"eapFormLink": "Start Full EAP",
"simplifiedEapLink": "Start sEAP"
}
diff --git a/app/src/views/EapApplications/index.tsx b/app/src/views/EapApplications/index.tsx
index dd9f788b5..130b9f6f1 100644
--- a/app/src/views/EapApplications/index.tsx
+++ b/app/src/views/EapApplications/index.tsx
@@ -1,39 +1,179 @@
-import { Container } from '@ifrc-go/ui';
+import {
+ useCallback,
+ useMemo,
+ useState,
+} from 'react';
+import {
+ Container,
+ Table,
+} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ createDateColumn,
+ createExpandColumn,
+ createExpansionIndicatorColumn,
+ createStringColumn,
+ numericIdSelector,
+} from '@ifrc-go/ui/utils';
import Link from '#components/Link';
+import useFilterState from '#hooks/useFilterState';
+import {
+ type GoApiResponse,
+ useRequest,
+} from '#utils/restRequest';
+
+import Filters, { type FilterValue } from './Filters';
import i18n from './i18n.json';
import styles from './styles.module.css';
+type EapResponse = GoApiResponse<'/api/v2/eap-registration/'>;
+type EapListItem = NonNullable[number];
+
+type Key = EapListItem['id'];
+
/** @knipignore */
// eslint-disable-next-line import/prefer-default-export
export function Component() {
const strings = useTranslation(i18n);
+ const {
+ filter,
+ offset,
+ limit,
+ rawFilter,
+ filtered,
+ setFilterField,
+ } = useFilterState({
+ filter: {},
+ pageSize: 6,
+ });
+
+ const {
+ response: eapResponse,
+ pending: eapPending,
+ } = useRequest({
+ url: '/api/v2/eap-registration/',
+ preserveResponse: true,
+ query: {
+ offset,
+ limit,
+ status: filter.status,
+ },
+ });
+
+ const [expandedRow, setExpandedRow] = useState();
+ const handleExpandClick = useCallback(
+ (row: EapListItem) => {
+ setExpandedRow(
+ (prevValue) => (prevValue?.id === row.id ? undefined : row),
+ );
+ },
+ [],
+ );
+
+ const baseColumns = useMemo(
+ () => ([
+ createDateColumn(
+ 'created_at',
+ 'Last Updated',
+ (item) => item.created_at,
+ { columnClassName: styles.date },
+ ),
+ createStringColumn(
+ 'name',
+ 'Name/Phase',
+ (item) => {
+ const baseYear = new Date(item.created_at).getFullYear();
+ let addedYear = baseYear;
+ if (item.eap_type === 10) {
+ addedYear = baseYear + 4;
+ } else if (item.eap_type === 20) {
+ addedYear = baseYear + 2;
+ }
+ return `${item.country_details?.name}:
+ ${item.disaster_type_details?.name}
+ ${baseYear} - ${addedYear}`;
+ },
+ { columnClassName: styles.title },
+ ),
+ createStringColumn(
+ 'eap_type_display',
+ 'EAP Type',
+ (item) => item.eap_type_display,
+ { columnClassName: styles.type },
+ ),
+ createStringColumn(
+ 'status_display',
+ 'Status',
+ (item) => item.status_display,
+ { columnClassName: styles.status },
+ ),
+ ]),
+ [],
+ );
+
+ const columns = useMemo(
+ () => ([
+ createExpansionIndicatorColumn(false),
+ ...baseColumns,
+ createExpandColumn(
+ 'expandRow',
+ '',
+ (row) => ({
+ onClick: handleExpandClick,
+ expanded: row.id === expandedRow?.id,
+ }),
+ ),
+ ]),
+ [baseColumns, handleExpandClick, expandedRow],
+ );
return (
+ )}
+ actions={(
+ <>
+
+ {strings.eapRegistrationLink}
+
+ {/* TODO: Move this to table action
+
+ {strings.eapFormLink}
+
+
+ {strings.simplifiedEapLink}
+
+ */}
+ >
+ )}
>
{/* FIXME: Add eap registration link */}
-
- {strings.eapRegistrationLink}
-
-
- {strings.eapFormLink}
-
-
- {strings.simplifiedEapLink}
-
+
);
}
diff --git a/app/src/views/EapApplications/styles.module.css b/app/src/views/EapApplications/styles.module.css
index c111ea1e6..2e3cef3c6 100644
--- a/app/src/views/EapApplications/styles.module.css
+++ b/app/src/views/EapApplications/styles.module.css
@@ -1,6 +1,10 @@
.eap-form-links {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: var(--go-ui-spacing-sm);
+ .table {
+ .type,
+ .status,
+ .date {
+ width: 0%;
+ min-width: 7rem;
+ }
+ }
}
\ No newline at end of file
From b523994ae32721ca341a10219708d886f5ed4745 Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Wed, 15 Oct 2025 15:43:29 +0545
Subject: [PATCH 06/15] eap(eap-registration-form): Add EAP Registration Form
---
app/src/views/EapRegistration/i18n.json | 42 +-
app/src/views/EapRegistration/index.tsx | 406 +++++++++++++++++-
app/src/views/EapRegistration/schema.ts | 56 +++
.../views/EapRegistration/styles.module.css | 22 +
4 files changed, 522 insertions(+), 4 deletions(-)
create mode 100644 app/src/views/EapRegistration/schema.ts
create mode 100644 app/src/views/EapRegistration/styles.module.css
diff --git a/app/src/views/EapRegistration/i18n.json b/app/src/views/EapRegistration/i18n.json
index 9b7a06dd0..de60e6530 100644
--- a/app/src/views/EapRegistration/i18n.json
+++ b/app/src/views/EapRegistration/i18n.json
@@ -2,6 +2,46 @@
"namespace": "eapRegistration",
"strings": {
"eapRegistrationHeading": "EAP Development Registration",
- "eapRegistrationDescription": "The purpose of this form is for you to notify the IFRC team of the start of your EAP process. If you need assistance with the initiation of the process, send us a message."
+ "eapRegistrationDescription": "Use the following page to submit your National Society's interest in following the Early Action Protocol (EAP) application process. Once you submit this form, the EAP team members will contact you to start the procedure. You can find more information on the process and different ways to apply {link}",
+ "eapRegistrationLink": "on this page.",
+ "eapApplicationDetails": "Application Details",
+ "eapNationalSociety": "National Society (NS)",
+ "eapNationalSocietyDescription": "Select National Society that is planning to apply for the EAP",
+ "eapCountry": "Country",
+ "eapCountryDescription": "The country will be pre-populated based on the NS selection, but can be adapted as needed.",
+ "eapDisasterType": "Disaster Type",
+ "eapDisasterTypeDescription": "Select the disaster type for which the EAP is needed.",
+ "eapType": "EAP Type",
+ "eapTypeDescription": "Select the EAP type. Find details of both under this link.",
+ "eapSubmission": "Expected Time of Submission",
+ "eapSubmissionDescription": "Include the proposed time of submission, accounting for the time it will take to deliver the application.",
+ "eapPartnersInvolved": "Partners Involved",
+ "eapPartnersInvolvedDescription": "Select from the list the partners involved in this process. Add as many as needed or select not applicable if no partners involved.",
+ "eapContacts": "Contacts",
+ "eapNSContact": "National Society Contact",
+ "eapNSContactDescription": "National Society contact responsible for the EAP process",
+ "eapNSName": "Name",
+ "eapNSTitle": "Title",
+ "eapNSEmail": "Email",
+ "eapNSPhoneNumber": "Phone Number",
+ "eapIFRCContact": "IFRC Contact",
+ "eapIFRCContactDescription": "The most senior staff in the National Society responsible and knowledgable about the disaster event.",
+ "eapIFRCName": "Name",
+ "eapIFRCTitle": "Title",
+ "eapIFRCEmail": "Email",
+ "eapIFRCPhoneNumber": "Phone Number",
+ "eapFocalPoint": "DREF Focal Point",
+ "eapFocalPointDescription": "The DREF contact person form IFRC",
+ "eapFocalPointName": "Name",
+ "eapFocalPointTitle": "Title",
+ "eapFocalPointEmail": "Email",
+ "eapFocalPointPhoneNumber": "Phone Number",
+ "eapSubmitButton": "Submit",
+ "eapCancelButton": "Cancel",
+ "eapRegistrationFailure": "Sorry could not register new EAP right now!",
+ "eapRegistrationSuccess": "Successfully created a new EAP!",
+ "eapNotSure": "Not Sure",
+ "eapDevelopmentRegistrationHeading": "EAP Development Registration",
+ "eapDevelopmentRegistrationDescription": "Thank you for notifying us about the start of your EAP process. We look forward to your completed application."
}
}
diff --git a/app/src/views/EapRegistration/index.tsx b/app/src/views/EapRegistration/index.tsx
index 31698b3c5..3e3e08b4f 100644
--- a/app/src/views/EapRegistration/index.tsx
+++ b/app/src/views/EapRegistration/index.tsx
@@ -1,21 +1,421 @@
+import {
+ type ElementRef,
+ useCallback,
+ useRef,
+} from 'react';
+import {
+ ConfirmButton,
+ Container,
+ DateInput,
+ InputSection,
+ Radio,
+ RadioInput,
+ TextInput,
+} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ resolveToComponent,
+ stringValueSelector,
+} from '@ifrc-go/ui/utils';
+import {
+ createSubmitHandler,
+ getErrorObject,
+ useForm,
+} from '@togglecorp/toggle-form';
+import CountrySelectInput from '#components/domain/CountrySelectInput';
+import DisasterTypeSelectInput from '#components/domain/DisasterTypeSelectInput';
+import NationalSocietyMultiSelectInput from '#components/domain/NationalSocietyMultiSelectInput';
+import NationalSocietySelectInput from '#components/domain/NationalSocietySelectInput';
+import Link from '#components/Link';
import Page from '#components/Page';
+import useGlobalEnums from '#hooks/domain/useGlobalEnums';
+import useAlert from '#hooks/useAlert';
+import useRouting from '#hooks/useRouting';
+import {
+ type GoApiBody,
+ type GoApiResponse,
+ useLazyRequest,
+} from '#utils/restRequest';
+import { transformObjectError } from '#utils/restRequest/error';
+
+import {
+ defaultFormValue,
+ formSchema,
+} from './schema';
import i18n from './i18n.json';
+import styles from './styles.module.css';
+
+type EapRegisterRequestBody = GoApiBody<'/api/v2/eap-registration/', 'POST'>;
+type GlobalEnumsResponse = GoApiResponse<'/api/v2/global-enums/'>;
+type EapTypeOption = NonNullable[number];
+
+function eapTypeKeySelector(option: EapTypeOption) {
+ return option.key;
+}
/** @knipignore */
// eslint-disable-next-line import/prefer-default-export
export function Component() {
const strings = useTranslation(i18n);
+ const alert = useAlert();
+ const { navigate } = useRouting();
+
+ const {
+ value,
+ setFieldValue,
+ error: formError,
+ setError,
+ validate,
+ } = useForm(formSchema, { value: defaultFormValue });
+
+ const {
+ eap_eap_type: eapFormOptions,
+ } = useGlobalEnums();
+
+ const error = getErrorObject(formError);
+ const formContentRef = useRef>(null);
+
+ const {
+ pending: eapRegistrationPending,
+ trigger: eapRegister,
+ } = useLazyRequest({
+ method: 'POST',
+ url: '/api/v2/eap-registration/',
+ body: (body: EapRegisterRequestBody) => body,
+ onSuccess: () => {
+ const message = strings.eapRegistrationSuccess;
+ alert.show(
+ message,
+ { variant: 'success' },
+ );
+ navigate('accountMyFormsEap');
+ },
+ onFailure: (err) => {
+ const {
+ value: {
+ formErrors,
+ },
+ } = err;
+
+ setError(transformObjectError(formErrors, () => undefined));
+
+ alert.show(
+ strings.eapRegistrationFailure,
+ { variant: 'danger' },
+ );
+ },
+ });
+
+ const handleCountryChange = useCallback(
+ (val: number | undefined, name: 'country') => {
+ setFieldValue(val, name);
+ },
+ [setFieldValue],
+ );
+
+ const handleEapTypeClick = useCallback(() => {
+ setFieldValue(undefined, 'eap_type');
+ }, [setFieldValue]);
+
+ const handleSubmissionTimeClick = useCallback(() => {
+ setFieldValue(undefined, 'expected_submission_time');
+ }, [setFieldValue]);
+
+ const eapRegistration = useCallback(() => {
+ const handler = createSubmitHandler(
+ validate,
+ setError,
+ (formValues) => {
+ eapRegister(formValues as EapRegisterRequestBody);
+ },
+ );
+ handler();
+ }, [
+ setError,
+ validate,
+ eapRegister,
+ ]);
+
+ const handleFormError = useCallback(() => {
+ setTimeout(() => formContentRef.current?.scrollIntoView(), 200);
+ }, []);
+
+ const handleEapRegistration = useCallback(() => {
+ const handler = createSubmitHandler(
+ validate,
+ setError,
+ eapRegistration,
+ handleFormError,
+ );
+ handler();
+ }, [
+ handleFormError,
+ eapRegistration,
+ validate,
+ setError,
+ ]);
+
+ const disabled = eapRegistrationPending;
return (
+ {strings.eapRegistrationLink}
+
+ ),
+ },
+ )}
+ actions={(
+
+ {strings.eapCancelButton}
+
+ )}
+ withBackgroundColorInMainSection
>
- {/* TODO: Add the form */}
- Application Details
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {strings.eapSubmitButton}
+
+
);
}
diff --git a/app/src/views/EapRegistration/schema.ts b/app/src/views/EapRegistration/schema.ts
new file mode 100644
index 000000000..640e0b1cb
--- /dev/null
+++ b/app/src/views/EapRegistration/schema.ts
@@ -0,0 +1,56 @@
+import {
+ emailCondition,
+ type ObjectSchema,
+ type PartialForm,
+} from '@togglecorp/toggle-form';
+
+import { type GoApiBody } from '#utils/restRequest';
+
+type EapRegisterRequestBody = GoApiBody<'/api/v2/eap-registration/', 'POST'>;
+
+export const defaultFormValue: FormFields = {
+ eap_type: null,
+ expected_submission_time: null,
+};
+
+type FormFields = PartialForm;
+
+type FormSchema = ObjectSchema;
+type FormSchemaFields = ReturnType
+
+export const formSchema: FormSchema = {
+ fields: (): FormSchemaFields => ({
+ national_society: {
+ required: true,
+ },
+ country: {
+ required: true,
+ },
+ disaster_type: {
+ required: true,
+ },
+ eap_type: {},
+ expected_submission_time: {},
+ partners: {
+ required: true,
+ },
+ national_society_contact_name: {},
+ national_society_contact_title: {},
+ national_society_contact_email: {
+ validations: [emailCondition],
+ },
+ national_society_contact_phone_number: {},
+ ifrc_contact_name: {},
+ ifrc_contact_title: {},
+ ifrc_contact_email: {
+ validations: [emailCondition],
+ },
+ ifrc_contact_phone_number: {},
+ dref_focal_point_name: {},
+ dref_focal_point_title: {},
+ dref_focal_point_email: {
+ validations: [emailCondition],
+ },
+ dref_focal_point_phone_number: {},
+ }),
+};
diff --git a/app/src/views/EapRegistration/styles.module.css b/app/src/views/EapRegistration/styles.module.css
new file mode 100644
index 000000000..a6479f54a
--- /dev/null
+++ b/app/src/views/EapRegistration/styles.module.css
@@ -0,0 +1,22 @@
+.eap-registration-form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--go-ui-spacing-md);
+
+ .content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--go-ui-spacing-md);
+
+ .radio-content {
+ display: flex;
+ gap: var(--go-ui-spacing-md);
+ }
+ }
+
+ .footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
From 4bc79889881d4b035b15b52e56001ce469adcad4 Mon Sep 17 00:00:00 2001
From: barshathakuri
Date: Mon, 10 Nov 2025 16:54:31 +0545
Subject: [PATCH 07/15] eap-table(table): Add eap development table
---
app/src/App/routes/index.tsx | 80 +++++++++++++---
.../EapApplications/EapTableActions/i18n.json | 8 ++
.../EapApplications/EapTableActions/index.tsx | 48 ++++++++++
app/src/views/EapApplications/i18n.json | 4 +-
app/src/views/EapApplications/index.tsx | 93 ++++++++++++++-----
.../views/EapApplications/styles.module.css | 5 +
6 files changed, 195 insertions(+), 43 deletions(-)
create mode 100644 app/src/views/EapApplications/EapTableActions/i18n.json
create mode 100644 app/src/views/EapApplications/EapTableActions/index.tsx
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index 3c4c91523..00fa1594a 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -1182,6 +1182,68 @@ const fieldReportDetails = customWrapRoute({
},
});
+type DefaultEapRegistrationChild = 'new';
+const eapRegistrationLayout = customWrapRoute({
+ parent: rootLayout,
+ path: 'eap-registration',
+ forwardPath: 'new' satisfies DefaultEapRegistrationChild,
+ component: {
+ render: () => import('#views/EapRegistration'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'EAP Process',
+ visibility: 'is-authenticated',
+ },
+});
+
+const eapRegistrationFormIndex = customWrapRoute({
+ parent: eapRegistrationLayout,
+ index: true,
+ component: {
+ eagerLoad: true,
+ render: Navigate,
+ props: {
+ to: 'new' satisfies DefaultPerProcessChild,
+ replace: true,
+ },
+ },
+ context: {
+ title: 'EAP Registration',
+ visibility: 'anything',
+ },
+});
+
+const eapDevelopmentRegistration = customWrapRoute({
+ parent: eapRegistrationLayout,
+ path: 'new' satisfies DefaultEapRegistrationChild,
+ component: {
+ render: () => import('#views/EapRegistration'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'New EAP Development Registration',
+ visibility: 'is-authenticated',
+ permissions: ({ isGuestUser }) => !isGuestUser,
+ },
+});
+
+const eapDevelopmentRegistrationForm = customWrapRoute({
+ parent: eapRegistrationLayout,
+ path: ':eapId/view',
+ component: {
+ render: () => import('#views/EapRegistration'),
+ props: {},
+ },
+ wrapperComponent: Auth,
+ context: {
+ title: 'View EAP Overview',
+ visibility: 'is-authenticated',
+ },
+});
+
type DefaultPerProcessChild = 'new';
const perProcessLayout = customWrapRoute({
parent: rootLayout,
@@ -1234,21 +1296,6 @@ const newPerOverviewForm = customWrapRoute({
},
});
-const eapDevelopmentRegistration = customWrapRoute({
- parent: rootLayout,
- path: 'eap-registration/new',
- component: {
- render: () => import('#views/EapRegistration'),
- props: {},
- },
- wrapperComponent: Auth,
- context: {
- title: 'EAP Development Registration',
- visibility: 'is-authenticated',
- permissions: ({ isGuestUser }) => !isGuestUser,
- },
-});
-
const perOverviewForm = customWrapRoute({
parent: perProcessLayout,
path: ':perId/overview',
@@ -1473,6 +1520,9 @@ const wrappedRoutes = {
drefDetail,
eapDetail,
drefProcessLayout,
+ eapRegistrationLayout,
+ eapDevelopmentRegistrationForm,
+ eapRegistrationFormIndex,
};
export const unwrappedRoutes = unwrapRoute(Object.values(wrappedRoutes));
diff --git a/app/src/views/EapApplications/EapTableActions/i18n.json b/app/src/views/EapApplications/EapTableActions/i18n.json
new file mode 100644
index 000000000..dcacb9754
--- /dev/null
+++ b/app/src/views/EapApplications/EapTableActions/i18n.json
@@ -0,0 +1,8 @@
+{
+ "namespace":"accountMyFormsEap",
+ "strings":{
+ "eapViewLabel": "View",
+ "eapFormLink": "Start Full EAP",
+ "simplifiedEapLink": "Start sEAP"
+ }
+}
diff --git a/app/src/views/EapApplications/EapTableActions/index.tsx b/app/src/views/EapApplications/EapTableActions/index.tsx
new file mode 100644
index 000000000..24039a845
--- /dev/null
+++ b/app/src/views/EapApplications/EapTableActions/index.tsx
@@ -0,0 +1,48 @@
+import { TableActions } from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+
+import DropdownMenuItem from '#components/DropdownMenuItem';
+import Link from '#components/Link';
+
+import i18n from './i18n.json';
+
+export interface Props {
+ eapId: number;
+}
+
+function EapTableActions(props: Props) {
+ const { eapId } = props;
+
+ const strings = useTranslation(i18n);
+
+ return (
+
+ {strings.eapViewLabel}
+
+ )}
+ >
+
+ {strings.eapFormLink}
+
+
+ {strings.simplifiedEapLink}
+
+
+ );
+}
+
+export default EapTableActions;
diff --git a/app/src/views/EapApplications/i18n.json b/app/src/views/EapApplications/i18n.json
index 72be7b0f2..2c28c7659 100644
--- a/app/src/views/EapApplications/i18n.json
+++ b/app/src/views/EapApplications/i18n.json
@@ -2,8 +2,6 @@
"namespace": "eapApplication",
"strings": {
"eapRegistrationLink": "Register Your EAP",
- "eapApplicationsHeading": "EAP Application",
- "eapFormLink": "Start Full EAP",
- "simplifiedEapLink": "Start sEAP"
+ "eapApplicationsHeading": "EAP Application"
}
}
diff --git a/app/src/views/EapApplications/index.tsx b/app/src/views/EapApplications/index.tsx
index 130b9f6f1..c6efb434c 100644
--- a/app/src/views/EapApplications/index.tsx
+++ b/app/src/views/EapApplications/index.tsx
@@ -5,11 +5,15 @@ import {
} from 'react';
import {
Container,
+ type RowOptions,
Table,
+ TableBodyContent,
} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
import {
createDateColumn,
+ createElementColumn,
+ createEmptyColumn,
createExpandColumn,
createExpansionIndicatorColumn,
createStringColumn,
@@ -23,6 +27,7 @@ import {
useRequest,
} from '#utils/restRequest';
+import EapTableActions, { type Props as EapTableActionProps } from './EapTableActions';
import Filters, { type FilterValue } from './Filters';
import i18n from './i18n.json';
@@ -37,6 +42,7 @@ type Key = EapListItem['id'];
// eslint-disable-next-line import/prefer-default-export
export function Component() {
const strings = useTranslation(i18n);
+
const {
filter,
offset,
@@ -113,7 +119,7 @@ export function Component() {
[],
);
- const columns = useMemo(
+ const aggregatedColumns = useMemo(
() => ([
createExpansionIndicatorColumn(false),
...baseColumns,
@@ -129,6 +135,59 @@ export function Component() {
[baseColumns, handleExpandClick, expandedRow],
);
+ const detailColumns = useMemo(
+ () => ([
+ createExpansionIndicatorColumn(true),
+ createStringColumn(
+ 'title',
+ '',
+ () => 'EAP Registration',
+ { columnClassName: styles.detailTitle },
+ ),
+ createElementColumn(
+ 'actions',
+ 'EAP Registration',
+ EapTableActions,
+ (eapId) => ({
+ eapId,
+ }),
+ ),
+ createEmptyColumn(),
+ createEmptyColumn(),
+ createEmptyColumn(),
+ ]),
+ [],
+ );
+
+ const rowModifier = useCallback(
+ ({ row, datum }: RowOptions) => {
+ if (datum.id !== expandedRow?.id) {
+ return row;
+ }
+
+ const subRows = eapResponse?.results?.filter(
+ (subRow) => subRow.id === datum.id,
+ );
+
+ return (
+ <>
+ {row}
+
+ >
+ );
+ },
+ [
+ expandedRow,
+ detailColumns,
+ eapResponse,
+ ],
+ );
+
return (
)}
actions={(
- <>
-
- {strings.eapRegistrationLink}
-
- {/* TODO: Move this to table action
-
- {strings.eapFormLink}
-
-
- {strings.simplifiedEapLink}
-
- */}
- >
+
+ {strings.eapRegistrationLink}
+
)}
>
- {/* FIXME: Add eap registration link */}
Date: Wed, 12 Nov 2025 16:22:37 +0545
Subject: [PATCH 08/15] eap(lisitng): Add eap listing page
---
app/src/App/routes/index.tsx | 26 +--
app/src/utils/constants.ts | 3 +
.../EapApplications/EapTableActions/i18n.json | 1 +
.../EapApplications/EapTableActions/index.tsx | 25 ++-
app/src/views/EapApplications/i18n.json | 7 +-
app/src/views/EapApplications/index.tsx | 66 ++++---
.../views/EapApplications/styles.module.css | 7 +-
app/src/views/EapRegistration/i18n.json | 6 +-
app/src/views/EapRegistration/index.tsx | 164 +++++++++++++++---
app/src/views/EapRegistration/schema.ts | 4 +-
app/src/views/EarlyActionProtocols/index.tsx | 2 +-
11 files changed, 223 insertions(+), 88 deletions(-)
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index 00fa1594a..0fb0e0e86 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -1198,24 +1198,7 @@ const eapRegistrationLayout = customWrapRoute({
},
});
-const eapRegistrationFormIndex = customWrapRoute({
- parent: eapRegistrationLayout,
- index: true,
- component: {
- eagerLoad: true,
- render: Navigate,
- props: {
- to: 'new' satisfies DefaultPerProcessChild,
- replace: true,
- },
- },
- context: {
- title: 'EAP Registration',
- visibility: 'anything',
- },
-});
-
-const eapDevelopmentRegistration = customWrapRoute({
+const newEapDevelopmentRegistration = customWrapRoute({
parent: eapRegistrationLayout,
path: 'new' satisfies DefaultEapRegistrationChild,
component: {
@@ -1232,14 +1215,14 @@ const eapDevelopmentRegistration = customWrapRoute({
const eapDevelopmentRegistrationForm = customWrapRoute({
parent: eapRegistrationLayout,
- path: ':eapId/view',
+ path: ':eapId/',
component: {
render: () => import('#views/EapRegistration'),
props: {},
},
wrapperComponent: Auth,
context: {
- title: 'View EAP Overview',
+ title: 'View EAP',
visibility: 'is-authenticated',
},
});
@@ -1504,7 +1487,7 @@ const wrappedRoutes = {
termsAndConditions,
operationalLearning,
montandonLandingPage,
- eapDevelopmentRegistration,
+ newEapDevelopmentRegistration,
eapFullForm,
simplifiedEapForm,
...regionRoutes,
@@ -1522,7 +1505,6 @@ const wrappedRoutes = {
drefProcessLayout,
eapRegistrationLayout,
eapDevelopmentRegistrationForm,
- eapRegistrationFormIndex,
};
export const unwrappedRoutes = unwrapRoute(Object.values(wrappedRoutes));
diff --git a/app/src/utils/constants.ts b/app/src/utils/constants.ts
index 8d3ec82ce..453939d3e 100644
--- a/app/src/utils/constants.ts
+++ b/app/src/utils/constants.ts
@@ -199,3 +199,6 @@ export const multiMonthSelectDefaultValue = listToMap(
export const ERU_READINESS_READY = 1;
export const ERU_READINESS_CAN_CONTRIBUTE = 2;
export const ERU_READINESS_NO_CAPACITY = 3;
+
+export const EAP_TYPE_SIMPLIFIED = 20;
+export const EAP_TYPE_FULL = 10;
diff --git a/app/src/views/EapApplications/EapTableActions/i18n.json b/app/src/views/EapApplications/EapTableActions/i18n.json
index dcacb9754..35e2dc216 100644
--- a/app/src/views/EapApplications/EapTableActions/i18n.json
+++ b/app/src/views/EapApplications/EapTableActions/i18n.json
@@ -2,6 +2,7 @@
"namespace":"accountMyFormsEap",
"strings":{
"eapViewLabel": "View",
+ "eapEditLabel": "Edit",
"eapFormLink": "Start Full EAP",
"simplifiedEapLink": "Start sEAP"
}
diff --git a/app/src/views/EapApplications/EapTableActions/index.tsx b/app/src/views/EapApplications/EapTableActions/index.tsx
index 24039a845..1294b0098 100644
--- a/app/src/views/EapApplications/EapTableActions/index.tsx
+++ b/app/src/views/EapApplications/EapTableActions/index.tsx
@@ -18,13 +18,24 @@ function EapTableActions(props: Props) {
return (
- {strings.eapViewLabel}
-
+ <>
+
+ {strings.eapViewLabel}
+
+
+ {strings.eapEditLabel}
+
+ >
)}
>
;
type EapListItem = NonNullable[number];
type Key = EapListItem['id'];
+const ITEM_PER_PAGE = 6;
/** @knipignore */
// eslint-disable-next-line import/prefer-default-export
@@ -50,9 +56,11 @@ export function Component() {
rawFilter,
filtered,
setFilterField,
+ page,
+ setPage,
} = useFilterState({
filter: {},
- pageSize: 6,
+ pageSize: ITEM_PER_PAGE,
});
const {
@@ -82,19 +90,18 @@ export function Component() {
() => ([
createDateColumn(
'created_at',
- 'Last Updated',
+ strings.eapLastUpdated,
(item) => item.created_at,
- { columnClassName: styles.date },
),
createStringColumn(
'name',
- 'Name/Phase',
+ strings.eapName,
(item) => {
const baseYear = new Date(item.created_at).getFullYear();
let addedYear = baseYear;
- if (item.eap_type === 10) {
- addedYear = baseYear + 4;
- } else if (item.eap_type === 20) {
+ if (item.eap_type === EAP_TYPE_FULL) {
+ addedYear = baseYear + 5;
+ } else if (item.eap_type === EAP_TYPE_SIMPLIFIED) {
addedYear = baseYear + 2;
}
return `${item.country_details?.name}:
@@ -105,24 +112,15 @@ export function Component() {
),
createStringColumn(
'eap_type_display',
- 'EAP Type',
+ strings.eapType,
(item) => item.eap_type_display,
- { columnClassName: styles.type },
),
createStringColumn(
'status_display',
- 'Status',
+ strings.eapStatus,
(item) => item.status_display,
{ columnClassName: styles.status },
),
- ]),
- [],
- );
-
- const aggregatedColumns = useMemo(
- () => ([
- createExpansionIndicatorColumn(false),
- ...baseColumns,
createExpandColumn(
'expandRow',
'',
@@ -132,7 +130,14 @@ export function Component() {
}),
),
]),
- [baseColumns, handleExpandClick, expandedRow],
+ [
+ strings.eapLastUpdated,
+ strings.eapName,
+ strings.eapType,
+ strings.eapStatus,
+ expandedRow,
+ handleExpandClick,
+ ],
);
const detailColumns = useMemo(
@@ -141,22 +146,21 @@ export function Component() {
createStringColumn(
'title',
'',
- () => 'EAP Registration',
+ () => strings.eapRegistration,
{ columnClassName: styles.detailTitle },
),
+ createEmptyColumn(),
createElementColumn(
'actions',
- 'EAP Registration',
+ '',
EapTableActions,
(eapId) => ({
eapId,
}),
),
createEmptyColumn(),
- createEmptyColumn(),
- createEmptyColumn(),
]),
- [],
+ [strings.eapRegistration],
);
const rowModifier = useCallback(
@@ -193,7 +197,7 @@ export function Component() {
childrenContainerClassName={styles.eapFormLinks}
heading={strings.eapApplicationsHeading}
withHeaderBorder
- filters={(
+ filters={(eapResponse?.count ?? 0) > 0 && (
{strings.eapRegistrationLink}
)}
+ footerActions={(
+
+ )}
>
();
+
+ const { state } = useLocation();
+ const eapId = eapIdFromParams ?? state?.eapId as string | undefined;
+ const isReadOnly = state?.mode === 'view';
const {
value,
setFieldValue,
error: formError,
setError,
+ setValue,
validate,
} = useForm(formSchema, { value: defaultFormValue });
@@ -77,6 +94,23 @@ export function Component() {
const error = getErrorObject(formError);
const formContentRef = useRef>(null);
+ const {
+ pending: fetchingEap,
+ error: eapError,
+ } = useRequest({
+ skip: isNotDefined(eapId),
+ url: '/api/v2/eap-registration/{id}/',
+ pathVariables: isTruthyString(eapId) ? {
+ id: Number(eapId),
+ } : undefined,
+ onSuccess: (response) => {
+ const {
+ ...formValues
+ } = response;
+ setValue(formValues);
+ },
+ });
+
const {
pending: eapRegistrationPending,
trigger: eapRegister,
@@ -108,6 +142,49 @@ export function Component() {
},
});
+ const {
+ pending: updateEapRegistrationPending,
+ trigger: updateEapRegistration,
+ } = useLazyRequest({
+ url: '/api/v2/eap-registration/{id}/',
+ method: 'PATCH',
+ pathVariables: {
+ id: Number(eapId),
+ },
+ body: (formFields: EapRegisterRequestBody) => formFields,
+ onSuccess: (response) => {
+ alert.show(
+ strings.eapRegistrationUpdateMessage,
+ { variant: 'success' },
+ );
+ navigate(
+ 'accountMyFormsEap',
+ { params: { eapId: response.id } },
+ );
+ },
+ onFailure: (err) => {
+ const {
+ value: {
+ formErrors,
+ messageForNotification,
+ },
+ } = err;
+
+ setError(transformObjectError(
+ formErrors,
+ () => undefined,
+ ));
+
+ alert.show(
+ strings.eapRegistrationFailureMessage,
+ {
+ variant: 'danger',
+ description: messageForNotification,
+ },
+ );
+ },
+ });
+
const handleCountryChange = useCallback(
(val: number | undefined, name: 'country') => {
setFieldValue(val, name);
@@ -116,19 +193,32 @@ export function Component() {
);
const handleEapTypeClick = useCallback(() => {
- setFieldValue(undefined, 'eap_type');
- }, [setFieldValue]);
+ if (isReadOnly) {
+ return;
+ }
+ setFieldValue(null, 'eap_type');
+ }, [isReadOnly, setFieldValue]);
const handleSubmissionTimeClick = useCallback(() => {
- setFieldValue(undefined, 'expected_submission_time');
- }, [setFieldValue]);
+ if (isReadOnly) {
+ return;
+ }
+ setFieldValue(null, 'expected_submission_time');
+ }, [isReadOnly, setFieldValue]);
const eapRegistration = useCallback(() => {
const handler = createSubmitHandler(
validate,
setError,
(formValues) => {
- eapRegister(formValues as EapRegisterRequestBody);
+ if (isNotDefined(eapId)) {
+ eapRegister(formValues as EapRegisterRequestBody);
+ } else {
+ updateEapRegistration({
+ ...formValues,
+ id: eapId,
+ } as EapRegisterRequestBody);
+ }
},
);
handler();
@@ -136,6 +226,8 @@ export function Component() {
setError,
validate,
eapRegister,
+ updateEapRegistration,
+ eapId,
]);
const handleFormError = useCallback(() => {
@@ -157,7 +249,15 @@ export function Component() {
setError,
]);
- const disabled = eapRegistrationPending;
+ const disabled = eapRegistrationPending || fetchingEap || updateEapRegistrationPending;
+
+ if (isDefined(eapError)) {
+ return (
+
+ );
+ }
return (
- {strings.eapCancelButton}
+ {eapId ? strings.eapBackButton : strings.eapCancelButton}
)}
withBackgroundColorInMainSection
@@ -201,6 +301,7 @@ export function Component() {
onChange={setFieldValue}
value={value?.national_society}
disabled={disabled}
+ readOnly={isReadOnly}
/>
@@ -301,6 +407,7 @@ export function Component() {
onChange={setFieldValue}
error={error?.national_society_contact_name}
disabled={disabled}
+ readOnly={isReadOnly}
/>
-
- {strings.eapSubmitButton}
-
+ {!isReadOnly && (
+
+ {strings.eapSubmitButton}
+
+ )}
);
diff --git a/app/src/views/EapRegistration/schema.ts b/app/src/views/EapRegistration/schema.ts
index 640e0b1cb..17dca9c0b 100644
--- a/app/src/views/EapRegistration/schema.ts
+++ b/app/src/views/EapRegistration/schema.ts
@@ -9,8 +9,8 @@ import { type GoApiBody } from '#utils/restRequest';
type EapRegisterRequestBody = GoApiBody<'/api/v2/eap-registration/', 'POST'>;
export const defaultFormValue: FormFields = {
- eap_type: null,
- expected_submission_time: null,
+ eap_type: undefined,
+ expected_submission_time: undefined,
};
type FormFields = PartialForm;
diff --git a/app/src/views/EarlyActionProtocols/index.tsx b/app/src/views/EarlyActionProtocols/index.tsx
index 3cd1d79d4..fa7d968d3 100644
--- a/app/src/views/EarlyActionProtocols/index.tsx
+++ b/app/src/views/EarlyActionProtocols/index.tsx
@@ -21,7 +21,7 @@ export function Component() {
childrenContainerClassName={styles.content}
actions={(
{strings.eapRegistrationLink}
From d46e1992f66add213332f3a30d56f522cd6c3078 Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Mon, 17 Nov 2025 16:07:17 +0545
Subject: [PATCH 09/15] feat(eap): update translation file
---
.../000053-1761542116137.json | 119 -----
.../000059-1763374780926.json | 503 ++++++++++++++++++
2 files changed, 503 insertions(+), 119 deletions(-)
delete mode 100644 translationMigrations/000053-1761542116137.json
create mode 100644 translationMigrations/000059-1763374780926.json
diff --git a/translationMigrations/000053-1761542116137.json b/translationMigrations/000053-1761542116137.json
deleted file mode 100644
index e18c829ed..000000000
--- a/translationMigrations/000053-1761542116137.json
+++ /dev/null
@@ -1,119 +0,0 @@
-{
- "parent": "000052-1758547474974.json",
- "actions": [
- {
- "action": "add",
- "key": "eapApplications",
- "namespace": "accountMyFormsLayout",
- "value": "EAP Applications"
- },
- {
- "action": "add",
- "key": "earlyActionProtocols",
- "namespace": "common",
- "value": "Early Action Protocols (EAP)"
- },
- {
- "action": "add",
- "key": "eapFormLink",
- "namespace": "eapApplication",
- "value": "Start Full EAP"
- },
- {
- "action": "add",
- "key": "eapRegistrationLink",
- "namespace": "eapApplication",
- "value": "EAP In Process? Let Us Know"
- },
- {
- "action": "add",
- "key": "simplifiedEapLink",
- "namespace": "eapApplication",
- "value": "Start sEAP"
- },
- {
- "action": "add",
- "key": "eapRegistrationDescription",
- "namespace": "eapRegistration",
- "value": "The purpose of this form is for you to notify the IFRC team of the start of your EAP process. If you need assistance with the initiation of the process, send us a message."
- },
- {
- "action": "add",
- "key": "eapRegistrationHeading",
- "namespace": "eapRegistration",
- "value": "EAP Development Registration"
- },
- {
- "action": "add",
- "key": "eapContent",
- "namespace": "earlyActionProtocols",
- "value": "What is an EAP?"
- },
- {
- "action": "add",
- "key": "eapContentHeading",
- "namespace": "earlyActionProtocols",
- "value": "Early Action Protocols (EAPs) are a core mechanism of the IFRC's Forecast-based Financing (FbF) approach, designed to ensure that humanitarian action happens before a disaster strikes, rather than only responding afterwards."
- },
- {
- "action": "add",
- "key": "eapContentSubHeadingOne",
- "namespace": "earlyActionProtocols",
- "value": "An EAP is a pre-agreed plan developed by a Nation Society together with partners, which outlines:"
- },
- {
- "action": "add",
- "key": "eapContentSubHeadingThree",
- "namespace": "earlyActionProtocols",
- "value": "What is the EAP Application Process?"
- },
- {
- "action": "add",
- "key": "eapContentSubHeadingTwo",
- "namespace": "earlyActionProtocols",
- "value": "Why are the EAPs Important?"
- },
- {
- "action": "add",
- "key": "eapDescription",
- "namespace": "earlyActionProtocols",
- "value": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action."
- },
- {
- "action": "add",
- "key": "eapDescriptionOne",
- "namespace": "earlyActionProtocols",
- "value": "The triggers (based on scientific forecasts and risk analysis) that indicate when a hazard is likely to impact communities."
- },
- {
- "action": "add",
- "key": "eapDescriptionThree",
- "namespace": "earlyActionProtocols",
- "value": "The roles, responsibilities, and budget required to carry out these actions quickly and effectively."
- },
- {
- "action": "add",
- "key": "eapDescriptionTwo",
- "namespace": "earlyActionProtocols",
- "value": "The early actions to be implemented once those triggers are met - practical, life-saving measures that reduce the impacts of the forecasted disaster."
- },
- {
- "action": "add",
- "key": "eapHeading",
- "namespace": "earlyActionProtocols",
- "value": "Disaster Response Emergency Fund (DREF)"
- },
- {
- "action": "add",
- "key": "eapRegistrationLink",
- "namespace": "earlyActionProtocols",
- "value": "EAP in Progress? Let Us Know"
- },
- {
- "action": "add",
- "key": "eapTitle",
- "namespace": "earlyActionProtocols",
- "value": "Early Action Protocols (EAP)"
- }
- ]
-}
\ No newline at end of file
diff --git a/translationMigrations/000059-1763374780926.json b/translationMigrations/000059-1763374780926.json
new file mode 100644
index 000000000..5578d15f3
--- /dev/null
+++ b/translationMigrations/000059-1763374780926.json
@@ -0,0 +1,503 @@
+{
+ "parent": "000058-1762859195042.json",
+ "actions": [
+ {
+ "action": "add",
+ "key": "eapEditLabel",
+ "namespace": "accountMyFormsEap",
+ "value": "Edit"
+ },
+ {
+ "action": "add",
+ "key": "eapFormLink",
+ "namespace": "accountMyFormsEap",
+ "value": "Start Full EAP"
+ },
+ {
+ "action": "add",
+ "key": "eapViewLabel",
+ "namespace": "accountMyFormsEap",
+ "value": "View"
+ },
+ {
+ "action": "add",
+ "key": "filterStatusPlaceholder",
+ "namespace": "accountMyFormsEap",
+ "value": "Select Status"
+ },
+ {
+ "action": "add",
+ "key": "simplifiedEapLink",
+ "namespace": "accountMyFormsEap",
+ "value": "Start sEAP"
+ },
+ {
+ "action": "add",
+ "key": "eapApplications",
+ "namespace": "accountMyFormsLayout",
+ "value": "EAP Applications"
+ },
+ {
+ "action": "add",
+ "key": "earlyActionProtocols",
+ "namespace": "common",
+ "value": "Early Action Protocols (EAP)"
+ },
+ {
+ "action": "add",
+ "key": "drefDrefApplication",
+ "namespace": "drefDetail",
+ "value": "DREF Application"
+ },
+ {
+ "action": "add",
+ "key": "drefIntroDetailOne",
+ "namespace": "drefDetail",
+ "value": "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."
+ },
+ {
+ "action": "add",
+ "key": "drefIntroDetailTwo",
+ "namespace": "drefDetail",
+ "value": "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."
+ },
+ {
+ "action": "add",
+ "key": "drefIntroHeading",
+ "namespace": "drefDetail",
+ "value": "DREF Intro"
+ },
+ {
+ "action": "add",
+ "key": "drefProcessDetailOne",
+ "namespace": "drefDetail",
+ "value": "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."
+ },
+ {
+ "action": "add",
+ "key": "drefProcessDetailTwo",
+ "namespace": "drefDetail",
+ "value": "On average, the DREF supports more than 100 responses to small and medium-sized disasters every year."
+ },
+ {
+ "action": "add",
+ "key": "drefProcessHeading",
+ "namespace": "drefDetail",
+ "value": "Dref Process"
+ },
+ {
+ "action": "add",
+ "key": "drefProcessListOne",
+ "namespace": "drefDetail",
+ "value": "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."
+ },
+ {
+ "action": "add",
+ "key": "drefProcessListTwo",
+ "namespace": "drefDetail",
+ "value": "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."
+ },
+ {
+ "action": "add",
+ "key": "drefProcessSubHeading",
+ "namespace": "drefDetail",
+ "value": "We provide funding in two ways:"
+ },
+ {
+ "action": "add",
+ "key": "eapDescription",
+ "namespace": "drefProcess",
+ "value": "The IFRC's Disaster Emergency Fund (DREF): rapid, reliable funding for life-saving action."
+ },
+ {
+ "action": "add",
+ "key": "eapHeading",
+ "namespace": "drefProcess",
+ "value": "Disaster Response Emergency Fund (DREF)"
+ },
+ {
+ "action": "add",
+ "key": "eapProcessDrefTab",
+ "namespace": "drefProcess",
+ "value": "Response And Imminent Dref"
+ },
+ {
+ "action": "add",
+ "key": "eapProcessEapTab",
+ "namespace": "drefProcess",
+ "value": "Early Action Protocols (EAP)"
+ },
+ {
+ "action": "add",
+ "key": "eapApplicationsHeading",
+ "namespace": "eapApplication",
+ "value": "EAP Application"
+ },
+ {
+ "action": "add",
+ "key": "eapLastUpdated",
+ "namespace": "eapApplication",
+ "value": "Last Updated"
+ },
+ {
+ "action": "add",
+ "key": "eapName",
+ "namespace": "eapApplication",
+ "value": "Name/Phase"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistration",
+ "namespace": "eapApplication",
+ "value": "EAP Registration"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationLink",
+ "namespace": "eapApplication",
+ "value": "Register Your EAP"
+ },
+ {
+ "action": "add",
+ "key": "eapStatus",
+ "namespace": "eapApplication",
+ "value": "Status"
+ },
+ {
+ "action": "add",
+ "key": "eapType",
+ "namespace": "eapApplication",
+ "value": "EAP Type"
+ },
+ {
+ "action": "add",
+ "key": "eapApplicationDetails",
+ "namespace": "eapRegistration",
+ "value": "Application Details"
+ },
+ {
+ "action": "add",
+ "key": "eapBackButton",
+ "namespace": "eapRegistration",
+ "value": "Back"
+ },
+ {
+ "action": "add",
+ "key": "eapCancelButton",
+ "namespace": "eapRegistration",
+ "value": "Cancel"
+ },
+ {
+ "action": "add",
+ "key": "eapContacts",
+ "namespace": "eapRegistration",
+ "value": "Contacts"
+ },
+ {
+ "action": "add",
+ "key": "eapCountry",
+ "namespace": "eapRegistration",
+ "value": "Country"
+ },
+ {
+ "action": "add",
+ "key": "eapCountryDescription",
+ "namespace": "eapRegistration",
+ "value": "The country will be pre-populated based on the NS selection, but can be adapted as needed."
+ },
+ {
+ "action": "add",
+ "key": "eapDevelopmentRegistrationDescription",
+ "namespace": "eapRegistration",
+ "value": "Thank you for notifying us about the start of your EAP process. We look forward to your completed application."
+ },
+ {
+ "action": "add",
+ "key": "eapDevelopmentRegistrationHeading",
+ "namespace": "eapRegistration",
+ "value": "EAP Development Registration"
+ },
+ {
+ "action": "add",
+ "key": "eapDisasterType",
+ "namespace": "eapRegistration",
+ "value": "Disaster Type"
+ },
+ {
+ "action": "add",
+ "key": "eapDisasterTypeDescription",
+ "namespace": "eapRegistration",
+ "value": "Select the disaster type for which the EAP is needed."
+ },
+ {
+ "action": "add",
+ "key": "eapFailedToLoad",
+ "namespace": "eapRegistration",
+ "value": "Failed to Load"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPoint",
+ "namespace": "eapRegistration",
+ "value": "DREF Focal Point"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPointDescription",
+ "namespace": "eapRegistration",
+ "value": "The DREF contact person form IFRC"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPointEmail",
+ "namespace": "eapRegistration",
+ "value": "Email"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPointName",
+ "namespace": "eapRegistration",
+ "value": "Name"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPointPhoneNumber",
+ "namespace": "eapRegistration",
+ "value": "Phone Number"
+ },
+ {
+ "action": "add",
+ "key": "eapFocalPointTitle",
+ "namespace": "eapRegistration",
+ "value": "Title"
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCContact",
+ "namespace": "eapRegistration",
+ "value": "IFRC Contact"
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCContactDescription",
+ "namespace": "eapRegistration",
+ "value": "The most senior staff in the National Society responsible and knowledgable about the disaster event."
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCEmail",
+ "namespace": "eapRegistration",
+ "value": "Email"
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCName",
+ "namespace": "eapRegistration",
+ "value": "Name"
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCPhoneNumber",
+ "namespace": "eapRegistration",
+ "value": "Phone Number"
+ },
+ {
+ "action": "add",
+ "key": "eapIFRCTitle",
+ "namespace": "eapRegistration",
+ "value": "Title"
+ },
+ {
+ "action": "add",
+ "key": "eapNationalSociety",
+ "namespace": "eapRegistration",
+ "value": "National Society (NS)"
+ },
+ {
+ "action": "add",
+ "key": "eapNationalSocietyDescription",
+ "namespace": "eapRegistration",
+ "value": "Select National Society that is planning to apply for the EAP"
+ },
+ {
+ "action": "add",
+ "key": "eapNotSure",
+ "namespace": "eapRegistration",
+ "value": "Not Sure"
+ },
+ {
+ "action": "add",
+ "key": "eapNSContact",
+ "namespace": "eapRegistration",
+ "value": "National Society Contact"
+ },
+ {
+ "action": "add",
+ "key": "eapNSContactDescription",
+ "namespace": "eapRegistration",
+ "value": "National Society contact responsible for the EAP process"
+ },
+ {
+ "action": "add",
+ "key": "eapNSEmail",
+ "namespace": "eapRegistration",
+ "value": "Email"
+ },
+ {
+ "action": "add",
+ "key": "eapNSName",
+ "namespace": "eapRegistration",
+ "value": "Name"
+ },
+ {
+ "action": "add",
+ "key": "eapNSPhoneNumber",
+ "namespace": "eapRegistration",
+ "value": "Phone Number"
+ },
+ {
+ "action": "add",
+ "key": "eapNSTitle",
+ "namespace": "eapRegistration",
+ "value": "Title"
+ },
+ {
+ "action": "add",
+ "key": "eapPartnersInvolved",
+ "namespace": "eapRegistration",
+ "value": "Partners Involved"
+ },
+ {
+ "action": "add",
+ "key": "eapPartnersInvolvedDescription",
+ "namespace": "eapRegistration",
+ "value": "Select from the list the partners involved in this process. Add as many as needed or select not applicable if no partners involved."
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationDescription",
+ "namespace": "eapRegistration",
+ "value": "Use the following page to submit your National Society's interest in following the Early Action Protocol (EAP) application process. Once you submit this form, the EAP team members will contact you to start the procedure. You can find more information on the process and different ways to apply {link}"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationFailure",
+ "namespace": "eapRegistration",
+ "value": "Sorry could not register new EAP right now!"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationFailureMessage",
+ "namespace": "eapRegistration",
+ "value": "Failed to update EAP Registration"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationHeading",
+ "namespace": "eapRegistration",
+ "value": "EAP Development Registration"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationLink",
+ "namespace": "eapRegistration",
+ "value": "on this page."
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationSuccess",
+ "namespace": "eapRegistration",
+ "value": "Successfully created a new EAP!"
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationUpdateMessage",
+ "namespace": "eapRegistration",
+ "value": "EAP Registration updated Successfully."
+ },
+ {
+ "action": "add",
+ "key": "eapSubmission",
+ "namespace": "eapRegistration",
+ "value": "Expected Time of Submission"
+ },
+ {
+ "action": "add",
+ "key": "eapSubmissionDescription",
+ "namespace": "eapRegistration",
+ "value": "Include the proposed time of submission, accounting for the time it will take to deliver the application."
+ },
+ {
+ "action": "add",
+ "key": "eapSubmitButton",
+ "namespace": "eapRegistration",
+ "value": "Submit"
+ },
+ {
+ "action": "add",
+ "key": "eapType",
+ "namespace": "eapRegistration",
+ "value": "EAP Type"
+ },
+ {
+ "action": "add",
+ "key": "eapTypeDescription",
+ "namespace": "eapRegistration",
+ "value": "Select the EAP type. Find details of both under this link."
+ },
+ {
+ "action": "add",
+ "key": "eapContent",
+ "namespace": "earlyActionProtocols",
+ "value": "What is an EAP?"
+ },
+ {
+ "action": "add",
+ "key": "eapContentHeading",
+ "namespace": "earlyActionProtocols",
+ "value": "Early Action Protocols (EAPs) are a core mechanism of the IFRC's Forecast-based Financing (FbF) approach, designed to ensure that humanitarian action happens before a disaster strikes, rather than only responding afterwards."
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingOne",
+ "namespace": "earlyActionProtocols",
+ "value": "An EAP is a pre-agreed plan developed by a Nation Society together with partners, which outlines:"
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingThree",
+ "namespace": "earlyActionProtocols",
+ "value": "What is the EAP Application Process?"
+ },
+ {
+ "action": "add",
+ "key": "eapContentSubHeadingTwo",
+ "namespace": "earlyActionProtocols",
+ "value": "Why are the EAPs Important?"
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionOne",
+ "namespace": "earlyActionProtocols",
+ "value": "The triggers (based on scientific forecasts and risk analysis) that indicate when a hazard is likely to impact communities."
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionThree",
+ "namespace": "earlyActionProtocols",
+ "value": "The roles, responsibilities, and budget required to carry out these actions quickly and effectively."
+ },
+ {
+ "action": "add",
+ "key": "eapDescriptionTwo",
+ "namespace": "earlyActionProtocols",
+ "value": "The early actions to be implemented once those triggers are met - practical, life-saving measures that reduce the impacts of the forecasted disaster."
+ },
+ {
+ "action": "add",
+ "key": "eapRegistrationLink",
+ "namespace": "earlyActionProtocols",
+ "value": "Register your EAP"
+ }
+ ]
+}
\ No newline at end of file
From 6c9791afec2df3443268a21e254c2927cc5e41b3 Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Tue, 18 Nov 2025 11:56:11 +0545
Subject: [PATCH 10/15] fix(eap): update eap section according to new UI
---
app/src/App/routes/index.tsx | 2 +-
.../EapTableActions/i18n.json | 0
.../EapTableActions/index.tsx | 4 +-
.../Filters/i18n.json | 0
.../Filters/index.tsx | 0
.../i18n.json | 0
.../index.tsx | 11 +-----
app/src/views/DrefDetail/index.tsx | 2 -
.../views/EapApplications/styles.module.css | 12 ------
app/src/views/EapRegistration/index.tsx | 38 +++++++++++--------
.../views/EapRegistration/styles.module.css | 23 ++---------
app/src/views/EarlyActionProtocols/index.tsx | 18 +++++----
.../EarlyActionProtocols/styles.module.css | 11 ------
13 files changed, 41 insertions(+), 80 deletions(-)
rename app/src/views/{EapApplications => AccountMyFormsEap}/EapTableActions/i18n.json (100%)
rename app/src/views/{EapApplications => AccountMyFormsEap}/EapTableActions/index.tsx (95%)
rename app/src/views/{EapApplications => AccountMyFormsEap}/Filters/i18n.json (100%)
rename app/src/views/{EapApplications => AccountMyFormsEap}/Filters/index.tsx (100%)
rename app/src/views/{EapApplications => AccountMyFormsEap}/i18n.json (100%)
rename app/src/views/{EapApplications => AccountMyFormsEap}/index.tsx (93%)
delete mode 100644 app/src/views/EapApplications/styles.module.css
delete mode 100644 app/src/views/EarlyActionProtocols/styles.module.css
diff --git a/app/src/App/routes/index.tsx b/app/src/App/routes/index.tsx
index 0fb0e0e86..799bcdf31 100644
--- a/app/src/App/routes/index.tsx
+++ b/app/src/App/routes/index.tsx
@@ -763,7 +763,7 @@ const accountMyFormsEap = customWrapRoute({
parent: accountMyFormsLayout,
path: 'eap-applications',
component: {
- render: () => import('#views/EapApplications'),
+ render: () => import('#views/AccountMyFormsEap'),
props: {},
},
context: {
diff --git a/app/src/views/EapApplications/EapTableActions/i18n.json b/app/src/views/AccountMyFormsEap/EapTableActions/i18n.json
similarity index 100%
rename from app/src/views/EapApplications/EapTableActions/i18n.json
rename to app/src/views/AccountMyFormsEap/EapTableActions/i18n.json
diff --git a/app/src/views/EapApplications/EapTableActions/index.tsx b/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
similarity index 95%
rename from app/src/views/EapApplications/EapTableActions/index.tsx
rename to app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
index 1294b0098..c3da79d9d 100644
--- a/app/src/views/EapApplications/EapTableActions/index.tsx
+++ b/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
@@ -41,14 +41,14 @@ function EapTableActions(props: Props) {
{strings.eapFormLink}
{strings.simplifiedEapLink}
diff --git a/app/src/views/EapApplications/Filters/i18n.json b/app/src/views/AccountMyFormsEap/Filters/i18n.json
similarity index 100%
rename from app/src/views/EapApplications/Filters/i18n.json
rename to app/src/views/AccountMyFormsEap/Filters/i18n.json
diff --git a/app/src/views/EapApplications/Filters/index.tsx b/app/src/views/AccountMyFormsEap/Filters/index.tsx
similarity index 100%
rename from app/src/views/EapApplications/Filters/index.tsx
rename to app/src/views/AccountMyFormsEap/Filters/index.tsx
diff --git a/app/src/views/EapApplications/i18n.json b/app/src/views/AccountMyFormsEap/i18n.json
similarity index 100%
rename from app/src/views/EapApplications/i18n.json
rename to app/src/views/AccountMyFormsEap/i18n.json
diff --git a/app/src/views/EapApplications/index.tsx b/app/src/views/AccountMyFormsEap/index.tsx
similarity index 93%
rename from app/src/views/EapApplications/index.tsx
rename to app/src/views/AccountMyFormsEap/index.tsx
index 7e92dea62..c22871e11 100644
--- a/app/src/views/EapApplications/index.tsx
+++ b/app/src/views/AccountMyFormsEap/index.tsx
@@ -36,7 +36,6 @@ import EapTableActions, { type Props as EapTableActionProps } from './EapTableAc
import Filters, { type FilterValue } from './Filters';
import i18n from './i18n.json';
-import styles from './styles.module.css';
type EapResponse = GoApiResponse<'/api/v2/eap-registration/'>;
type EapListItem = NonNullable[number];
@@ -108,7 +107,6 @@ export function Component() {
${item.disaster_type_details?.name}
${baseYear} - ${addedYear}`;
},
- { columnClassName: styles.title },
),
createStringColumn(
'eap_type_display',
@@ -119,7 +117,6 @@ export function Component() {
'status_display',
strings.eapStatus,
(item) => item.status_display,
- { columnClassName: styles.status },
),
createExpandColumn(
'expandRow',
@@ -147,7 +144,6 @@ export function Component() {
'title',
'',
() => strings.eapRegistration,
- { columnClassName: styles.detailTitle },
),
createEmptyColumn(),
createElementColumn(
@@ -180,7 +176,6 @@ export function Component() {
keySelector={numericIdSelector}
data={subRows}
columns={detailColumns}
- cellClassName={styles.subCell}
/>
>
);
@@ -194,7 +189,6 @@ export function Component() {
return (
0 && (
@@ -203,10 +197,10 @@ export function Component() {
onChange={setFilterField}
/>
)}
- actions={(
+ headerActions={(
{strings.eapRegistrationLink}
@@ -221,7 +215,6 @@ export function Component() {
)}
>
{eapId ? strings.eapBackButton : strings.eapCancelButton}
)}
+ elementRef={formContentRef}
withBackgroundColorInMainSection
>
-
-
+
+ {/* FIXME: label is not showing */}
+ {/* FIXME: label is not showing */}
-
-
+
+
+
-
-
+
+
{!isReadOnly && (
{strings.eapRegistrationLink}
@@ -52,10 +48,16 @@ export function Component() {
{/* TODO: Add remaining content */}
+ >
+ {/* TODO: Add real content and replace with strings */}
+ EAP content sub heading description two
+
+ >
+ {/* TODO: Add real content and replace with strings */}
+ EAP content sub heading description three
+
);
}
diff --git a/app/src/views/EarlyActionProtocols/styles.module.css b/app/src/views/EarlyActionProtocols/styles.module.css
deleted file mode 100644
index 4df12fe2b..000000000
--- a/app/src/views/EarlyActionProtocols/styles.module.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.eap-detail {
- display: flex;
- flex-direction: column;
- padding: var(--go-ui-spacing-2xl) 0;
-
- .content {
- display: flex;
- flex-direction: column;
- gap: var(--go-ui-spacing-lg);
- }
-}
From 39a46578549e783f6246a23754704d22a23123f2 Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Thu, 20 Nov 2025 12:17:16 +0545
Subject: [PATCH 11/15] fixup! fix(eap): update eap section according to new UI
---
.../EapTableActions/index.tsx | 6 +-
app/src/views/DrefDetail/index.tsx | 69 +++++++++--------
app/src/views/EapRegistration/index.tsx | 5 +-
app/src/views/EarlyActionProtocols/index.tsx | 74 ++++++++++---------
4 files changed, 86 insertions(+), 68 deletions(-)
diff --git a/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx b/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
index c3da79d9d..bf783af4c 100644
--- a/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
+++ b/app/src/views/AccountMyFormsEap/EapTableActions/index.tsx
@@ -41,14 +41,16 @@ function EapTableActions(props: Props) {
{strings.eapFormLink}
{strings.simplifiedEapLink}
diff --git a/app/src/views/DrefDetail/index.tsx b/app/src/views/DrefDetail/index.tsx
index 0087a2e53..cca8ac0f3 100644
--- a/app/src/views/DrefDetail/index.tsx
+++ b/app/src/views/DrefDetail/index.tsx
@@ -1,4 +1,7 @@
-import { Container } from '@ifrc-go/ui';
+import {
+ Container,
+ ListView,
+} from '@ifrc-go/ui';
import { useTranslation } from '@ifrc-go/ui/hooks';
import SurgeContentContainer from '#components/domain/SurgeContentContainer';
@@ -16,37 +19,41 @@ export function Component() {
-
- {strings.drefIntroDetailOne}
- {strings.drefIntroDetailTwo}
-
-
- {strings.drefProcessSubHeading}
-
- -
- {strings.drefProcessListOne}
-
- -
- {strings.drefProcessListTwo}
-
-
-
- {strings.drefProcessDetailOne}
-
-
- {strings.drefProcessDetailTwo}
-
-
-
- {strings.drefDrefApplication}
-
+
+ {strings.drefIntroDetailOne}
+ {strings.drefIntroDetailTwo}
+
+
+ {strings.drefProcessSubHeading}
+
+ -
+ {strings.drefProcessListOne}
+
+ -
+ {strings.drefProcessListTwo}
+
+
+
+ {strings.drefProcessDetailOne}
+
+
+ {strings.drefProcessDetailTwo}
+
+
+
+ {strings.drefDrefApplication}
+
+
);
}
diff --git a/app/src/views/EapRegistration/index.tsx b/app/src/views/EapRegistration/index.tsx
index 613220f00..4d3a6f2ec 100644
--- a/app/src/views/EapRegistration/index.tsx
+++ b/app/src/views/EapRegistration/index.tsx
@@ -278,7 +278,8 @@ export function Component() {
actions={(
{eapId ? strings.eapBackButton : strings.eapCancelButton}
@@ -354,6 +355,8 @@ export function Component() {
{/* FIXME: label is not showing */}
{strings.eapRegistrationLink}
)}
>
-
-
- {strings.eapContentHeading}
-
-
- {strings.eapContentSubHeadingOne}
-
- -
- {strings.eapDescriptionOne}
-
- -
- {strings.eapDescriptionTwo}
-
- -
- {strings.eapDescriptionThree}
-
-
-
-
- {/* TODO: Add remaining content */}
-
- {/* TODO: Add real content and replace with strings */}
- EAP content sub heading description two
-
-
- {/* TODO: Add real content and replace with strings */}
- EAP content sub heading description three
-
+
+
+ {strings.eapContentHeading}
+
+
+ {strings.eapContentSubHeadingOne}
+
+ -
+ {strings.eapDescriptionOne}
+
+ -
+ {strings.eapDescriptionTwo}
+
+ -
+ {strings.eapDescriptionThree}
+
+
+
+
+ {/* TODO: Add remaining content */}
+
+ {/* TODO: Add real content and replace with strings */}
+ EAP content sub heading description two
+
+
+ {/* TODO: Add real content and replace with strings */}
+ EAP content sub heading description three
+
+
);
}
From 41eabdb389d2bf4849b058c1e8ff64b7f3cbe10b Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Thu, 20 Nov 2025 12:26:39 +0545
Subject: [PATCH 12/15] fixup! fix(eap): update eap section according to new UI
---
app/src/views/DrefDetail/index.tsx | 5 +----
app/src/views/DrefDetail/styles.module.css | 11 -----------
2 files changed, 1 insertion(+), 15 deletions(-)
delete mode 100644 app/src/views/DrefDetail/styles.module.css
diff --git a/app/src/views/DrefDetail/index.tsx b/app/src/views/DrefDetail/index.tsx
index cca8ac0f3..c43f6f350 100644
--- a/app/src/views/DrefDetail/index.tsx
+++ b/app/src/views/DrefDetail/index.tsx
@@ -8,7 +8,6 @@ import SurgeContentContainer from '#components/domain/SurgeContentContainer';
import Link from '#components/Link';
import i18n from './i18n.json';
-import styles from './styles.module.css';
/** @knipignore */
// eslint-disable-next-line import/prefer-default-export
@@ -16,9 +15,7 @@ export function Component() {
const strings = useTranslation(i18n);
return (
-
+
diff --git a/app/src/views/DrefDetail/styles.module.css b/app/src/views/DrefDetail/styles.module.css
deleted file mode 100644
index c850c0ee2..000000000
--- a/app/src/views/DrefDetail/styles.module.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.dref-detail {
- display: flex;
- flex-direction: column;
- padding: var(--go-ui-spacing-2xl) 0;
-
- .content {
- display: flex;
- flex-direction: column;
- gap: var(--go-ui-spacing-xl);
- }
-}
From b35db56b660fb98a303d8ae98f2f96dc2ecc36cf Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Thu, 20 Nov 2025 14:20:20 +0545
Subject: [PATCH 13/15] fixup! fix(eap): update eap section according to new UI
---
app/src/views/AccountMyFormsEap/index.tsx | 3 ++-
app/src/views/DrefDetail/index.tsx | 2 +-
app/src/views/EapRegistration/index.tsx | 3 ++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/app/src/views/AccountMyFormsEap/index.tsx b/app/src/views/AccountMyFormsEap/index.tsx
index c22871e11..35a643200 100644
--- a/app/src/views/AccountMyFormsEap/index.tsx
+++ b/app/src/views/AccountMyFormsEap/index.tsx
@@ -200,7 +200,8 @@ export function Component() {
headerActions={(
{strings.eapRegistrationLink}
diff --git a/app/src/views/DrefDetail/index.tsx b/app/src/views/DrefDetail/index.tsx
index c43f6f350..33869faf0 100644
--- a/app/src/views/DrefDetail/index.tsx
+++ b/app/src/views/DrefDetail/index.tsx
@@ -15,7 +15,7 @@ export function Component() {
const strings = useTranslation(i18n);
return (
-
+
diff --git a/app/src/views/EapRegistration/index.tsx b/app/src/views/EapRegistration/index.tsx
index 4d3a6f2ec..16d65dc60 100644
--- a/app/src/views/EapRegistration/index.tsx
+++ b/app/src/views/EapRegistration/index.tsx
@@ -289,7 +289,6 @@ export function Component() {
>
Date: Tue, 18 Nov 2025 12:17:05 +0545
Subject: [PATCH 14/15] feat(eap): create timespan component
---
app/src/components/TimespanInput/i18n.json | 7 ++
app/src/components/TimespanInput/index.tsx | 128 +++++++++++++++++++++
app/src/views/EapRegistration/index.tsx | 9 ++
3 files changed, 144 insertions(+)
create mode 100644 app/src/components/TimespanInput/i18n.json
create mode 100644 app/src/components/TimespanInput/index.tsx
diff --git a/app/src/components/TimespanInput/i18n.json b/app/src/components/TimespanInput/i18n.json
new file mode 100644
index 000000000..31ffd8985
--- /dev/null
+++ b/app/src/components/TimespanInput/i18n.json
@@ -0,0 +1,7 @@
+{
+ "namespace": "common",
+ "strings": {
+ "timeframeLabel": "Timeframe",
+ "timespanLabel": "Time Span"
+ }
+}
diff --git a/app/src/components/TimespanInput/index.tsx b/app/src/components/TimespanInput/index.tsx
new file mode 100644
index 000000000..1852473d0
--- /dev/null
+++ b/app/src/components/TimespanInput/index.tsx
@@ -0,0 +1,128 @@
+import { useMemo } from 'react';
+import {
+ Checklist,
+ SelectInput,
+} from '@ifrc-go/ui';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import { stringValueSelector } from '@ifrc-go/ui/utils';
+import { isNotDefined } from '@togglecorp/fujs';
+
+import i18n from './i18n.json';
+
+type Timeframe = 'hours' | 'days' | 'months' | 'years';
+
+type TimeframeOptions = {
+ key: Timeframe,
+ value: string,
+}
+
+type TimespanOptions = {
+ key: number,
+ value: string,
+}
+
+const timeframeOptions: TimeframeOptions[] = [
+ {
+ key: 'hours',
+ value: 'Hours',
+ },
+ {
+ key: 'days',
+ value: 'Days',
+ },
+ {
+ key: 'months',
+ value: 'Months',
+ },
+ {
+ key: 'years',
+ value: 'Years',
+ },
+];
+
+function createTimespanOptions(range: number[]): TimespanOptions[] {
+ return range.map((num) => ({
+ key: num,
+ value: String(num),
+ }));
+}
+
+const timespanOptionsMap: Record = {
+ hours: createTimespanOptions(Array.from({ length: 25 }, (_, i) => i)),
+ days: createTimespanOptions(Array.from({ length: 31 }, (_, i) => i + 1)),
+ months: createTimespanOptions(Array.from({ length: 12 }, (_, i) => i + 1)),
+ years: createTimespanOptions(Array.from({ length: 10 }, (_, i) => i + 1)),
+};
+
+function timeframeKeySelector(option: TimeframeOptions) {
+ return option.key;
+}
+
+function timeSpanKeySelector(option: TimespanOptions) {
+ return option.key;
+}
+
+export interface TimespanInputValue {
+ timeframe?: Timeframe;
+ timespan?: number[];
+}
+
+export interface Props {
+ value?: TimespanInputValue;
+ onChange: (value: TimespanInputValue) => void;
+}
+
+function TimespanInput(props: Props) {
+ const {
+ value,
+ onChange,
+ } = props;
+
+ const strings = useTranslation(i18n);
+
+ const timespanOptions = useMemo(() => {
+ if (isNotDefined(value?.timeframe)) {
+ return undefined;
+ }
+ return timespanOptionsMap[value?.timeframe];
+ }, [value?.timeframe]);
+
+ const handleTimeframeChange = (newTimeframe: Timeframe | undefined) => {
+ onChange({
+ ...value,
+ timeframe: newTimeframe ?? 'months',
+ });
+ };
+
+ const handleTimespanChange = (newTimespan: number[] | undefined) => {
+ onChange({
+ ...value,
+ timespan: newTimespan,
+ });
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+}
+
+export default TimespanInput;
diff --git a/app/src/views/EapRegistration/index.tsx b/app/src/views/EapRegistration/index.tsx
index 16d65dc60..102a82eb6 100644
--- a/app/src/views/EapRegistration/index.tsx
+++ b/app/src/views/EapRegistration/index.tsx
@@ -2,6 +2,7 @@ import {
type ElementRef,
useCallback,
useRef,
+ useState,
} from 'react';
import {
useLocation,
@@ -40,6 +41,7 @@ import NationalSocietyMultiSelectInput from '#components/domain/NationalSocietyM
import NationalSocietySelectInput from '#components/domain/NationalSocietySelectInput';
import Link from '#components/Link';
import Page from '#components/Page';
+import TimespanInput, { type TimespanInputValue } from '#components/TimespanInput';
import useGlobalEnums from '#hooks/domain/useGlobalEnums';
import useAlert from '#hooks/useAlert';
import useRouting from '#hooks/useRouting';
@@ -75,6 +77,8 @@ export function Component() {
const { navigate } = useRouting();
const { eapId: eapIdFromParams } = useParams<{ eapId: string }>();
+ const [timespanValue, setTimespanValue] = useState();
+
const { state } = useLocation();
const eapId = eapIdFromParams ?? state?.eapId as string | undefined;
const isReadOnly = state?.mode === 'view';
@@ -532,6 +536,11 @@ export function Component() {
disabled={disabled}
readOnly={isReadOnly}
/>
+ {/* NOTE: Just for testing purpose */}
+
From 1251d9f0cb733cbc75a5335bc60c3f8998433835 Mon Sep 17 00:00:00 2001
From: Shreeyash Shrestha
Date: Thu, 20 Nov 2025 15:09:21 +0545
Subject: [PATCH 15/15] fixup! feat(eap): create timespan component
---
app/src/components/TimespanInput/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/components/TimespanInput/index.tsx b/app/src/components/TimespanInput/index.tsx
index 1852473d0..982761813 100644
--- a/app/src/components/TimespanInput/index.tsx
+++ b/app/src/components/TimespanInput/index.tsx
@@ -67,7 +67,7 @@ export interface TimespanInputValue {
timespan?: number[];
}
-export interface Props {
+interface Props {
value?: TimespanInputValue;
onChange: (value: TimespanInputValue) => void;
}