Skip to content
Open
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
0fe3fbe
fix: make dropdown menus scrollable
imdeaconu Sep 6, 2024
4ca1a44
fix: truncate overflowing table columns
imdeaconu Sep 6, 2024
921aa13
Merge branch 'commitglobal:main' into main
imdeaconu Sep 6, 2024
e5a2869
Merge branch 'commitglobal:main' into main
imdeaconu Sep 6, 2024
7866a67
Merge branch 'commitglobal:main' into main
imdeaconu Sep 9, 2024
9ea6c42
Merge branch 'commitglobal:main' into main
imdeaconu Sep 10, 2024
1bd449d
Merge branch 'commitglobal:main' into main
imdeaconu Sep 11, 2024
c9874d1
Squashed commit of the following:
imdeaconu Sep 11, 2024
b7715f3
Merge branch 'commitglobal:main' into main
imdeaconu Sep 12, 2024
0facf65
Squashed commit of the following:
imdeaconu Sep 13, 2024
67f681d
chore: remove unused import
imdeaconu Sep 13, 2024
8d73252
chore: delete duplicated / unused classes
imdeaconu Sep 16, 2024
63b21b9
Merge branch 'commitglobal:main' into main
imdeaconu Sep 17, 2024
1892e6e
Merge branch 'commitglobal:main' into main
imdeaconu Sep 18, 2024
abb7c01
feature: add searching to MonitoringObserversTagFilter
imdeaconu Sep 19, 2024
9d0b8ae
Merge branch 'commitglobal:main' into main
imdeaconu Sep 20, 2024
c9fcd3e
chore: update config files
imdeaconu Sep 20, 2024
333ba49
Revert "[NGO Admin] Rewrite the tag selector component (#675)"
imdeaconu Sep 23, 2024
580b68e
Merge branch 'main' of https://github.com/commitglobal/votemonitor
imdeaconu Sep 23, 2024
ba2dad9
Merge branch 'commitglobal:main' into main
imdeaconu Sep 25, 2024
eea4faa
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Sep 26, 2024
29b8163
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Sep 26, 2024
68a44ee
Merge branch 'commitglobal-main'
imdeaconu Sep 26, 2024
7cf3244
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Oct 1, 2024
b6abee7
Merge branch 'commitglobal-main-s1'
imdeaconu Oct 1, 2024
cc71856
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
e45ea22
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
50d15b6
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
1ed8e99
Merge branch 'commitglobal:main' into main
imdeaconu Oct 3, 2024
c2f1395
Merge branch 'commitglobal:main' into main
imdeaconu Oct 7, 2024
2c6d5f0
Merge branch 'commitglobal:main' into main
imdeaconu Oct 9, 2024
8c8e18f
Merge branch 'commitglobal:main' into main
imdeaconu Oct 9, 2024
db46a6d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 10, 2024
d4b0263
Merge branch 'commitglobal:main' into main
imdeaconu Oct 12, 2024
79864cd
Merge branch 'commitglobal:main' into main
imdeaconu Oct 14, 2024
5ae7edf
Merge branch 'commitglobal:main' into main
imdeaconu Oct 15, 2024
c0fe98a
Merge branch 'commitglobal:main' into main
imdeaconu Oct 17, 2024
b7b3c5c
Merge branch 'commitglobal:main' into main
imdeaconu Oct 18, 2024
a892349
Merge branch 'commitglobal:main' into main
imdeaconu Oct 19, 2024
2d98793
Merge branch 'commitglobal:main' into main
imdeaconu Oct 20, 2024
66ba8d0
Merge branch 'commitglobal:main' into main
imdeaconu Oct 21, 2024
a86608d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 22, 2024
aa1745c
Merge branch 'commitglobal:main' into main
imdeaconu Oct 23, 2024
9942029
Merge branch 'commitglobal:main' into main
imdeaconu Oct 23, 2024
d855c24
Merge branch 'commitglobal:main' into main
imdeaconu Oct 25, 2024
5a2b99d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 28, 2024
e9ea9a3
Merge branch 'commitglobal:main' into main
imdeaconu Oct 29, 2024
7dbc8a4
WIP: rework incident reports filters by entry and observer
imdeaconu Oct 29, 2024
37f57c6
WIP: remove redundant separate tag filter for form submissions
imdeaconu Oct 29, 2024
d4d2657
Merge branch 'commitglobal:main' into rework-filters-on-various-pages
imdeaconu Oct 29, 2024
90aa5f9
WIP: add filtering icon component
imdeaconu Oct 30, 2024
5f28a57
Merge branch 'rework-filters-on-various-pages' of https://github.com/…
imdeaconu Oct 30, 2024
b735543
add filtering by form ID and use the new filtering system in Incident…
imdeaconu Oct 30, 2024
de766f4
rework filters and add filtering UI for citizen reports
imdeaconu Oct 30, 2024
6326e9c
rework quick reports filters
imdeaconu Oct 30, 2024
86b6081
map quick reports location type in the ActiveFilters component
imdeaconu Oct 30, 2024
315e235
Merge branch 'commitglobal:main' into rework-filters-on-various-pages
imdeaconu Nov 4, 2024
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
17 changes: 10 additions & 7 deletions web/src/features/filtering/components/ActiveFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { DateTimeFormat } from '@/common/formats';
import { FilterBadge } from '@/components/ui/badge';
import { useCurrentElectionRoundStore } from '@/context/election-round.store';
import { useFormSubmissionsFilters } from '@/features/responses/hooks/form-submissions-queries';
import { useNavigate } from '@tanstack/react-router';
import { format } from 'date-fns/format';
import { FC, useCallback } from 'react';
import { FILTER_KEY, FILTER_LABEL } from '../filtering-enums';
import { isNotNilOrWhitespace, toBoolean } from '@/lib/utils';
import {
mapFormSubmissionFollowUpStatus,
mapIncidentCategory,
mapIncidentReportLocationType,
mapQuickReportFollowUpStatus,
mapQuickReportLocationType,
} from '@/features/responses/utils/helpers';
import { QuickReportFollowUpStatus } from '@/common/types';
import { isNotNilOrWhitespace, toBoolean } from '@/lib/utils';
import { useNavigate } from '@tanstack/react-router';
import { format } from 'date-fns/format';
import { FC, useCallback } from 'react';
import { FILTER_KEY, FILTER_LABEL } from '../filtering-enums';

interface ActiveFilterProps {
filterId: string;
Expand Down Expand Up @@ -48,7 +48,6 @@ const FILTER_LABELS = new Map<string, string>([
[FILTER_KEY.LocationL3, FILTER_LABEL.LocationL3],
[FILTER_KEY.LocationL4, FILTER_LABEL.LocationL4],
[FILTER_KEY.LocationL5, FILTER_LABEL.LocationL5],
[FILTER_KEY.FormSubmissionsMonitoringObserverTags, FILTER_LABEL.FormSubmissionsMonitoringObserverTags],
[FILTER_KEY.PollingStationNumber, FILTER_LABEL.PollingStationNumber],
[FILTER_KEY.FormId, FILTER_LABEL.FormId],
[FILTER_KEY.FormStatusFilter, FILTER_LABEL.FormStatus],
Expand All @@ -59,12 +58,16 @@ const FILTER_LABELS = new Map<string, string>([
[FILTER_KEY.QuickReportIncidentCategory, FILTER_LABEL.QuickReportIncidentCategory],
[FILTER_KEY.QuickReportFollowUpStatus, FILTER_LABEL.QuickReportFollowUpStatus],
[FILTER_KEY.HasQuickReports, FILTER_LABEL.HasQuickReports],
[FILTER_KEY.IncidentReportLocationType, FILTER_LABEL.IncidentReportLocationType],
[FILTER_KEY.QuickReportLocationType, FILTER_LABEL.IncidentReportLocationType],
]);

const FILTER_VALUE_LOCALIZATORS = new Map<string, (value: any) => string>([
[FILTER_KEY.QuickReportFollowUpStatus, mapQuickReportFollowUpStatus],
[FILTER_KEY.FormSubmissionFollowUpStatus, mapFormSubmissionFollowUpStatus],
[FILTER_KEY.QuickReportIncidentCategory, mapIncidentCategory],
[FILTER_KEY.IncidentReportLocationType, mapIncidentReportLocationType],
[FILTER_KEY.QuickReportLocationType, mapQuickReportLocationType],
]);

const ActiveFilter: FC<ActiveFilterProps> = ({ filterId, value, isArray }) => {
Expand Down
20 changes: 20 additions & 0 deletions web/src/features/filtering/components/FilteringIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { FunnelIcon } from '@heroicons/react/24/outline';
import { FC, SetStateAction } from 'react';

interface FilteringIconProps {
filteringIsExpanded: boolean;
setFilteringIsExpanded: (value: SetStateAction<boolean>) => void;
}

export const FilteringIcon: FC<FilteringIconProps> = ({ filteringIsExpanded, setFilteringIsExpanded }) => {
return (
<FunnelIcon
title={`${filteringIsExpanded ? 'Collapse' : 'Expand'} filtering`}
className='w-[20px] text-purple-900 cursor-pointer'
fill={filteringIsExpanded ? '#5F288D' : 'rgba(0,0,0,0)'}
onClick={() => {
setFilteringIsExpanded((prev) => !prev);
}}
/>
);
};
68 changes: 68 additions & 0 deletions web/src/features/filtering/components/LocationTypeFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { SelectFilter, SelectFilterOption } from '@/features/filtering/components/SelectFilter';
import { FILTER_KEY } from '@/features/filtering/filtering-enums';
import { useFilteringContainer } from '@/features/filtering/hooks/useFilteringContainer';
import { IncidentReportLocationType } from '@/features/responses/models/incident-report';
import { QuickReportLocationType } from '@/features/responses/models/quick-report';
import { mapIncidentReportLocationType, mapQuickReportLocationType } from '@/features/responses/utils/helpers';
import { FC } from 'react';

export const IncidentReportsLocationTypeFilter: FC = () => {
const { queryParams, navigateHandler } = useFilteringContainer();

const onChange = (value: string) => {
navigateHandler({ [FILTER_KEY.IncidentReportLocationType]: value });
};
const options: SelectFilterOption[] = [
{
value: IncidentReportLocationType.PollingStation,
label: mapIncidentReportLocationType(IncidentReportLocationType.PollingStation),
},

{
value: IncidentReportLocationType.OtherLocation,
label: mapIncidentReportLocationType(IncidentReportLocationType.OtherLocation),
},
];

return (
<SelectFilter
value={(queryParams as any)[FILTER_KEY.IncidentReportLocationType]}
onChange={onChange}
options={options}
placeholder='Location Type'
/>
);
};

export const QuickReportsLocationTypeFilter: FC = () => {
const { queryParams, navigateHandler } = useFilteringContainer();

const onChange = (value: string) => {
navigateHandler({ [FILTER_KEY.QuickReportLocationType]: value });
};
const options: SelectFilterOption[] = [
{
value: QuickReportLocationType.NotRelatedToAPollingStation,
label: mapQuickReportLocationType(QuickReportLocationType.NotRelatedToAPollingStation),
},

{
value: QuickReportLocationType.OtherPollingStation,
label: mapQuickReportLocationType(QuickReportLocationType.OtherPollingStation),
},

{
value: QuickReportLocationType.VisitedPollingStation,
label: mapQuickReportLocationType(QuickReportLocationType.VisitedPollingStation),
},
];

return (
<SelectFilter
value={(queryParams as any)[FILTER_KEY.QuickReportLocationType]}
onChange={onChange}
options={options}
placeholder='Location Type'
/>
);
};
19 changes: 10 additions & 9 deletions web/src/features/filtering/filtering-enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const enum FILTER_KEY {
LocationL4 = 'level4Filter',
LocationL5 = 'level5Filter',
PollingStationNumber = 'pollingStationNumberFilter',
FormSubmissionsMonitoringObserverTags = 'tagsFilter',
ViewBy = 'viewBy',
Tab = 'tab',
FormId = 'formId',
Expand All @@ -26,14 +25,16 @@ export const enum FILTER_KEY {
ToDate = 'submissionsToDate',
SearchText = 'searchText',
FormIsCompleted = 'formIsCompleted',
QuickReportIncidentCategory ='incidentCategory',
QuickReportFollowUpStatus ='quickReportFollowUpStatus',
HasQuickReports ='hasQuickReports',
QuickReportIncidentCategory = 'incidentCategory',
QuickReportFollowUpStatus = 'quickReportFollowUpStatus',
HasQuickReports = 'hasQuickReports',
IncidentReportLocationType = 'incidentReportLocationType',
QuickReportLocationType = 'quickReportLocationType',
}

export const enum FILTER_LABEL {
MonitoringObserverStatus = 'Observer status',
MonitoringObserverTags = 'Tags',
MonitoringObserverTags = 'Observer tags',
FormTypeFilter = 'Form type',
HasFlaggedAnswers = 'Flagged answers',
FollowUpStatus = 'Follow-up status',
Expand All @@ -45,15 +46,15 @@ export const enum FILTER_LABEL {
LocationL4 = 'Location - L4',
LocationL5 = 'Location - L5',
PollingStationNumber = 'Polling station number',
FormSubmissionsMonitoringObserverTags = 'Observer tags',
MediaFiles = 'Has attachments',
FormId = 'Form',
FormStatus = 'Form status',
FromDate = 'From date',
ToDate = 'To Date',
SearchText = 'Search text',
FormCompleted = 'Form completed',
QuickReportIncidentCategory ='Incident category',
QuickReportFollowUpStatus ='Quick report follow up status',
HasQuickReports ='Has quick reports',
QuickReportIncidentCategory = 'Incident category',
QuickReportFollowUpStatus = 'Quick report follow up status',
HasQuickReports = 'Has quick reports',
IncidentReportLocationType = 'Location type',
}
15 changes: 12 additions & 3 deletions web/src/features/filtering/hooks/useFilteringContainer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useSetPrevSearch } from '@/common/prev-search-store';
import { useNavigate, useSearch } from '@tanstack/react-router';
import { useCallback, useMemo } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { HIDDEN_FILTERS } from '../components/ActiveFilters';
import { FILTER_KEY } from '../filtering-enums';

Expand All @@ -14,12 +14,13 @@ export function useFilteringContainer() {

const setPrevSearch = useSetPrevSearch();
const filteringIsActive = useMemo(() => {

return Object.entries(queryParams)
.filter(([key, _]) => !HIDDEN_FILTERS.includes(key))
.some(([_, value]) => !!value);
}, [queryParams]);

const [filteringIsExpanded, setFilteringIsExpanded] = useState(filteringIsActive ?? false);

const navigateHandler = useCallback(
(search: Record<string, any | undefined>) => {
void navigate({
Expand All @@ -44,5 +45,13 @@ export function useFilteringContainer() {
setPrevSearch(filterObject(queryParams, HIDDEN_FILTERS));
};

return { queryParams, filteringIsActive, navigate, navigateHandler, resetFilters };
return {
queryParams,
filteringIsActive,
filteringIsExpanded,
setFilteringIsExpanded,
navigate,
navigateHandler,
resetFilters,
};
}
14 changes: 4 additions & 10 deletions web/src/features/forms/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ import { formsKeys, useForms } from '../../queries';
import AddTranslationsDialog, { useAddTranslationsDialog } from './AddTranslationsDialog';
import CreateForm from './CreateForm';
import { FormFilters } from './FormFilters/FormFilters';
import { FilteringIcon } from '@/features/filtering/components/FilteringIcon';

export default function FormsDashboard(): ReactElement {
const navigate = useNavigate();
const search = Route.useSearch();
const debouncedSearch = useDebounce(search, 300);
const [searchText, setSearchText] = useState('');
const { filteringIsActive } = useFilteringContainer();
const { filteringIsExpanded, setFilteringIsExpanded } = useFilteringContainer();

const queryParams = useMemo(() => {
const params = [
Expand Down Expand Up @@ -347,7 +348,6 @@ export default function FormsDashboard(): ReactElement {
return defaultColumns;
}, [currentElectionRoundId, isMonitoringNgoForCitizenReporting]);

const [isFiltering, setIsFiltering] = useState(filteringIsActive);

const handleSearchInput = (ev: React.FormEvent<HTMLInputElement>) => {
setSearchText(ev.currentTarget.value);
Expand Down Expand Up @@ -526,18 +526,12 @@ export default function FormsDashboard(): ReactElement {
<div className='flex justify-end gap-4 px-6'>
<>
<Input className='max-w-md' onChange={handleSearchInput} placeholder='Search' />
<FunnelIcon
className='w-[20px] text-purple-900 cursor-pointer'
fill={isFiltering ? '#5F288D' : 'rgba(0,0,0,0)'}
onClick={() => {
setIsFiltering((prev) => !prev);
}}
/>
<FilteringIcon filteringIsExpanded={filteringIsExpanded} setFilteringIsExpanded={setFilteringIsExpanded} />
</>
</div>

<Separator />
{isFiltering && <FormFilters />}
{filteringIsExpanded && <FormFilters />}
</CardHeader>
<CardContent>
<QueryParamsDataTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import ImportMonitoringObserversDialog from '../MonitoringObserversList/ImportMo
import ImportMonitoringObserversErrorsDialog from '../MonitoringObserversList/ImportMonitoringObserversErrorsDialog';
import ConfirmResendInvitationDialog from './ConfirmResendInvitationDialog';
import CreateMonitoringObserverDialog from './CreateMonitoringObserverDialog';
import { FilteringIcon } from '@/features/filtering/components/FilteringIcon';

function MonitoringObserversList() {
const navigate = useNavigate();
Expand Down Expand Up @@ -136,8 +137,7 @@ function MonitoringObserversList() {
const importMonitoringObserversDialog = useDialog();
const importMonitoringObserverErrorsDialog = useDialog();
const confirmResendInvitesDialog = useDialog();
const { filteringIsActive, navigateHandler } = useFilteringContainer();
const [filtersExpanded, setFiltersExpanded] = useState(false);
const { filteringIsExpanded, setFilteringIsExpanded, navigateHandler } = useFilteringContainer();

const handleSearchInput = (ev: React.FormEvent<HTMLInputElement>) => {
setSearchText(ev.currentTarget.value);
Expand Down Expand Up @@ -208,11 +208,6 @@ function MonitoringObserversList() {
},
});

const changeIsFiltering = () => {
setFiltersExpanded((prev) => {
return !prev;
});
};

function handleResendInviteToObserver(id?: string): void {
setMonitoringObserverId(id);
Expand Down Expand Up @@ -339,16 +334,12 @@ function MonitoringObserversList() {
<div className='flex flex-row justify-end gap-4 px-6 filters'>
<>
<Input onChange={handleSearchInput} value={searchText} className='max-w-md' placeholder='Search' />
<FunnelIcon
onClick={changeIsFiltering}
className='w-[20px] text-purple-900 cursor-pointer'
fill={filteringIsActive ? '#5F288D' : 'rgba(0,0,0,0)'}
/>
<FilteringIcon filteringIsExpanded={filteringIsExpanded} setFilteringIsExpanded={setFilteringIsExpanded} />
<Cog8ToothIcon className='w-[20px] text-purple-900' />
</>
</div>
<Separator />
{filtersExpanded && <MonitoringObserversListFilters />}
{filteringIsExpanded && <MonitoringObserversListFilters />}
</CardHeader>
<CardContent>
<QueryParamsDataTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@ import { useMonitoringObserversTags } from '@/hooks/tags-queries';

import { FC } from 'react';

interface MonitoringObserverTagsSelectProps {
isFilteringFormSubmissions?: boolean;
}

export const MonitoringObserverTagsSelect: FC<MonitoringObserverTagsSelectProps> = ({ isFilteringFormSubmissions }) => {
const COMPONENT_FILTER_KEY = isFilteringFormSubmissions
? FILTER_KEY.FormSubmissionsMonitoringObserverTags
: FILTER_KEY.MonitoringObserverTags;
export const MonitoringObserverTagsSelect: FC = () => {
const COMPONENT_FILTER_KEY = FILTER_KEY.MonitoringObserverTags;

const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: tags } = useMonitoringObserversTags(currentElectionRoundId);
Expand Down
Loading