['alerts']>['items']>[number];
+
+export interface Props {
+ data: AlertType;
+}
+function AlertActions(props: Props) {
+ const { data } = props;
+ const strings = useTranslation(i18n);
+ const alert = useAlert();
+
+ const url = generatePath(
+ routes.alertDetails.absolutePath,
+ { alertId: data.id },
+ );
+
+ const handleClick = useCallback(() => {
+ navigator.clipboard.writeText(`${window.location.origin}${url}`);
+ alert.show('Link copied to clipboard');
+ }, [url, alert]);
+
+ return (
+
+
+ {strings.alertTableViewDetailsTitle}
+
+
+
+ );
+}
+
+export default AlertActions;
diff --git a/src/views/HistoricalAlerts/AlertActions/styles.module.css b/src/views/HistoricalAlerts/AlertActions/styles.module.css
new file mode 100644
index 0000000..39705f6
--- /dev/null
+++ b/src/views/HistoricalAlerts/AlertActions/styles.module.css
@@ -0,0 +1,6 @@
+.alert-actions{
+ display: flex;
+ gap: var(--go-ui-spacing-sm);
+}
+
+
diff --git a/src/views/HistoricalAlerts/i18n.json b/src/views/HistoricalAlerts/i18n.json
new file mode 100644
index 0000000..a1027bf
--- /dev/null
+++ b/src/views/HistoricalAlerts/i18n.json
@@ -0,0 +1,33 @@
+{
+ "namespace": "historicalAlerts",
+ "strings": {
+ "allOngoingAlertTitle":"Past 3 Months Alerts ({numAppeals}) ",
+ "historicalAlertTableEventTitle":"Event" ,
+ "historicalAlertTableCategoryTitle":"Event Categories",
+ "historicalAlertTableRegionTitle":"Region",
+ "historicalAlertTableCountryTitle":"Country",
+ "historicalAlertTableActionsTitle":"Actions",
+ "historicalAlertTableAdminsTitle":"Admin1s",
+ "historicalAlertTableSentLabel":"Sent",
+ "tableViewAllSources": "View All Sources",
+ "historicalAlertTitle": "IFRC Alert Hub - Historical Alerts",
+ "historicalAlert": "Historical Alerts",
+ "filterCountriesPlaceholder": "All Countries",
+ "filterAdmin1Placeholder": "All Admin1",
+ "filterUrgencyPlaceholder": "All Urgency Types",
+ "filterSeverityPlaceholder": "All Severity Types",
+ "filterCertaintyPlaceholder": "All Certainty Types",
+ "filterCountriesLabel": "Country",
+ "filterAdmin1Label": "Admin1",
+ "filterUrgencyLabel": "Urgency Level",
+ "filterSeverityLabel": "Severity Level",
+ "filterCertaintyLabel": "Certainty Level",
+ "filterRegionsLabel": "Regions",
+ "filterRegionsPlaceholder": "All Regions",
+ "filterCategoriesLabel": "Event Categories",
+ "filterCategoriesPlaceholder": "All Event Categories",
+ "filterStartDateFrom":"Start date from",
+ "filterStartDateTo":"Start date To",
+ "historicalAlertDescription": "IFRC Alert Hub provides global emergency alerts, empowering communities to protect lives and livelihoods. Easily access and filter past alerts from the latest months to stay informed."
+ }
+}
diff --git a/src/views/HistoricalAlerts/index.tsx b/src/views/HistoricalAlerts/index.tsx
new file mode 100644
index 0000000..32dad1f
--- /dev/null
+++ b/src/views/HistoricalAlerts/index.tsx
@@ -0,0 +1,495 @@
+import {
+ ComponentType,
+ HTMLProps,
+ useCallback,
+ useMemo,
+} from 'react';
+import {
+ gql,
+ useQuery,
+} from '@apollo/client';
+import { ChevronRightLineIcon } from '@ifrc-go/icons';
+import {
+ Container,
+ DateInput,
+ DateOutput,
+ DateOutputProps,
+ MultiSelectInput,
+ Pager,
+ SelectInput,
+ Table,
+} from '@ifrc-go/ui';
+import { SortContext } from '@ifrc-go/ui/contexts';
+import { useTranslation } from '@ifrc-go/ui/hooks';
+import {
+ createElementColumn,
+ createListDisplayColumn,
+ createStringColumn,
+ resolveToString,
+} from '@ifrc-go/ui/utils';
+import {
+ isDefined,
+ isNotDefined,
+} from '@togglecorp/fujs';
+
+import Link from '#components/Link';
+import Page from '#components/Page';
+import {
+ AlertEnumsAndAllCountryListQuery,
+ AlertEnumsAndAllCountryListQueryVariables,
+ AlertEnumsQuery,
+ AlertFilter,
+ AlertInformationsQuery,
+ AlertInformationsQueryVariables,
+ FilteredAdminListQuery,
+ FilteredAdminListQueryVariables,
+ OffsetPaginationInput,
+} from '#generated/types/graphql';
+import useFilterState from '#hooks/useFilterState';
+import { DATE_FORMAT } from '#utils/constants';
+import {
+ stringIdSelector,
+ stringNameSelector,
+} from '#utils/selectors';
+import AlertFilters from '#views/Home/AlertFilters';
+
+import AlertActions, { type Props as AlertActionsProps } from './AlertActions';
+
+import i18n from './i18n.json';
+import styles from './styles.module.css';
+
+// TODO: Add Historical alert query here
+
+const ALERT_INFORMATIONS = gql`
+ query AlertInformations(
+ $order:AlertOrder,
+ $pagination: OffsetPaginationInput,
+ $filters: AlertFilter,
+ ) {
+ public {
+ id
+ alerts(
+ pagination: $pagination,
+ filters: $filters,
+ order:$order,
+ ) {
+ limit
+ offset
+ count
+ items {
+ id
+ country {
+ id
+ name
+ region {
+ id
+ name
+ }
+ }
+ admin1s {
+ id
+ name
+ }
+ sent
+ info {
+ id
+ event
+ alertId
+ categoryDisplay
+ }
+ }
+ }
+ }
+ }
+`;
+
+const ALERT_ENUMS_AND_ALL_COUNTRY = gql`
+query AlertEnumsAndAllCountryList {
+ enums {
+ AlertInfoCertainty {
+ key
+ label
+ }
+ AlertInfoUrgency {
+ key
+ label
+ }
+ AlertInfoSeverity {
+ key
+ label
+ }
+ AlertInfoCategory {
+ key
+ label
+ }
+ }
+ public {
+ id
+ allCountries {
+ name
+ id
+ }
+ }
+}
+`;
+
+const ADMIN_LIST = gql`
+query FilteredAdminList($filters:Admin1Filter, $pagination: OffsetPaginationInput) {
+ public {
+ id
+ admin1s(filters: $filters, pagination: $pagination) {
+ items {
+ id
+ name
+ countryId
+ alertCount
+ }
+ }
+ }
+}
+`;
+
+type AdminOption = NonNullable['admin1s']>['items']>[number];
+
+type Urgency = NonNullable[number];
+type Severity = NonNullable[number];
+type Certainty = NonNullable[number];
+type Category = NonNullable[number];
+
+type AlertType = NonNullable['alerts']>['items']>[number];
+type Admin1 = AlertType['admin1s'][number];
+
+const adminKeySelector = (admin1: AdminOption) => admin1.id;
+const urgencyKeySelector = (urgency: Urgency) => urgency.key;
+const severityKeySelector = (severity: Severity) => severity.key;
+const certaintyKeySelector = (certainty: Certainty) => certainty.key;
+const labelSelector = (alert: AlertFilters) => alert.label;
+const categoryKeySelector = (category: Category) => category.key;
+
+const alertKeySelector = (item: AlertType) => item.id;
+const PAGE_SIZE = 20;
+const ASC = 'ASC';
+const DESC = 'DESC';
+
+// eslint-disable-next-line import/prefer-default-export
+export function Component() {
+ const strings = useTranslation(i18n);
+
+ const {
+ sortState,
+ limit,
+ page,
+ rawFilter,
+ setPage,
+ filter,
+ setFilterField,
+ filtered,
+ offset,
+ } = useFilterState({
+ pageSize: PAGE_SIZE,
+ filter: {},
+ });
+
+ const order = useMemo(() => {
+ if (isNotDefined(sortState.sorting)) {
+ return undefined;
+ }
+ return {
+ [sortState.sorting.name]: sortState.sorting.direction === 'asc' ? ASC : DESC,
+ };
+ }, [sortState.sorting]);
+
+ const variables = useMemo<{ filters: AlertFilter, pagination: OffsetPaginationInput }>(() => ({
+ pagination: {
+ offset,
+ limit,
+ },
+ order,
+ filters: {
+ urgency: filter.urgency,
+ severity: filter.severity,
+ certainty: filter.certainty,
+ category: filter.category,
+ country: isDefined(filter.country?.pk) ? { pk: filter.country.pk } : undefined,
+ admin1: filter.admin1,
+ sent: isDefined(filter.sent) ? {
+ // TODO: Add start date & end date
+ range: {
+ end: filter.sent,
+ start: filter.sent,
+ },
+ } : undefined,
+ },
+ }), [
+ order,
+ limit,
+ offset,
+ filter,
+ ]);
+
+ const {
+ loading: alertInfoLoading,
+ previousData,
+ data: alertInfosResponse = previousData,
+ error: alertInfoError,
+ } = useQuery(
+ ALERT_INFORMATIONS,
+ {
+ skip: isNotDefined(variables),
+ variables,
+ },
+ );
+
+ const {
+ data: alertEnumsResponse,
+ } = useQuery(
+ ALERT_ENUMS_AND_ALL_COUNTRY,
+ );
+
+ const adminQueryVariables = useMemo(
+ () => {
+ if (isNotDefined(filter.country)) {
+ return {
+ filters: undefined,
+ // FIXME: Implement search select input
+ pagination: {
+ offset: 0,
+ limit: 500,
+ },
+ };
+ }
+
+ return {
+ filters: {
+ country: { pk: filter.country.pk },
+ },
+ // FIXME: Implement search select input
+ pagination: {
+ offset: 0,
+ limit: 500,
+ },
+ };
+ },
+ [filter.country],
+ );
+
+ const {
+ data: adminResponse,
+ } = useQuery(
+ ADMIN_LIST,
+ { variables: adminQueryVariables, skip: isNotDefined(filter.country) },
+ );
+
+ const data = alertInfosResponse?.public.alerts;
+
+ const columns = useMemo(
+ () => ([
+ createStringColumn(
+ 'event',
+ strings.historicalAlertTableEventTitle,
+ (item) => item.info?.event,
+ { columnClassName: styles.event },
+ ),
+ createStringColumn(
+ 'category',
+ strings.historicalAlertTableCategoryTitle,
+ (item) => item.info?.categoryDisplay,
+ { columnClassName: styles.category },
+ ),
+ createStringColumn(
+ 'region',
+ strings.historicalAlertTableRegionTitle,
+ (item) => (item.country.region.name),
+ { columnClassName: styles.region },
+
+ ),
+ createStringColumn(
+ 'country',
+ strings.historicalAlertTableCountryTitle,
+ (item) => (item.country.name),
+ { columnClassName: styles.country },
+ ),
+ createListDisplayColumn>(
+ 'admin1s',
+ strings.historicalAlertTableAdminsTitle,
+ (item) => ({
+ list: item.admin1s,
+ keySelector: ({ id }) => id,
+ renderer: 'span' as unknown as ComponentType>,
+ rendererParams: ({ name }) => ({ children: name }),
+ }),
+ { columnClassName: styles.admins },
+ ),
+ createElementColumn(
+ 'sent',
+ strings.historicalAlertTableSentLabel,
+ DateOutput,
+ (_, item) => ({
+ value: item.sent,
+ format: DATE_FORMAT,
+ }),
+ {
+ sortable: true,
+ columnClassName: styles.sent,
+ },
+ ),
+ createElementColumn(
+ 'actions',
+ strings.historicalAlertTableActionsTitle,
+ AlertActions,
+ (_, item) => ({ data: item }),
+ {
+ columnClassName: styles.actions,
+ cellRendererClassName: styles.actions,
+ },
+ ),
+ ]),
+ [
+ strings.historicalAlertTableEventTitle,
+ strings.historicalAlertTableCategoryTitle,
+ strings.historicalAlertTableRegionTitle,
+ strings.historicalAlertTableCountryTitle,
+ strings.historicalAlertTableAdminsTitle,
+ strings.historicalAlertTableSentLabel,
+ strings.historicalAlertTableActionsTitle,
+ ],
+ );
+ const heading = resolveToString(
+ strings.allOngoingAlertTitle,
+ { numAppeals: data?.count ?? '--' },
+ );
+
+ const handleCountryFilterChange = useCallback((countryId: string | undefined) => {
+ setFilterField(countryId ? { pk: countryId } : undefined, 'country');
+ }, [setFilterField]);
+
+ return (
+
+
+ )}
+ >
+ {strings.tableViewAllSources}
+
+ )}
+ overlayPending
+ pending={alertInfoLoading}
+ errored={isDefined(alertInfoError)}
+ errorMessage={alertInfoError?.message}
+ footerActions={isDefined(data) && (
+
+ )}
+ filters={(
+ <>
+
+
+
+
+ {/* // TODO Add start date and end date filter */}
+ { }}
+ />
+ { }}
+ />
+
+
+ >
+ )}
+ >
+
+
+
+
+
+ );
+}
+
+Component.displayName = 'HistoricalAlerts';
diff --git a/src/views/HistoricalAlerts/styles.module.css b/src/views/HistoricalAlerts/styles.module.css
new file mode 100644
index 0000000..2b1da9d
--- /dev/null
+++ b/src/views/HistoricalAlerts/styles.module.css
@@ -0,0 +1,68 @@
+.historical-alerts {
+ .alerts-table {
+ overflow: auto;
+
+ .alert-info {
+ display: flex;
+ align-items: flex-end;
+
+ .alert-icon {
+ font-size: var(--go-ui-font-size-md);
+ }
+ }
+
+ .main-content {
+ flex-grow: 1;
+ overflow: auto;
+ }
+
+ .event {
+ width: 0%;
+ min-width: 8rem;
+ }
+
+ .category {
+ width: 0%;
+ min-width: 5rem;
+ }
+
+ .region {
+ width: 0%;
+ min-width: 7rem;
+ }
+
+ .country {
+ width: 0%;
+ min-width: 8rem;
+ }
+
+ .admins {
+ min-width: 14rem;
+ }
+
+ .sent {
+ width: 0;
+ min-width: 7rem;
+ }
+
+ .actions {
+ width: 0;
+ min-width: 10rem;
+ color: var(--go-ui-color-text);
+ font-weight: var(--go-ui-font-weight-medium);
+ }
+
+ .sources {
+ display: flex;
+ align-items: center;
+ text-decoration: none;
+ color: var(--go-ui-color-text);
+ font-weight: var(--go-ui-font-weight-medium);
+ }
+
+ .sources:hover {
+ text-decoration: underline;
+ color: var(--go-ui-color-primary-red);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/views/MySubscription/index.tsx b/src/views/MySubscription/index.tsx
index 96131d9..1bab16b 100644
--- a/src/views/MySubscription/index.tsx
+++ b/src/views/MySubscription/index.tsx
@@ -113,12 +113,11 @@ export function Component() {
)}
>
- {showSubscriptionModal && data?.map((subscription) => (
+ {showSubscriptionModal && (
- ))}
+ )}
void;
}