Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscription page integration #175

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend
Submodule backend updated 39 files
+1 −0 .github/workflows/helm-publish.yml
+1 −0 apps/cap_feed/admin.py
+22 −2 apps/cap_feed/dataloaders.py
+71 −0 apps/cap_feed/factories.py
+28 −33 apps/cap_feed/filters.py
+18 −0 apps/cap_feed/migrations/0009_alert_is_processed_by_subscription.py
+22 −0 apps/cap_feed/migrations/0010_alter_alert_is_processed_by_subscription_and_more.py
+33 −0 apps/cap_feed/migrations/0011_alter_alertinfo_category_alter_alertinfo_certainty_and_more.py
+13 −5 apps/cap_feed/models.py
+24 −1 apps/cap_feed/queries.py
+1 −1 apps/cap_feed/types.py
+92 −0 apps/subscription/emails.py
+8 −15 apps/subscription/enums.py
+16 −0 apps/subscription/factories.py
+51 −0 apps/subscription/migrations/0002_remove_useralertsubscription_alert_filters_and_more.py
+18 −0 apps/subscription/migrations/0003_alter_useralertsubscription_is_active.py
+20 −6 apps/subscription/models.py
+54 −5 apps/subscription/mutations.py
+8 −3 apps/subscription/queries.py
+57 −26 apps/subscription/serializers.py
+113 −0 apps/subscription/tasks.py
+0 −0 apps/subscription/tests/__init__.py
+554 −0 apps/subscription/tests/test_mutations.py
+0 −0 apps/subscription/tests/test_queries.py
+56 −0 apps/subscription/tests/test_subscription_alert_tagging.py
+35 −3 apps/subscription/types.py
+36 −0 apps/subscription/views.py
+1 −0 apps/user/models.py
+0 −33 apps/user/views.py
+2 −0 main/cache.py
+10 −0 main/celery.py
+4 −0 main/permalinks.py
+1 −0 main/settings.py
+10 −0 main/tokens.py
+12 −3 main/urls.py
+35 −30 schema.graphql
+26 −0 templates/emails/subscription/body.html
+0 −0 templates/emails/subscription/body.txt
+3 −3 utils/strawberry/transformers.py
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@graphql-codegen/typescript-operations": "^4.2.0",
"@hcaptcha/react-hcaptcha": "^1.11.0",
"@ifrc-go/icons": "^1.3.3",
"@ifrc-go/ui": "^1.1.2",
"@ifrc-go/ui": "^1.2.1",
"@mapbox/mapbox-gl-draw": "^1.4.3",
"@placemarkio/geo-viewport": "^1.0.2",
"@sentry/react": "^7.81.1",
Expand Down
21 changes: 0 additions & 21 deletions src/components/Badge/index.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions src/components/Badge/styles.module.css

This file was deleted.

1 change: 0 additions & 1 deletion src/views/AlertDetails/AlertInfo/AreaInfoDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ function AreaInfoDetail(props: Props) {
onChange={setSelectedFeature}
/>
)}
withGridViewInFilter
headingLevel={4}
>
<div className={styles.map}>
Expand Down
1 change: 0 additions & 1 deletion src/views/AllSourcesFeeds/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export function Component() {
heading={strings.sourceFeedsTitle}
>
<Container
withGridViewInFilter
filters={(
<TextInput
placeholder={strings.searchSourcesPlaceholder}
Expand Down
2 changes: 2 additions & 0 deletions src/views/HistoricalAlerts/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"filterCategoriesPlaceholder": "All Event Categories",
"filterStartDateFrom":"Start date from",
"filterStartDateTo":"Start date To",
"filterApply": "Apply",
"filterClear": "Clear",
"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."
}
}
124 changes: 74 additions & 50 deletions src/views/HistoricalAlerts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import {
HTMLProps,
useCallback,
useMemo,
useState,
} from 'react';
import {
gql,
useQuery,
} from '@apollo/client';
import { ChevronRightLineIcon } from '@ifrc-go/icons';
import {
Button,
Container,
DateInput,
DateOutput,
Expand Down Expand Up @@ -39,10 +41,10 @@ import {
AlertEnumsAndAllCountryListQueryVariables,
AlertEnumsQuery,
AlertFilter,
AlertInformationsQuery,
AlertInformationsQueryVariables,
FilteredAdminListQuery,
FilteredAdminListQueryVariables,
HistoricalAlertInformationsQuery,
HistoricalAlertInformationsQueryVariables,
OffsetPaginationInput,
} from '#generated/types/graphql';
import useFilterState from '#hooks/useFilterState';
Expand All @@ -58,20 +60,16 @@ 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,
const HISTORICAL_ALERT_INFORMATIONS = gql`
query HistoricalAlertInformations(
$pagination: OffsetPaginationInput,
$filters: AlertFilter,
) {
public {
id
alerts(
historicalAlerts(
pagination: $pagination,
filters: $filters,
order:$order,
) {
limit
offset
Expand Down Expand Up @@ -156,7 +154,7 @@ type Severity = NonNullable<AlertEnumsQuery['enums']['AlertInfoSeverity']>[numbe
type Certainty = NonNullable<AlertEnumsQuery['enums']['AlertInfoCertainty']>[number];
type Category = NonNullable<AlertEnumsQuery['enums']['AlertInfoCategory']>[number];

type AlertType = NonNullable<NonNullable<NonNullable<AlertInformationsQuery['public']>['alerts']>['items']>[number];
type AlertType = NonNullable<NonNullable<NonNullable<HistoricalAlertInformationsQuery['public']>['historicalAlerts']>['items']>[number];
type Admin1 = AlertType['admin1s'][number];

const adminKeySelector = (admin1: AdminOption) => admin1.id;
Expand All @@ -168,13 +166,18 @@ const categoryKeySelector = (category: Category) => category.key;

const alertKeySelector = (item: AlertType) => item.id;
const PAGE_SIZE = 20;
const ASC = 'ASC';
const DESC = 'DESC';

type NewFilter = Omit<AlertFilter, 'infos'> & AlertFilter['infos'] & {
startDateAfter?: string;
startDateBefore?: string;
};

// eslint-disable-next-line import/prefer-default-export
export function Component() {
const strings = useTranslation(i18n);

const [finalFilter, setFinalFilter] = useState<NewFilter | undefined>();

const {
sortState,
limit,
Expand All @@ -185,55 +188,62 @@ export function Component() {
setFilterField,
filtered,
offset,
} = useFilterState<AlertFilter>({
setFilter,
} = useFilterState<NewFilter>({
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 }>(() => ({
const variables = useMemo<{
filters: AlertFilter | undefined,
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
filters: finalFilter ? {
DISTINCT: true,
infos: {
urgency: finalFilter?.urgency,
severity: finalFilter?.severity,
certainty: finalFilter?.certainty,
category: finalFilter?.category,
},
country: isDefined(finalFilter?.country?.pk)
? { pk: finalFilter.country.pk } : undefined,
admin1: finalFilter?.admin1,
sent: {
range: {
end: filter.sent,
start: filter.sent,
end: finalFilter?.startDateBefore,
start: finalFilter?.startDateAfter,
},
} : undefined,
},
},
} : undefined,
}), [
order,
limit,
offset,
filter,
finalFilter,
]);

const handleApplyFilters = useCallback(() => {
setFinalFilter(rawFilter);
}, [
rawFilter,
]);

const handleResetFilters = useCallback(() => {
setFinalFilter(undefined);
setFilter({});
}, [setFilter]);

const {
loading: alertInfoLoading,
previousData,
data: alertInfosResponse = previousData,
error: alertInfoError,
} = useQuery<AlertInformationsQuery, AlertInformationsQueryVariables>(
ALERT_INFORMATIONS,
} = useQuery<HistoricalAlertInformationsQuery, HistoricalAlertInformationsQueryVariables>(
HISTORICAL_ALERT_INFORMATIONS,
{
skip: isNotDefined(variables),
variables,
Expand Down Expand Up @@ -280,7 +290,7 @@ export function Component() {
{ variables: adminQueryVariables, skip: isNotDefined(filter.country) },
);

const data = alertInfosResponse?.public.alerts;
const data = alertInfosResponse?.public.historicalAlerts;

const columns = useMemo(
() => ([
Expand Down Expand Up @@ -374,7 +384,6 @@ export function Component() {
className={styles.alertsTable}
heading={heading}
withHeaderBorder
withGridViewInFilter
actions={(
<Link
className={styles.sources}
Expand Down Expand Up @@ -440,18 +449,17 @@ export function Component() {
value={rawFilter.category}
onChange={setFilterField}
/>
{/* // TODO Add start date and end date filter */}
<DateInput
name="sent"
name="startDateAfter"
label={strings.filterStartDateFrom}
value={undefined}
onChange={() => { }}
value={rawFilter.startDateAfter}
onChange={setFilterField}
/>
<DateInput
name="sent"
name="startDateBefore"
label={strings.filterStartDateTo}
value={undefined}
onChange={() => { }}
value={rawFilter.startDateBefore}
onChange={setFilterField}
/>
<SelectInput
label={strings.filterCountriesLabel}
Expand All @@ -474,6 +482,22 @@ export function Component() {
value={rawFilter.admin1}
onChange={setFilterField}
/>
<div className={styles.filterButton}>
<Button
name={undefined}
onClick={handleApplyFilters}
variant="secondary"
>
{strings.filterApply}
</Button>
<Button
name={undefined}
onClick={handleResetFilters}
variant="secondary"
>
{strings.filterClear}
</Button>
</div>
</>
)}
>
Expand Down
6 changes: 6 additions & 0 deletions src/views/HistoricalAlerts/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,11 @@
text-decoration: underline;
color: var(--go-ui-color-primary-red);
}

.filter-button {
display: flex;
gap: var(--go-ui-spacing-md);
align-items: flex-end;
}
}
}
19 changes: 0 additions & 19 deletions src/views/Home/AlertFilters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,12 @@ function AlertFilters(props: Props) {
selectedUrgencyTypes,
selectedCertaintyTypes,
activeRegionId,
// startDateFrom,
// startDateTo,
setActiveCountryId,
setActiveAdmin1Id,
setSelectedSeverityTypes,
setSelectedUrgencyTypes,
setSelectedCertaintyTypes,
setActiveRegionId,
// setStartDateFrom,
// setStartDateTo,
selectedCategoryTypes,
setSelectedCategoryTypes,
} = useContext(AlertDataContext);
Expand Down Expand Up @@ -231,21 +227,6 @@ function AlertFilters(props: Props) {
value={selectedCertaintyTypes}
onChange={setSelectedCertaintyTypes}
/>
{/*
Add these filter after adding Historical alerts
<DateInput
name="startDateFrom"
label={strings.filterStartDateFrom}
value={startDateFrom}
onChange={setStartDateFrom}
/>
<DateInput
name="startDateTo"
label={strings.filterStartDateTo}
value={startDateTo}
onChange={setStartDateTo}
/>
*/}
{variant === 'table' && (
<MultiSelectInput
label={strings.filterCategoriesLabel}
Expand Down
9 changes: 6 additions & 3 deletions src/views/Home/AlertsMap/Sidebar/CountryAdmin1List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ function CountryAdmin1List(props: Props) {
() => ({
countryId,
alertFilters: {
severity: alertFilters.severity,
certainty: alertFilters.certainty,
urgency: alertFilters.urgency,
DISTINCT: true,
infos: {
severity: alertFilters.infos?.severity,
certainty: alertFilters.infos?.certainty,
urgency: alertFilters.infos?.urgency,
},
sent: alertFilters.sent,
},
}),
Expand Down
Loading