diff --git a/src/misc.ts b/src/misc.ts index 122e77459..517e1a00e 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -466,3 +466,15 @@ export function generateCode(charNum: number) { } return result; } + +export function findInEnum( + needle: string, + haystack: TEnum +) { + const match = Object.keys(haystack).find(key => key === needle); + if (!!match) { + return haystack[needle as keyof TEnum]; + } + + throw new Error(`Key ${needle} not found in enum`); +} diff --git a/src/orders/urls.ts b/src/orders/urls.ts index c54540c6c..b53fdd2e5 100644 --- a/src/orders/urls.ts +++ b/src/orders/urls.ts @@ -6,6 +6,7 @@ import { BulkAction, Dialog, Filters, + FiltersWithMultipleValues, Pagination, SingleAction } from "../types"; @@ -16,11 +17,14 @@ export const orderListPath = orderSectionUrl; export enum OrderListUrlFiltersEnum { dateFrom = "dateFrom", dateTo = "dateTo", - status = "status", email = "email", payment = "payment" } -export type OrderListUrlFilters = Filters; +export enum OrderListUrlFiltersWithMultipleValuesEnum { + status = "status" +} +export type OrderListUrlFilters = Filters & + FiltersWithMultipleValues; export type OrderListUrlDialog = "cancel" | "save-search" | "delete-search"; export type OrderListUrlQueryParams = BulkAction & Dialog & diff --git a/src/orders/views/OrderList/OrderList.tsx b/src/orders/views/OrderList/OrderList.tsx index a8fe9c47b..5b84e64b2 100644 --- a/src/orders/views/OrderList/OrderList.tsx +++ b/src/orders/views/OrderList/OrderList.tsx @@ -229,8 +229,8 @@ export const OrderList: React.StatelessComponent = ({ } onSearchChange={email => changeFilterField({ email })} - onFilterAdd={filter => - changeFilterField(createFilter(filter)) + onFilterAdd={data => + changeFilterField(createFilter(params, data)) } onFilterSave={() => openModal("save-search")} onFilterDelete={() => openModal("delete-search")} diff --git a/src/orders/views/OrderList/filters.ts b/src/orders/views/OrderList/filters.ts index 980a1119f..017196a2d 100644 --- a/src/orders/views/OrderList/filters.ts +++ b/src/orders/views/OrderList/filters.ts @@ -1,5 +1,7 @@ import { defineMessages, IntlShape } from "react-intl"; +import { findInEnum } from "@saleor/misc"; +import { removeAtIndex } from "@saleor/utils/lists"; import { FilterContentSubmitData } from "../../../components/Filter"; import { Filter } from "../../../components/TableFilter"; import { @@ -7,8 +9,12 @@ import { OrderStatusFilter } from "../../../types/globalTypes"; import { + arrayOrUndefined, + arrayOrValue, createFilterTabUtils, - createFilterUtils + createFilterUtils, + dedupeFilter, + valueOrFirst } from "../../../utils/filters"; import { OrderFilterKeys } from "../../components/OrderListFilter"; import { @@ -70,22 +76,25 @@ export function getFilterVariables( lte: params.dateTo }, customer: params.email, - status: OrderStatusFilter[params.status] + status: Array.isArray(params.status) + ? params.status.map(status => findInEnum(status, OrderStatusFilter)) + : params.status + ? [findInEnum(params.status, OrderStatusFilter)] + : undefined }; } export function createFilter( - filter: FilterContentSubmitData + filter: OrderListUrlFilters, + data: FilterContentSubmitData ): OrderListUrlFilters { - const filterName = filter.name; + const { name: filterName, value } = data; if (filterName === OrderFilterKeys.dateEqual.toString()) { - const value = filter.value as string; return { - dateFrom: value, - dateTo: value + dateFrom: valueOrFirst(value), + dateTo: valueOrFirst(value) }; } else if (filterName === OrderFilterKeys.dateRange.toString()) { - const { value } = filter; return { dateFrom: value[0], dateTo: value[1] @@ -99,15 +108,17 @@ export function createFilter( .map(value => value.toString()) .includes(filterName) ) { - const { value } = filter; return { - dateFrom: value as string, + dateFrom: valueOrFirst(value), dateTo: undefined }; } else if (filterName === OrderFilterKeys.fulfillment.toString()) { - const { value } = filter; return { - status: value as string + status: dedupeFilter( + filter.status + ? [...(filter.status as string[]), valueOrFirst(value)] + : arrayOrValue(value) + ) }; } } @@ -175,17 +186,29 @@ export function createFilterChips( } if (!!filters.status) { - filterChips = [ - ...filterChips, - { - label: getStatusLabel(filters.status, intl), - onClick: () => - onFilterDelete({ - ...filters, - status: undefined - }) - } - ]; + const statusFilterChips = Array.isArray(filters.status) + ? filters.status.map((status, statusIndex) => ({ + label: getStatusLabel(status, intl), + onClick: () => + onFilterDelete({ + ...filters, + status: arrayOrUndefined( + removeAtIndex(filters.status as string[], statusIndex) + ) + }) + })) + : [ + { + label: getStatusLabel(filters.status, intl), + onClick: () => + onFilterDelete({ + ...filters, + status: undefined + }) + } + ]; + + filterChips = [...filterChips, ...statusFilterChips]; } return filterChips; diff --git a/src/types.ts b/src/types.ts index 12e09862d..27deb132c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -112,6 +112,9 @@ export type ActiveTab = Partial<{ export type Filters = Partial< Record >; +export type FiltersWithMultipleValues = Partial< + Record +>; export type SingleAction = Partial<{ id: string; }>; diff --git a/src/utils/filters/filters.ts b/src/utils/filters/filters.ts index 9e0800d87..c620d9fd7 100644 --- a/src/utils/filters/filters.ts +++ b/src/utils/filters/filters.ts @@ -1,4 +1,7 @@ -function createFilterUtils(filters: object) { +function createFilterUtils< + TQueryParams extends object, + TFilters extends object +>(filters: object) { function getActiveFilters(params: TQueryParams): TFilters { return Object.keys(params) .filter(key => Object.keys(filters).includes(key)) @@ -21,4 +24,32 @@ function createFilterUtils(filters: object) { }; } +export function valueOrFirst(value: T | T[]): T { + if (Array.isArray(value)) { + return value[0]; + } + + return value; +} + +export function arrayOrValue(value: T | T[]): T[] { + if (Array.isArray(value)) { + return value; + } + + return [value]; +} + +export function arrayOrUndefined(array: T[]): T[] | undefined { + if (array.length === 0) { + return undefined; + } + + return array; +} + +export function dedupeFilter(array: T[]): T[] { + return Array.from(new Set(array)); +} + export default createFilterUtils;