Skip to content

Commit

Permalink
ISSUE #5257 - refactor filters data structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Amantini1997 committed Nov 26, 2024
1 parent e21a60c commit 14c62a0
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@
*/

export type TicketFilterListItemType = { module: string, property: string, type: CardFilterType };
export type FormFilter = { values: CardFilterValue[], type?: CardFilterType };

export type CardFilterOperator = 'ex' | 'nex' | 'eq' | 'neq' | 'ss' | 'nss' | 'rng' | 'nrng' | 'gt' | 'gte' | 'lt' | 'lte';
export type CardFilterType = 'text' | 'longText' | 'date' | 'pastDate' | 'sequencing' | 'oneOf' | 'manyOf' | 'boolean' | 'number' | 'ticketTitle' | 'ticketId' | 'template';
export type CardFilterValue = string | number | Date;
export type CardFiltersByOperator = Partial<Record<CardFilterOperator, FormFilter>>;
export type FormFilter = { operator: CardFilterOperator, values: CardFilterValue[] };

export type CardFiltersByType = Partial<Record<CardFilterType, FormFilter>>;
export type CardFilter = {
module: string,
property: string,
operator: CardFilterOperator,
type: CardFilterType,
filter: FormFilter,
};
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ import { ChipContainer, DeleteButton, TextWrapper, OperatorIconContainer, Displa
import { FILTER_OPERATOR_ICON, FILTER_OPERATOR_LABEL } from '../cardFilters.helpers';
import { Tooltip } from '@mui/material';
import { FormattedMessage } from 'react-intl';
import { CardFilterOperator, CardFilterType, CardFilterValue } from '../cardFilters.types';
import { CardFilterType, FormFilter } from '../cardFilters.types';
import { formatSimpleDate } from '@/v5/helpers/intl.helper';

type FilterChipProps = {
property: string;
operator: CardFilterOperator;
values: CardFilterValue[];
type: CardFilterType;
type: CardFilterType,
filter: FormFilter,
selected?: boolean;
onDelete: () => void;
};
export const FilterChip = ({ property, values, onDelete, operator, selected, type }: FilterChipProps) => {
export const FilterChip = ({ property, onDelete, selected, type, filter }: FilterChipProps) => {
const { operator, values } = filter;
const OperatorIcon = FILTER_OPERATOR_ICON[operator];
const hasMultipleValues = values.length > 1;
const isDate = ['date', 'pastDate'].includes(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { formatSimpleDate } from '@/v5/helpers/intl.helper';
import { FormattedMessage } from 'react-intl';
import { CardFilterOperator, CardFilterValue, CardFilter, CardFilterType } from '../cardFilters.types';
import { CardFilterOperator, CardFilterValue, CardFilter, CardFilterType, FormFilter } from '../cardFilters.types';
import { FILTER_OPERATOR_LABEL, getFilterFormTitle } from '../cardFilters.helpers';
import { Container, ButtonsContainer, Button } from './filterForm.styles';
import { MenuItem } from '@mui/material';
Expand All @@ -33,21 +33,21 @@ type FilterFormProps = {
module: string,
property: string,
type: CardFilterType,
values?: CardFilterValue[]
operator?: CardFilterOperator,
filter?: FormFilter,
onSubmit: (newFilter: CardFilter) => void,
onCancel: () => void,
};
export const FilterForm = ({ module, property, operator, type, values = [], onSubmit, onCancel }: FilterFormProps) => {
export const FilterForm = ({ module, property, type, filter, onSubmit, onCancel }: FilterFormProps) => {
const { operator, values = [] } = filter || {};
const formData = useForm<FormType>({ defaultValues: _.defaults({ values, operator }, DEFAULT_VALUES) });

const handleSubmit = formData.handleSubmit((body: FormType) => {
// TODO - remove this line
const newValues = body.values.filter((x) => ![undefined, ''].includes(x as any));
onSubmit({ module, property, operator: body.operator, filter: { values: newValues, type } });
onSubmit({ module, property, type, filter: { operator: body.operator, values: newValues } });
});

const isUpdatingFilter = !!operator;
const isUpdatingFilter = !!filter;
const canSubmit = formData.formState.isValid && !isEmpty(formData.formState.dirtyFields);
const formOperator = formData.watch('operator');
const valuesInputsCount = Math.min(getOperatorMaxSupportedValues(formOperator), 3);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { CardFiltersByOperator, CardFilterOperator, FormFilter, CardFilter } from '../cardFilters.types';
import { CardFiltersByType } from '../cardFilters.types';
import { FilterChip } from '../filterChip/filterChip.component';
import { Section } from './filtersSection.styles';
import { FilterForm } from '../filterForm/filterForm.component';
Expand All @@ -26,59 +26,54 @@ import { TicketFiltersContext } from '../../tickets/ticketFiltersContext';

type FiltersSectionProps = {
module?: string;
filters: Record<string, CardFiltersByOperator>;
filters: Record<string, CardFiltersByType>;
};
export const FiltersSection = ({ module, filters }: FiltersSectionProps) => {
const [selectedChip, setSelectedChip] = useState('');
const { deleteFilter, editFilter } = useContext(TicketFiltersContext);
const [selectedProperty, setSelectedProperty] = useState('');
const { deleteFilter, upsertFilter } = useContext(TicketFiltersContext);

const onDeleteFilter = (property, operator) => deleteFilter({ module, property, operator });

const handleEditFilter = (oldOperator: CardFilterOperator) => (newFilter: CardFilter) => editFilter(newFilter, oldOperator);
const onDeleteFilter = (property, type) => deleteFilter({ module, property, type });

const filtersToChips = () => {
const filterChips = [];
Object.entries(filters).forEach(([property, operatorAndFilter]) => {
const moduleFilterChips = Object.entries(operatorAndFilter).map(([operator, filter]) => [property, operator, filter]);
Object.entries(filters).forEach(([property, typeAndFilter]) => {
const moduleFilterChips = Object.entries(typeAndFilter).map(([type, filter]) => [property, type, filter]);
filterChips.push(...moduleFilterChips);
});
return filterChips;
};

return (
<Section>
{filtersToChips().map(([property, operator, filter]) => {
const filterKey = `${property}.${operator}`;
return (
<CardFilterActionMenu
key={filterKey}
onOpen={() => setSelectedChip(filterKey)}
onClose={() => setSelectedChip('')}
TriggerButton={(
<FilterChip
{...filter}
operator={operator}
{filtersToChips().map(([property, type, filter]) => (
<CardFilterActionMenu
key={property}
onOpen={() => setSelectedProperty(property)}
onClose={() => setSelectedProperty('')}
TriggerButton={(
<FilterChip
property={property}
type={type}
filter={filter}
selected={selectedProperty === property}
onDelete={() => onDeleteFilter(property, type)}
/>
)}
>
<ActionMenuContext.Consumer>
{({ close }) => (
<FilterForm
onCancel={close}
onSubmit={upsertFilter}
module={module}
property={property}
selected={selectedChip === filterKey}
onDelete={() => onDeleteFilter(property, operator)}
type={type}
filter={filter}
/>
)}
>
<ActionMenuContext.Consumer>
{({ close }) => (
<FilterForm
onCancel={close}
onSubmit={handleEditFilter(operator)}
module={module}
property={property}
operator={operator}
{...filter}
/>
)}
</ActionMenuContext.Consumer>
</CardFilterActionMenu>
);
})}
</ActionMenuContext.Consumer>
</CardFilterActionMenu>
))}
</Section>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { CardFilterActionMenu } from '../../filterForm/filterForm.styles';
import { TicketFiltersContext } from '@components/viewer/cards/tickets/ticketFiltersContext';

export const FilterSelection = () => {
const { addFilter } = useContext(TicketFiltersContext);
const { upsertFilter } = useContext(TicketFiltersContext);
const [active, setActive] = useState(false);
const [selectedItem, setSelectedItem] = useState<TicketFilterListItemType>(null);
const { containerOrFederation } = useParams<ViewerParams>();
Expand Down Expand Up @@ -81,7 +81,7 @@ export const FilterSelection = () => {
<DrillDownItem $visible={!showFiltersList}>
<FilterForm
{...(selectedItem || {} as any)}
onSubmit={addFilter}
onSubmit={upsertFilter}
onCancel={onCancel}
/>
</DrillDownItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@

import { get, isEmpty, set, unset } from 'lodash';
import { createContext, useState } from 'react';
import { CardFilterOperator, CardFilter } from '../cardFilters/cardFilters.types';
import { CardFilter } from '../cardFilters/cardFilters.types';

export interface TicketFiltersContextType {
filters: Record<string, any>;
addFilter: (filter: CardFilter) => void;
editFilter: (filter: CardFilter, oldOperator: CardFilterOperator) => void;
upsertFilter: (filter: CardFilter) => void;
deleteFilter: (filter: Omit<CardFilter, 'filter'>) => void;
deleteAllFilters: () => void;
}

const defaultValue: TicketFiltersContextType = {
filters: {},
addFilter: () => {},
editFilter: () => {},
upsertFilter: () => {},
deleteFilter: () => {},
deleteAllFilters: () => {},
};
Expand All @@ -52,41 +50,29 @@ export const TicketFiltersContextComponent = ({ filters: initialFilters, childre
path.pop();
} while (path.length && isEmpty(get(fltrs, path)));
};

const addFilter = ({ module, property, operator, filter }: CardFilter) => {
const upsertFilter = ({ module, property, type, filter }: CardFilter) => {
let newFilters = { ...filters };
const path = [module, property, operator];
const path = [module, property, type];
set(newFilters, path, filter);
setFilters({ ...newFilters });
};

const editFilter = ({ module, property, operator, filter }: CardFilter, oldOperator?: CardFilterOperator) => {
let newFilters = { ...filters };
const path = [module, property, operator];
set(newFilters, path, filter);
if (operator !== oldOperator) {
const oldPath = [module, property, oldOperator];
deleteFilterAndEmptyAncestors(newFilters, oldPath);
}
setFilters({ ...newFilters });
};

const deleteFilter = ({ module, property, operator }: CardFilter) => {

const deleteFilter = ({ module, property, type }: CardFilter) => {
const newFilters = { ...filters };
const path = [module, property, operator];
const path = [module, property, type];
deleteFilterAndEmptyAncestors(newFilters, path);
setFilters(newFilters);
};

const handleDeleteAllFilters = () => setFilters({});
const deleteAllFilters = () => setFilters({});

return (
<TicketFiltersContext.Provider value={{
filters,
addFilter: addFilter,
editFilter: editFilter,
deleteFilter: deleteFilter,
deleteAllFilters: handleDeleteAllFilters,
upsertFilter,
deleteFilter,
deleteAllFilters,
}}>
{children}
</TicketFiltersContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,48 +38,48 @@ import { TicketBaseKeys } from '../tickets.constants';
const defaultFilters = {
'': {
'templateId': {
'eq': {
'templateId': {
values: ['template id'],
type: 'templateId',
operator: 'eq',
},
},
},
[TicketBaseKeys.PROPERTIES]: {
'createdAt': {
'eq': {
'pastDate': {
values: [new Date('12/12/2024')],
type: 'pastDate',
operator: 'eq',
},
},
'property1': {
'rng': {
'date': {
values: [new Date('12/12/2024'), new Date('12/20/2024')],
type: 'date',
},
'nrng': {
values: [3],
type: 'number',
operator:'rng',
},
},
'property2': {
'eq': {
'number': {
values: [4],
type: 'number',
operator: 'eq',
},
},
'assignees': {
'ss': {
'manyOf': {
values: ['Ale', 'San', 'Dan'],
type: 'manyOf',
operator: 'ss',
},
},
},
'module1': {
'property1': {
'ex': { values: [] },
'ss': {
'numberOrStringProperty': {
'number': {
values: [],
operator: 'ex',
},
// This is
'text': {
values: [2, 3],
type: 'oneOf',
operator:'ss',
},
},
},
Expand Down

0 comments on commit 14c62a0

Please sign in to comment.