From 6aadc0532286349b01800aa9ce52f65fc79b2f51 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 5 Sep 2019 15:05:12 +0200 Subject: [PATCH 1/6] Make multiple choice filters work --- src/misc.ts | 12 +++++ src/orders/urls.ts | 8 ++- src/orders/views/OrderList/OrderList.tsx | 4 +- src/orders/views/OrderList/filters.ts | 69 ++++++++++++++++-------- src/types.ts | 3 ++ src/utils/filters/filters.ts | 33 +++++++++++- 6 files changed, 101 insertions(+), 28 deletions(-) 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; From 3917e13613c96fc4c4f83c7c431e75c2a704800f Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 6 Sep 2019 14:58:44 +0200 Subject: [PATCH 2/6] Refacto filters to handle multiple values --- src/components/Filter/Filter.tsx | 4 +- src/components/Filter/FilterContent.tsx | 14 +- src/components/Filter/FilterElement.tsx | 8 +- src/components/Filter/types.ts | 4 +- src/components/FilterBar/FilterBar.tsx | 6 +- src/components/TableFilter/FilterChips.tsx | 6 +- src/fixtures.ts | 2 +- .../OrderListFilter/OrderListFilter.tsx | 33 ++-- .../OrderListPage/OrderListPage.tsx | 3 +- .../__snapshots__/filters.test.ts.snap | 109 ++++++++++++ src/orders/views/OrderList/filters.test.ts | 155 ++++++++++++++++++ src/orders/views/OrderList/filters.ts | 12 +- .../ProductListFilter/ProductListFilter.tsx | 28 ++-- .../ProductListPage/ProductListPage.tsx | 4 +- .../__snapshots__/filters.test.ts.snap | 66 ++++++++ .../views/ProductList/filters.test.ts | 77 +++++++++ src/products/views/ProductList/filters.ts | 10 +- src/types.ts | 7 +- .../menu/__snapshots__/menu.test.ts.snap | 28 ++-- src/utils/menu/menu.test.ts | 23 ++- src/utils/menu/menu.ts | 126 ++++++++------ 21 files changed, 581 insertions(+), 144 deletions(-) create mode 100644 src/orders/views/OrderList/__snapshots__/filters.test.ts.snap create mode 100644 src/orders/views/OrderList/filters.test.ts create mode 100644 src/products/views/ProductList/__snapshots__/filters.test.ts.snap create mode 100644 src/products/views/ProductList/filters.test.ts diff --git a/src/components/Filter/Filter.tsx b/src/components/Filter/Filter.tsx index a68e682df..dbe641496 100644 --- a/src/components/Filter/Filter.tsx +++ b/src/components/Filter/Filter.tsx @@ -19,9 +19,9 @@ import { FilterContent } from "."; import { FilterContentSubmitData } from "./FilterContent"; import { IFilter } from "./types"; -export interface FilterProps { +export interface FilterProps { currencySymbol: string; - menu: IFilter; + menu: IFilter; filterLabel: string; onFilterAdd: (filter: FilterContentSubmitData) => void; } diff --git a/src/components/Filter/FilterContent.tsx b/src/components/Filter/FilterContent.tsx index bf6b4b1d1..1ad5d77ee 100644 --- a/src/components/Filter/FilterContent.tsx +++ b/src/components/Filter/FilterContent.tsx @@ -10,13 +10,13 @@ import SingleSelectField from "../SingleSelectField"; import FilterElement from "./FilterElement"; import { IFilter } from "./types"; -export interface FilterContentSubmitData { - name: string; +export interface FilterContentSubmitData { + name: TKeys; value: string | string[]; } export interface FilterContentProps { currencySymbol: string; - filters: IFilter; + filters: IFilter; onSubmit: (data: FilterContentSubmitData) => void; } @@ -27,10 +27,10 @@ function checkFilterValue(value: string | string[]): boolean { return value.some(v => !!v); } -function getFilterChoices(items: IFilter) { +function getFilterChoices(items: IFilter) { return items.map(filterItem => ({ label: filterItem.label, - value: filterItem.value + value: filterItem.value.toString() })); } @@ -46,7 +46,7 @@ const FilterContent: React.FC = ({ onSubmit }) => { const intl = useIntl(); - const [menuValue, setMenuValue] = React.useState(""); + const [menuValue, setMenuValue] = React.useState(null); const [filterValue, setFilterValue] = React.useState(""); const classes = useStyles({}); @@ -95,7 +95,7 @@ const FilterContent: React.FC = ({ }} value={ filterItemIndex === menus.length - 1 - ? menuValue + ? menuValue.toString() : menus[filterItemIndex - 1].label.toString() } placeholder={intl.formatMessage({ diff --git a/src/components/Filter/FilterElement.tsx b/src/components/Filter/FilterElement.tsx index da4e1d8f6..00dc915e4 100644 --- a/src/components/Filter/FilterElement.tsx +++ b/src/components/Filter/FilterElement.tsx @@ -10,9 +10,9 @@ import PriceField from "../PriceField"; import SingleSelectField from "../SingleSelectField"; import { FieldType, IFilterItem } from "./types"; -export interface FilterElementProps { +export interface FilterElementProps { className?: string; - filter: IFilterItem; + filter: IFilterItem; value: string | string[]; onChange: (value: string | string[]) => void; } @@ -26,10 +26,10 @@ const useStyles = makeStyles({ } }); -export interface FilterElementProps { +export interface FilterElementProps { className?: string; currencySymbol: string; - filter: IFilterItem; + filter: IFilterItem; value: string | string[]; onChange: (value: string | string[]) => void; } diff --git a/src/components/Filter/types.ts b/src/components/Filter/types.ts index 53bf9302a..c991801b8 100644 --- a/src/components/Filter/types.ts +++ b/src/components/Filter/types.ts @@ -25,6 +25,6 @@ export interface FilterData { value?: string; } -export type IFilterItem = IMenuItem; +export type IFilterItem = IMenuItem; -export type IFilter = IMenu; +export type IFilter = IMenu; diff --git a/src/components/FilterBar/FilterBar.tsx b/src/components/FilterBar/FilterBar.tsx index 7f81046c5..e55ca25da 100644 --- a/src/components/FilterBar/FilterBar.tsx +++ b/src/components/FilterBar/FilterBar.tsx @@ -6,9 +6,9 @@ import Debounce from "../Debounce"; import { IFilter } from "../Filter/types"; import FilterTabs, { FilterChips, FilterTab } from "../TableFilter"; -export interface FilterBarProps - extends FilterProps { - filterMenu: IFilter; +export interface FilterBarProps + extends FilterProps { + filterMenu: IFilter; } const FilterBar: React.FC = ({ diff --git a/src/components/TableFilter/FilterChips.tsx b/src/components/TableFilter/FilterChips.tsx index 176c53b44..180c26aa4 100644 --- a/src/components/TableFilter/FilterChips.tsx +++ b/src/components/TableFilter/FilterChips.tsx @@ -99,16 +99,16 @@ const useStyles = makeStyles( } ); -interface FilterChipProps { +interface FilterChipProps { currencySymbol: string; - menu: IFilter; + menu: IFilter; filtersList: Filter[]; filterLabel: string; placeholder: string; search: string; isCustomSearch: boolean; onSearchChange: (event: React.ChangeEvent) => void; - onFilterAdd: (filter: FilterContentSubmitData) => void; + onFilterAdd: (filter: FilterContentSubmitData) => void; onFilterDelete: () => void; onFilterSave: () => void; } diff --git a/src/fixtures.ts b/src/fixtures.ts index b55c9d863..2b290708b 100644 --- a/src/fixtures.ts +++ b/src/fixtures.ts @@ -46,7 +46,7 @@ export const countries = [ { code: "AS", label: "American Samoa" } ]; -export const filterPageProps: FilterPageProps<{}> = { +export const filterPageProps: FilterPageProps<{}, unknown> = { currencySymbol: "USD", currentTab: 0, filterTabs: [ diff --git a/src/orders/components/OrderListFilter/OrderListFilter.tsx b/src/orders/components/OrderListFilter/OrderListFilter.tsx index 676a3548c..06d9fa0d5 100644 --- a/src/orders/components/OrderListFilter/OrderListFilter.tsx +++ b/src/orders/components/OrderListFilter/OrderListFilter.tsx @@ -10,17 +10,16 @@ import { FilterProps } from "../../../types"; import { OrderStatusFilter } from "../../../types/globalTypes"; import { OrderListUrlFilters } from "../../urls"; -type OrderListFilterProps = FilterProps; +type OrderListFilterProps = FilterProps; export enum OrderFilterKeys { - date, - dateEqual, - dateRange, - dateLastWeek, - dateLastMonth, - dateLastYear, - email, - fulfillment + date = "date", + dateEqual = "dateEqual", + dateRange = "dateRange", + dateLastWeek = "dateLastWeek", + dateLastMonth = "dateLastMonth", + dateLastYear = "dateLastYear", + fulfillment = "fulfillment" } const OrderListFilter: React.FC = props => { @@ -28,7 +27,7 @@ const OrderListFilter: React.FC = props => { const tz = React.useContext(TimezoneContext); const intl = useIntl(); - const filterMenu: IFilter = [ + const filterMenu: IFilter = [ { children: [ { @@ -44,7 +43,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Last 7 Days" }), - value: OrderFilterKeys.dateLastWeek.toString() + value: OrderFilterKeys.dateLastWeek }, { children: [], @@ -59,7 +58,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Last 30 Days" }), - value: OrderFilterKeys.dateLastMonth.toString() + value: OrderFilterKeys.dateLastMonth }, { children: [], @@ -74,7 +73,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Last Year" }), - value: OrderFilterKeys.dateLastYear.toString() + value: OrderFilterKeys.dateLastYear }, { children: [], @@ -88,7 +87,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Specific Date" }), - value: OrderFilterKeys.dateEqual.toString() + value: OrderFilterKeys.dateEqual }, { children: [], @@ -101,7 +100,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Range" }), - value: OrderFilterKeys.dateRange.toString() + value: OrderFilterKeys.dateRange } ], data: { @@ -113,7 +112,7 @@ const OrderListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Date" }), - value: OrderFilterKeys.date.toString() + value: OrderFilterKeys.date }, { children: [], @@ -155,7 +154,7 @@ const OrderListFilter: React.FC = props => { defaultMessage: "Fulfillment Status", description: "order" }), - value: OrderFilterKeys.fulfillment.toString() + value: OrderFilterKeys.fulfillment } ]; diff --git a/src/orders/components/OrderListPage/OrderListPage.tsx b/src/orders/components/OrderListPage/OrderListPage.tsx index 3ccd68653..a4cc2db64 100644 --- a/src/orders/components/OrderListPage/OrderListPage.tsx +++ b/src/orders/components/OrderListPage/OrderListPage.tsx @@ -7,6 +7,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; import { sectionNames } from "@saleor/intl"; +import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter"; import { FilterPageProps, ListActions, PageListProps } from "@saleor/types"; import { OrderList_orders_edges_node } from "../../types/OrderList"; import { OrderListUrlFilters } from "../../urls"; @@ -16,7 +17,7 @@ import OrderListFilter from "../OrderListFilter"; export interface OrderListPageProps extends PageListProps, ListActions, - FilterPageProps { + FilterPageProps { orders: OrderList_orders_edges_node[]; } diff --git a/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap b/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..8c70c08ce --- /dev/null +++ b/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,109 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Crate filter chips 1`] = ` +Array [ + Object { + "label": "Date from 2019-09-01", + "onClick": [Function], + }, + Object { + "label": "Date to 2019-09-10", + "onClick": [Function], + }, + Object { + "label": "Fulfilled", + "onClick": [Function], + }, + Object { + "label": "Partially Fulfilled", + "onClick": [Function], + }, +] +`; + +exports[`Create filter object with date 1`] = ` +Object { + "dateFrom": "2019-09-01", + "dateTo": "2019-09-01", +} +`; + +exports[`Create filter object with date last month 1`] = ` +Object { + "dateFrom": "2019-09-01", + "dateTo": undefined, +} +`; + +exports[`Create filter object with date last week 1`] = ` +Object { + "dateFrom": "2019-09-01", + "dateTo": undefined, +} +`; + +exports[`Create filter object with date last year 1`] = ` +Object { + "dateFrom": "2019-09-01", + "dateTo": undefined, +} +`; + +exports[`Create filter object with date range 1`] = ` +Object { + "dateFrom": "2019-09-01", + "dateTo": "2019-09-10", +} +`; + +exports[`Create filter object with fulfillment status 1`] = ` +Object { + "status": Array [ + "PARTIALLY_FULFILLED", + ], +} +`; + +exports[`Create filter object with multiple deduped values 1`] = ` +Object { + "status": Array [ + "FULFILLED", + ], +} +`; + +exports[`Create filter object with multiple values 1`] = ` +Object { + "status": Array [ + "FULFILLED", + "PARTIALLY_FULFILLED", + ], +} +`; + +exports[`Get filter variables from multiple status value 1`] = ` +Object { + "created": Object { + "gte": "2019-09-01", + "lte": "2019-09-10", + }, + "customer": "email@example.com", + "status": Array [ + "FULFILLED", + "PARTIALLY_FULFILLED", + ], +} +`; + +exports[`Get filter variables from single status value 1`] = ` +Object { + "created": Object { + "gte": "2019-09-01", + "lte": "2019-09-10", + }, + "customer": "email@example.com", + "status": Array [ + "FULFILLED", + ], +} +`; diff --git a/src/orders/views/OrderList/filters.test.ts b/src/orders/views/OrderList/filters.test.ts new file mode 100644 index 000000000..6217678b0 --- /dev/null +++ b/src/orders/views/OrderList/filters.test.ts @@ -0,0 +1,155 @@ +import { createIntl } from "react-intl"; + +import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter"; +import { OrderStatus, OrderStatusFilter } from "@saleor/types/globalTypes"; +import { createFilter, createFilterChips, getFilterVariables } from "./filters"; + +const mockIntl = createIntl({ + locale: "en" +}); + +describe("Create filter object", () => { + it("with date", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.dateEqual, + value: "2019-09-01" + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with date range", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.dateRange, + value: ["2019-09-01", "2019-09-10"] + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with date last week", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.dateLastWeek, + value: "2019-09-01" + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with date last month", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.dateLastMonth, + value: "2019-09-01" + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with date last year", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.dateLastYear, + value: "2019-09-01" + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with fulfillment status", () => { + const filter = createFilter( + {}, + { + name: OrderFilterKeys.fulfillment, + value: OrderStatusFilter.PARTIALLY_FULFILLED + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with multiple values", () => { + const filter = createFilter( + { + status: [OrderStatusFilter.FULFILLED] + }, + { + name: OrderFilterKeys.fulfillment, + value: OrderStatusFilter.PARTIALLY_FULFILLED + } + ); + + expect(filter).toMatchSnapshot(); + }); + + it("with multiple deduped values", () => { + const filter = createFilter( + { + status: [OrderStatusFilter.FULFILLED] + }, + { + name: OrderFilterKeys.fulfillment, + value: OrderStatusFilter.FULFILLED + } + ); + + expect(filter).toMatchSnapshot(); + }); +}); + +test("Crate filter chips", () => { + const chips = createFilterChips( + { + dateFrom: "2019-09-01", + dateTo: "2019-09-10", + status: [OrderStatus.FULFILLED, OrderStatus.PARTIALLY_FULFILLED] + }, + { + formatDate: date => date + }, + jest.fn(), + mockIntl as any + ); + + expect(chips).toMatchSnapshot(); +}); + +describe("Get filter variables", () => { + it("from single status value", () => { + const filter = getFilterVariables({ + dateFrom: "2019-09-01", + dateTo: "2019-09-10", + email: "email@example.com", + status: OrderStatus.FULFILLED.toString() + }); + + expect(filter).toMatchSnapshot(); + }); + + it("from multiple status value", () => { + const filter = getFilterVariables({ + dateFrom: "2019-09-01", + dateTo: "2019-09-10", + email: "email@example.com", + status: [ + OrderStatus.FULFILLED.toString(), + OrderStatus.PARTIALLY_FULFILLED.toString() + ] + }); + + expect(filter).toMatchSnapshot(); + }); +}); diff --git a/src/orders/views/OrderList/filters.ts b/src/orders/views/OrderList/filters.ts index 017196a2d..46ad23977 100644 --- a/src/orders/views/OrderList/filters.ts +++ b/src/orders/views/OrderList/filters.ts @@ -86,15 +86,15 @@ export function getFilterVariables( export function createFilter( filter: OrderListUrlFilters, - data: FilterContentSubmitData + data: FilterContentSubmitData ): OrderListUrlFilters { const { name: filterName, value } = data; - if (filterName === OrderFilterKeys.dateEqual.toString()) { + if (filterName === OrderFilterKeys.dateEqual) { return { dateFrom: valueOrFirst(value), dateTo: valueOrFirst(value) }; - } else if (filterName === OrderFilterKeys.dateRange.toString()) { + } else if (filterName === OrderFilterKeys.dateRange) { return { dateFrom: value[0], dateTo: value[1] @@ -104,15 +104,13 @@ export function createFilter( OrderFilterKeys.dateLastWeek, OrderFilterKeys.dateLastMonth, OrderFilterKeys.dateLastYear - ] - .map(value => value.toString()) - .includes(filterName) + ].includes(filterName) ) { return { dateFrom: valueOrFirst(value), dateTo: undefined }; - } else if (filterName === OrderFilterKeys.fulfillment.toString()) { + } else if (filterName === OrderFilterKeys.fulfillment) { return { status: dedupeFilter( filter.status diff --git a/src/products/components/ProductListFilter/ProductListFilter.tsx b/src/products/components/ProductListFilter/ProductListFilter.tsx index deeaca78b..6bd04e778 100644 --- a/src/products/components/ProductListFilter/ProductListFilter.tsx +++ b/src/products/components/ProductListFilter/ProductListFilter.tsx @@ -7,21 +7,23 @@ import { FilterProps } from "@saleor/types"; import { StockAvailability } from "@saleor/types/globalTypes"; import { ProductListUrlFilters } from "../../urls"; -type ProductListFilterProps = FilterProps; +type ProductListFilterProps = FilterProps< + ProductListUrlFilters, + ProductFilterKeys +>; export enum ProductFilterKeys { - published, - price, - priceEqual, - priceRange, - stock, - query + published = "published", + price = "price", + priceEqual = "priceEqual", + priceRange = "priceRange", + stock = "stock" } const ProductListFilter: React.FC = props => { const intl = useIntl(); - const filterMenu: IFilter = [ + const filterMenu: IFilter = [ { children: [], data: { @@ -55,7 +57,7 @@ const ProductListFilter: React.FC = props => { defaultMessage: "Visibility", description: "product visibility" }), - value: ProductFilterKeys.published.toString() + value: ProductFilterKeys.published }, { children: [], @@ -85,7 +87,7 @@ const ProductListFilter: React.FC = props => { defaultMessage: "Stock", description: "product stock" }), - value: ProductFilterKeys.stock.toString() + value: ProductFilterKeys.stock }, { children: [ @@ -102,7 +104,7 @@ const ProductListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Specific Price" }), - value: ProductFilterKeys.priceEqual.toString() + value: ProductFilterKeys.priceEqual }, { children: [], @@ -115,7 +117,7 @@ const ProductListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Range" }), - value: ProductFilterKeys.priceRange.toString() + value: ProductFilterKeys.priceRange } ], data: { @@ -127,7 +129,7 @@ const ProductListFilter: React.FC = props => { label: intl.formatMessage({ defaultMessage: "Price" }), - value: ProductFilterKeys.price.toString() + value: ProductFilterKeys.price } ]; diff --git a/src/products/components/ProductListPage/ProductListPage.tsx b/src/products/components/ProductListPage/ProductListPage.tsx index ec18734b2..fb083d483 100644 --- a/src/products/components/ProductListPage/ProductListPage.tsx +++ b/src/products/components/ProductListPage/ProductListPage.tsx @@ -26,12 +26,12 @@ import { } from "@saleor/types"; import { ProductListUrlFilters } from "../../urls"; import ProductList from "../ProductList"; -import ProductListFilter from "../ProductListFilter"; +import ProductListFilter, { ProductFilterKeys } from "../ProductListFilter"; export interface ProductListPageProps extends PageListProps, ListActions, - FilterPageProps, + FilterPageProps, FetchMoreProps { availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[]; currencySymbol: string; diff --git a/src/products/views/ProductList/__snapshots__/filters.test.ts.snap b/src/products/views/ProductList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..20fe2f275 --- /dev/null +++ b/src/products/views/ProductList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Crate filter chips 1`] = ` +Array [ + Object { + "label": "Price from $10.00", + "onClick": [Function], + }, + Object { + "label": "Price to $20.00", + "onClick": [Function], + }, + Object { + "label": "Available", + "onClick": [Function], + }, + Object { + "label": "Published", + "onClick": [Function], + }, +] +`; + +exports[`Create filter object with price 1`] = ` +Object { + "priceFrom": "10", + "priceTo": "10", +} +`; + +exports[`Create filter object with price range 1`] = ` +Object { + "priceFrom": Array [ + "10", + "20", + ], + "priceTo": Array [ + "10", + "20", + ], +} +`; + +exports[`Create filter object with publication status 1`] = ` +Object { + "isPublished": "false", +} +`; + +exports[`Create filter object with stock status 1`] = ` +Object { + "status": "OUT_OF_STOCK", +} +`; + +exports[`Get filter variables 1`] = ` +Object { + "isPublished": true, + "price": Object { + "gte": 10, + "lte": 20, + }, + "search": undefined, + "stockAvailability": "IN_STOCK", +} +`; diff --git a/src/products/views/ProductList/filters.test.ts b/src/products/views/ProductList/filters.test.ts new file mode 100644 index 000000000..cdb06af94 --- /dev/null +++ b/src/products/views/ProductList/filters.test.ts @@ -0,0 +1,77 @@ +import { createIntl } from "react-intl"; + +import { ProductFilterKeys } from "@saleor/products/components/ProductListFilter"; +import { StockAvailability } from "@saleor/types/globalTypes"; +import { createFilter, createFilterChips, getFilterVariables } from "./filters"; + +const mockIntl = createIntl({ + locale: "en" +}); + +describe("Create filter object", () => { + it("with price", () => { + const filter = createFilter({ + name: ProductFilterKeys.priceEqual, + value: "10" + }); + + expect(filter).toMatchSnapshot(); + }); + + it("with price range", () => { + const filter = createFilter({ + name: ProductFilterKeys.priceEqual, + value: ["10", "20"] + }); + + expect(filter).toMatchSnapshot(); + }); + + it("with publication status", () => { + const filter = createFilter({ + name: ProductFilterKeys.published, + value: "false" + }); + + expect(filter).toMatchSnapshot(); + }); + + it("with stock status", () => { + const filter = createFilter({ + name: ProductFilterKeys.stock, + value: StockAvailability.OUT_OF_STOCK + }); + + expect(filter).toMatchSnapshot(); + }); +}); + +test("Crate filter chips", () => { + const chips = createFilterChips( + { + isPublished: "true", + priceFrom: "10", + priceTo: "20", + status: StockAvailability.IN_STOCK + }, + { + currencySymbol: "USD", + locale: "en" + }, + jest.fn(), + mockIntl as any + ); + + expect(chips).toMatchSnapshot(); +}); + +test("Get filter variables", () => { + const filter = getFilterVariables({ + isPublished: "true", + priceFrom: "10", + priceTo: "20", + status: StockAvailability.IN_STOCK + }); + + expect(filter).toMatchSnapshot(); +}); diff --git a/src/products/views/ProductList/filters.ts b/src/products/views/ProductList/filters.ts index 3368e19b3..5a47fc9aa 100644 --- a/src/products/views/ProductList/filters.ts +++ b/src/products/views/ProductList/filters.ts @@ -34,26 +34,26 @@ export function getFilterVariables( } export function createFilter( - filter: FilterContentSubmitData + filter: FilterContentSubmitData ): ProductListUrlFilters { const filterName = filter.name; - if (filterName === ProductFilterKeys.priceEqual.toString()) { + if (filterName === ProductFilterKeys.priceEqual) { const value = filter.value as string; return { priceFrom: value, priceTo: value }; - } else if (filterName === ProductFilterKeys.priceRange.toString()) { + } else if (filterName === ProductFilterKeys.priceRange) { const { value } = filter; return { priceFrom: value[0], priceTo: value[1] }; - } else if (filterName === ProductFilterKeys.published.toString()) { + } else if (filterName === ProductFilterKeys.published) { return { isPublished: filter.value as string }; - } else if (filterName === ProductFilterKeys.stock.toString()) { + } else if (filterName === ProductFilterKeys.stock) { const value = filter.value as string; return { status: StockAvailability[value] diff --git a/src/types.ts b/src/types.ts index 27deb132c..68de233fb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -65,7 +65,7 @@ export interface PageListProps defaultSettings?: ListSettings; onAdd: () => void; } -export interface FilterPageProps { +export interface FilterPageProps { currencySymbol: string; currentTab: number; filterTabs: GetFilterTabsOutput; @@ -73,12 +73,13 @@ export interface FilterPageProps { initialSearch: string; onAll: () => void; onSearchChange: (value: string) => void; - onFilterAdd: (filter: FilterContentSubmitData) => void; + onFilterAdd: (filter: FilterContentSubmitData) => void; onFilterDelete: () => void; onFilterSave: () => void; onTabChange: (tab: number) => void; } -export interface FilterProps extends FilterPageProps { +export interface FilterProps + extends FilterPageProps { allTabLabel: string; filterLabel: string; searchPlaceholder: string; diff --git a/src/utils/menu/__snapshots__/menu.test.ts.snap b/src/utils/menu/__snapshots__/menu.test.ts.snap index 045953f35..c21c5d0bb 100644 --- a/src/utils/menu/__snapshots__/menu.test.ts.snap +++ b/src/utils/menu/__snapshots__/menu.test.ts.snap @@ -8,7 +8,7 @@ Array [ "label": "1", "parent": null, "sort": 0, - "value": "1", + "value": 0, }, Object { "data": null, @@ -16,7 +16,7 @@ Array [ "label": "2", "parent": null, "sort": 1, - "value": "2", + "value": 1, }, Object { "data": null, @@ -24,7 +24,7 @@ Array [ "label": "3", "parent": null, "sort": 2, - "value": "3", + "value": 2, }, Object { "data": null, @@ -32,7 +32,7 @@ Array [ "label": "4", "parent": null, "sort": 3, - "value": "4", + "value": 3, }, Object { "data": null, @@ -40,7 +40,7 @@ Array [ "label": "4.1", "parent": "3", "sort": 0, - "value": "4.1", + "value": 4, }, Object { "data": null, @@ -48,7 +48,7 @@ Array [ "label": "4.2", "parent": "3", "sort": 1, - "value": "4.2", + "value": 5, }, ] `; @@ -61,24 +61,24 @@ Array [ "children": Array [], "data": null, "label": "4.1", - "value": "4.1", + "value": 4, }, Object { "children": Array [], "data": null, "label": "4.2", - "value": "4.2", + "value": 5, }, ], "data": null, "label": "4", - "value": "4", + "value": 3, }, Object { "children": Array [], "data": null, "label": "4.1", - "value": "4.1", + "value": 4, }, ] `; @@ -89,7 +89,7 @@ Array [ "children": Array [], "data": null, "label": "4.1", - "value": "4.1", + "value": 4, }, Object { "children": Array [ @@ -97,18 +97,18 @@ Array [ "children": Array [], "data": null, "label": "4.1", - "value": "4.1", + "value": 4, }, Object { "children": Array [], "data": null, "label": "4.2", - "value": "4.2", + "value": 5, }, ], "data": null, "label": "4", - "value": "4", + "value": 3, }, ] `; diff --git a/src/utils/menu/menu.test.ts b/src/utils/menu/menu.test.ts index 9b6d6b65b..2e42c134e 100644 --- a/src/utils/menu/menu.test.ts +++ b/src/utils/menu/menu.test.ts @@ -9,24 +9,33 @@ import { walkToRoot } from "./menu"; -const validMenu: IMenu = [ +enum MenuKey { + one, + two, + three, + four, + fourOne, + foutTwo +} + +const validMenu: IMenu = [ { children: [], data: null, label: "1", - value: "1" + value: MenuKey.one }, { children: [], data: null, label: "2", - value: "2" + value: MenuKey.two }, { children: [], data: null, label: "3", - value: "3" + value: MenuKey.three }, { children: [ @@ -34,18 +43,18 @@ const validMenu: IMenu = [ children: [], data: null, label: "4.1", - value: "4.1" + value: MenuKey.fourOne }, { children: [], data: null, label: "4.2", - value: "4.2" + value: MenuKey.foutTwo } ], data: null, label: "4", - value: "4" + value: MenuKey.four } ]; diff --git a/src/utils/menu/menu.ts b/src/utils/menu/menu.ts index 4abae4363..55fba25ba 100644 --- a/src/utils/menu/menu.ts +++ b/src/utils/menu/menu.ts @@ -1,62 +1,76 @@ -interface IBaseMenuItem { +interface IBaseMenuItem { label: React.ReactNode; - value?: string; + value?: TValue; data: TMenuData | null; } -export type IFlatMenuItem = IBaseMenuItem & { +export type IFlatMenuItem = IBaseMenuItem< + TMenuData, + TValue +> & { id: string; parent: string | null; sort: number; }; -export type IMenuItem = IBaseMenuItem & { - children: Array>; +export type IMenuItem = IBaseMenuItem< + TMenuData, + TValue +> & { + children: Array>; }; -export type IMenu = Array>; -export type IFlatMenu = Array>; +export type IMenu = Array< + IMenuItem +>; +export type IFlatMenu = Array< + IFlatMenuItem +>; -export function validateMenuOptions( - menu: IMenu +export function validateMenuOptions( + menu: IMenu ): boolean { - const values: string[] = toFlat(menu) + const values: TValue[] = toFlat(menu) .map(menuItem => menuItem.value) .filter(value => value !== undefined); const uniqueValues = Array.from(new Set(values)); return uniqueValues.length === values.length; } -function _getMenuItemByPath( - menuItem: IMenuItem, +function _getMenuItemByPath( + menuItem: IMenuItem, path: number[] -): IMenuItem { +): IMenuItem { if (path.length === 0) { return menuItem; } return _getMenuItemByPath(menuItem.children[path[0]], path.slice(1)); } -export function getMenuItemByPath( - menu: IMenu, +export function getMenuItemByPath( + menu: IMenu, path: number[] -): IMenuItem { +): IMenuItem { return _getMenuItemByPath(menu[path[0]], path.slice(1)); } -export function getMenuItemByValue( - menu: IMenu, - value: string -): IMenuItem { +export function getMenuItemByValue( + menu: IMenu, + value: TValue +): IMenuItem { const flatMenu = toFlat(menu); - const flatMenuItem: IFlatMenuItem = flatMenu.find( + const flatMenuItem: IFlatMenuItem = flatMenu.find( menuItem => menuItem.value === value ); + if (flatMenuItem === undefined) { + throw new Error(`Value ${value} does not exist in menu`); + } + return _fromFlat(flatMenu, flatMenuItem); } -function _walkToMenuItem( - menuItem: IMenuItem, +function _walkToMenuItem( + menuItem: IMenuItem, path: number[] -): IMenu { +): IMenu { const node = menuItem.children[path[0]]; if (path.length === 1) { @@ -66,18 +80,18 @@ function _walkToMenuItem( return [node, ..._walkToMenuItem(node, path.slice(1))]; } -export function walkToMenuItem( - menu: IMenu, +export function walkToMenuItem( + menu: IMenu, path: number[] -): IMenu { +): IMenu { const walkByNode = menu[path[0]]; return [walkByNode, ..._walkToMenuItem(walkByNode, path.slice(1))]; } -function _walkToRoot( - flatMenu: IFlatMenu, +function _walkToRoot( + flatMenu: IFlatMenu, parent: string -): IFlatMenu { +): IFlatMenu { const menuItem = flatMenu.find(menuItem => menuItem.id === parent); if (menuItem.parent === null) { @@ -86,10 +100,10 @@ function _walkToRoot( return [menuItem, ..._walkToRoot(flatMenu, menuItem.parent)]; } -export function walkToRoot( - menu: IMenu, - value: string -): IMenu { +export function walkToRoot( + menu: IMenu, + value: TValue +): IMenu { const flatMenu = toFlat(menu); const menuItem = flatMenu.find(menuItem => menuItem.value === value); @@ -99,13 +113,13 @@ export function walkToRoot( ).map(flatMenuItem => _fromFlat(flatMenu, flatMenuItem)); } -function _toFlat( - menuItem: IMenuItem, +function _toFlat( + menuItem: IMenuItem, sort: number, parent: string -): IFlatMenu { +): IFlatMenu { const id = parent ? [parent, sort].join(":") : sort.toString(); - const flatMenuItem: IFlatMenuItem = { + const flatMenuItem: IFlatMenuItem = { data: menuItem.data, id, label: menuItem.label, @@ -117,22 +131,28 @@ function _toFlat( flatMenuItem, ...menuItem.children .map((child, childIndex) => _toFlat(child, childIndex, id)) - .reduce((acc, curr) => [...acc, ...curr], [] as IFlatMenu) + .reduce((acc, curr) => [...acc, ...curr], [] as IFlatMenu< + TMenuData, + TValue + >) ]; } -export function toFlat( - menu: IMenu -): IFlatMenu { +export function toFlat( + menu: IMenu +): IFlatMenu { return menu .map((menuItem, menuItemIndex) => _toFlat(menuItem, menuItemIndex, null)) - .reduce((acc, curr) => [...acc, ...curr], [] as IFlatMenu); + .reduce((acc, curr) => [...acc, ...curr], [] as IFlatMenu< + TMenuData, + TValue + >); } -function _fromFlat( - menu: IFlatMenu, - flatMenuItem: IFlatMenuItem -): IMenuItem { - const children: Array> = menu +function _fromFlat( + menu: IFlatMenu, + flatMenuItem: IFlatMenuItem +): IMenuItem { + const children: Array> = menu .filter(menuItem => menuItem.parent === flatMenuItem.id) .map(menuItem => _fromFlat(menu, menuItem)); @@ -143,16 +163,16 @@ function _fromFlat( value: flatMenuItem.value }; } -export function fromFlat( - menu: IFlatMenu -): IMenu { +export function fromFlat( + menu: IFlatMenu +): IMenu { return menu .filter(menuItem => menuItem.parent === null) .map(menuItem => _fromFlat(menu, menuItem)); } -export function isLeaf( - menuItem: IMenuItem +export function isLeaf( + menuItem: IMenuItem ): boolean { return menuItem.children.length === 0; } From 258847545d6213567d9071f4abfab02c99522e15 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 6 Sep 2019 15:41:02 +0200 Subject: [PATCH 3/6] Add ready to capture field --- src/home/views/index.tsx | 7 +++++-- .../components/OrderListFilter/OrderListFilter.tsx | 14 ++++++++++---- src/orders/views/OrderList/filters.ts | 9 ++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/home/views/index.tsx b/src/home/views/index.tsx index 116175d7c..63bba5deb 100644 --- a/src/home/views/index.tsx +++ b/src/home/views/index.tsx @@ -31,14 +31,17 @@ const HomeSection = () => { onOrdersToCaptureClick={() => navigate( orderListUrl({ - status: OrderStatusFilter.READY_TO_CAPTURE + status: [OrderStatusFilter.READY_TO_CAPTURE] }) ) } onOrdersToFulfillClick={() => navigate( orderListUrl({ - status: OrderStatusFilter.READY_TO_FULFILL + status: [ + OrderStatusFilter.UNFULFILLED, + OrderStatusFilter.PARTIALLY_FULFILLED + ] }) ) } diff --git a/src/orders/components/OrderListFilter/OrderListFilter.tsx b/src/orders/components/OrderListFilter/OrderListFilter.tsx index 06d9fa0d5..ca7547276 100644 --- a/src/orders/components/OrderListFilter/OrderListFilter.tsx +++ b/src/orders/components/OrderListFilter/OrderListFilter.tsx @@ -19,7 +19,7 @@ export enum OrderFilterKeys { dateLastWeek = "dateLastWeek", dateLastMonth = "dateLastMonth", dateLastYear = "dateLastYear", - fulfillment = "fulfillment" + status = "status" } const OrderListFilter: React.FC = props => { @@ -146,15 +146,21 @@ const OrderListFilter: React.FC = props => { description: "order fulfillment status" }), value: OrderStatusFilter.UNFULFILLED.toString() + }, + { + label: intl.formatMessage({ + defaultMessage: "Ready to Capture", + description: "order status" + }), + value: OrderStatusFilter.READY_TO_CAPTURE.toString() } ], type: FieldType.select }, label: intl.formatMessage({ - defaultMessage: "Fulfillment Status", - description: "order" + defaultMessage: "Order Status" }), - value: OrderFilterKeys.fulfillment + value: OrderFilterKeys.status } ]; diff --git a/src/orders/views/OrderList/filters.ts b/src/orders/views/OrderList/filters.ts index 46ad23977..db290ab37 100644 --- a/src/orders/views/OrderList/filters.ts +++ b/src/orders/views/OrderList/filters.ts @@ -46,6 +46,10 @@ const filterMessages = defineMessages({ defaultMessage: "Partially Fulfilled", description: "order status" }, + readyToCapture: { + defaultMessage: "Ready to Capture", + description: "order status" + }, unfulfilled: { defaultMessage: "Unfulfilled", description: "order status" @@ -62,6 +66,9 @@ function getStatusLabel(status: string, intl: IntlShape): string { case OrderStatusFilter.UNFULFILLED.toString(): return intl.formatMessage(filterMessages.unfulfilled); + + case OrderStatusFilter.READY_TO_CAPTURE.toString(): + return intl.formatMessage(filterMessages.readyToCapture); } return ""; @@ -110,7 +117,7 @@ export function createFilter( dateFrom: valueOrFirst(value), dateTo: undefined }; - } else if (filterName === OrderFilterKeys.fulfillment) { + } else if (filterName === OrderFilterKeys.status) { return { status: dedupeFilter( filter.status From bcc5264105fd3bde9763d1ae76c01a21eb16aae1 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 6 Sep 2019 15:47:22 +0200 Subject: [PATCH 4/6] Fix test --- src/orders/views/OrderList/filters.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/orders/views/OrderList/filters.test.ts b/src/orders/views/OrderList/filters.test.ts index 6217678b0..7864d9455 100644 --- a/src/orders/views/OrderList/filters.test.ts +++ b/src/orders/views/OrderList/filters.test.ts @@ -73,7 +73,7 @@ describe("Create filter object", () => { const filter = createFilter( {}, { - name: OrderFilterKeys.fulfillment, + name: OrderFilterKeys.status, value: OrderStatusFilter.PARTIALLY_FULFILLED } ); @@ -87,7 +87,7 @@ describe("Create filter object", () => { status: [OrderStatusFilter.FULFILLED] }, { - name: OrderFilterKeys.fulfillment, + name: OrderFilterKeys.status, value: OrderStatusFilter.PARTIALLY_FULFILLED } ); @@ -101,7 +101,7 @@ describe("Create filter object", () => { status: [OrderStatusFilter.FULFILLED] }, { - name: OrderFilterKeys.fulfillment, + name: OrderFilterKeys.status, value: OrderStatusFilter.FULFILLED } ); From 315c3b2dc076b8a09fd0387bd421087bf0500eec Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 6 Sep 2019 15:48:44 +0200 Subject: [PATCH 5/6] Update messages --- locale/messages.pot | 178 ++++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 57 deletions(-) diff --git a/locale/messages.pot b/locale/messages.pot index 375f88ea9..8197eddc2 100644 --- a/locale/messages.pot +++ b/locale/messages.pot @@ -1,6 +1,6 @@ msgid "" msgstr "" -"POT-Creation-Date: 2019-09-06T13:56:36.897Z\n" +"POT-Creation-Date: 2019-09-10T11:00:36.829Z\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "MIME-Version: 1.0\n" @@ -1439,6 +1439,10 @@ msgctxt "description" msgid "Availability" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.2157131639] - product status +#. defaultMessage is: +#. Available #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.2157131639] - product status #. defaultMessage is: @@ -3447,14 +3451,6 @@ msgctxt "order history message" msgid "Fulfilled {quantity} items" msgstr "" -#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json -#. [src.orders.components.OrderListFilter.2943502192] - order -#. defaultMessage is: -#. Fulfillment Status -msgctxt "order" -msgid "Fulfillment Status" -msgstr "" - #: build/locale/src/orders/components/OrderHistory/OrderHistory.json #. [src.orders.components.OrderHistory.3081292385] - order history message #. defaultMessage is: @@ -3555,14 +3551,10 @@ msgctxt "subheader" msgid "Here is some information we gathered about your store" msgstr "" -#: build/locale/src/components/VisibilityCard/VisibilityCard.json -#. [src.components.VisibilityCard.77815154] +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.77815154] - product is hidden #. defaultMessage is: #. Hidden -msgctxt "description" -msgid "Hidden" -msgstr "" - #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.77815154] - product is hidden #. defaultMessage is: @@ -3571,6 +3563,14 @@ msgctxt "product is hidden" msgid "Hidden" msgstr "" +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.77815154] +#. defaultMessage is: +#. Hidden +msgctxt "description" +msgid "Hidden" +msgstr "" + #: build/locale/src/products/views/ProductList/filters.json #. [src.products.views.ProductList.hidden] - filter products by visibility #. defaultMessage is: @@ -4871,6 +4871,14 @@ msgctxt "description" msgid "Order History" msgstr "" +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.2222765704] +#. defaultMessage is: +#. Order Status +msgctxt "description" +msgid "Order Status" +msgstr "" + #: build/locale/src/orders/components/OrderHistory/OrderHistory.json #. [src.orders.components.OrderHistory.1230178536] - order history message #. defaultMessage is: @@ -5027,6 +5035,10 @@ msgctxt "description" msgid "Original String" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.1640493122] - product status +#. defaultMessage is: +#. Out Of Stock #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.1640493122] - product status #. defaultMessage is: @@ -5363,6 +5375,18 @@ msgctxt "order payment" msgid "Preauthorized amount" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.1134347598] +#. defaultMessage is: +#. Price +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1134347598] +#. defaultMessage is: +#. Price +msgctxt "description" +msgid "Price" +msgstr "" + #: build/locale/src/categories/components/CategoryProductList/CategoryProductList.json #. [src.categories.components.CategoryProductList.1134347598] - product price #. defaultMessage is: @@ -5411,14 +5435,6 @@ msgctxt "product unit price" msgid "Price" msgstr "" -#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json -#. [src.products.components.ProductListFilter.1134347598] -#. defaultMessage is: -#. Price -msgctxt "description" -msgid "Price" -msgstr "" - #: build/locale/src/products/components/ProductVariants/ProductVariants.json #. [src.products.components.ProductVariants.1134347598] - product variant price #. defaultMessage is: @@ -5903,6 +5919,10 @@ msgctxt "description" msgid "Quick Pick" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.2545228781] +#. defaultMessage is: +#. Range #: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json #. [src.orders.components.OrderListFilter.2545228781] #. defaultMessage is: @@ -5939,6 +5959,18 @@ msgctxt "shipping method price" msgid "Rate Price" msgstr "" +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.2415661583] - order status +#. defaultMessage is: +#. Ready to Capture +#: build/locale/src/orders/views/OrderList/filters.json +#. [src.orders.views.OrderList.readyToCapture] - order status +#. defaultMessage is: +#. Ready to Capture +msgctxt "order status" +msgid "Ready to Capture" +msgstr "" + #: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json #. [src.customers.components.CustomerOrders.3878642352] - section header #. defaultMessage is: @@ -6803,6 +6835,10 @@ msgctxt "description" msgid "Specific Date" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.2844426531] +#. defaultMessage is: +#. Specific Price #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.2844426531] #. defaultMessage is: @@ -6883,6 +6919,18 @@ msgctxt "voucher is active from date" msgid "Starts" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.1756106276] - product status +#. defaultMessage is: +#. Status +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1756106276] - product status +#. defaultMessage is: +#. Status +msgctxt "product status" +msgid "Status" +msgstr "" + #: build/locale/src/customers/components/CustomerOrders/CustomerOrders.json #. [src.customers.components.CustomerOrders.1756106276] - order status #. defaultMessage is: @@ -6907,14 +6955,6 @@ msgctxt "plugin status" msgid "Status" msgstr "" -#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json -#. [src.products.components.ProductListFilter.1756106276] - product status -#. defaultMessage is: -#. Status -msgctxt "product status" -msgid "Status" -msgstr "" - #: build/locale/src/products/components/ProductVariants/ProductVariants.json #. [src.products.components.ProductVariants.1756106276] - product variant status #. defaultMessage is: @@ -6923,6 +6963,10 @@ msgctxt "product variant status" msgid "Status" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.3841616483] - product stock +#. defaultMessage is: +#. Stock #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.3841616483] - product stock #. defaultMessage is: @@ -6939,6 +6983,10 @@ msgctxt "product variant stock, section header" msgid "Stock" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.3645081351] +#. defaultMessage is: +#. Stock quantity #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.3645081351] #. defaultMessage is: @@ -8107,6 +8155,18 @@ msgctxt "description" msgid "View and update your site settings" msgstr "" +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.1459686496] - product visibility +#. defaultMessage is: +#. Visibility +#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json +#. [src.products.components.ProductListFilter.1459686496] - product visibility +#. defaultMessage is: +#. Visibility +msgctxt "product visibility" +msgid "Visibility" +msgstr "" + #: build/locale/src/components/VisibilityCard/VisibilityCard.json #. [src.components.VisibilityCard.1459686496] - section header #. defaultMessage is: @@ -8123,14 +8183,6 @@ msgctxt "page status" msgid "Visibility" msgstr "" -#: build/locale/src/products/components/ProductListFilter/ProductListFilter.json -#. [src.products.components.ProductListFilter.1459686496] - product visibility -#. defaultMessage is: -#. Visibility -msgctxt "product visibility" -msgid "Visibility" -msgstr "" - #: build/locale/src/attributes/components/AttributeList/AttributeList.json #. [src.attributes.components.AttributeList.643174786] - attribute is visible #. defaultMessage is: @@ -8139,14 +8191,10 @@ msgctxt "attribute is visible" msgid "Visible" msgstr "" -#: build/locale/src/components/VisibilityCard/VisibilityCard.json -#. [src.components.VisibilityCard.643174786] +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.643174786] - product is visible #. defaultMessage is: #. Visible -msgctxt "description" -msgid "Visible" -msgstr "" - #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.643174786] - product is visible #. defaultMessage is: @@ -8155,6 +8203,14 @@ msgctxt "product is visible" msgid "Visible" msgstr "" +#: build/locale/src/components/VisibilityCard/VisibilityCard.json +#. [src.components.VisibilityCard.643174786] +#. defaultMessage is: +#. Visible +msgctxt "description" +msgid "Visible" +msgstr "" + #: build/locale/src/attributes/components/AttributeProperties/AttributeProperties.json #. [src.attributes.components.AttributeProperties.3876764312] - attribute #. defaultMessage is: @@ -8303,14 +8359,10 @@ msgctxt "order does not require shipping" msgid "does not apply" msgstr "" -#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json -#. [src.orders.components.OrderListFilter.3477667254] +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.3477667254] - product price #. defaultMessage is: #. equals -msgctxt "description" -msgid "equals" -msgstr "" - #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.3477667254] - product price #. defaultMessage is: @@ -8319,6 +8371,14 @@ msgctxt "product price" msgid "equals" msgstr "" +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.3477667254] +#. defaultMessage is: +#. equals +msgctxt "description" +msgid "equals" +msgstr "" + #: build/locale/src/components/Filter/FilterElement.json #. [src.components.Filter.2755325844] #. defaultMessage is: @@ -8343,14 +8403,10 @@ msgctxt "weight" msgid "from {value} {unit}" msgstr "" -#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json -#. [src.orders.components.OrderListFilter.1438173764] - date is set as +#: build/locale/src/attributes/components/ProductListFilter/ProductListFilter.json +#. [src.attributes.components.ProductListFilter.1438173764] - product status is set as #. defaultMessage is: #. is set as -msgctxt "date is set as" -msgid "is set as" -msgstr "" - #: build/locale/src/products/components/ProductListFilter/ProductListFilter.json #. [src.products.components.ProductListFilter.1438173764] - product status is set as #. defaultMessage is: @@ -8359,6 +8415,14 @@ msgctxt "product status is set as" msgid "is set as" msgstr "" +#: build/locale/src/orders/components/OrderListFilter/OrderListFilter.json +#. [src.orders.components.OrderListFilter.1438173764] - date is set as +#. defaultMessage is: +#. is set as +msgctxt "date is set as" +msgid "is set as" +msgstr "" + #: build/locale/src/staff/views/StaffDetails.json #. [src.staff.views.2240444792] - dialog header #. defaultMessage is: From 2ae84e7f6c30102db9e8164bab65de521fbd862b Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Fri, 6 Sep 2019 15:50:16 +0200 Subject: [PATCH 6/6] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f57dbf3..a4cecca6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,4 @@ All notable, unreleased changes to this project will be documented in this file. - Add fallback locale - #153 by @dominik-zeglen - Replace checkbox with switch component in "product type has variants" - #152 by @dominik-zeglen - Add password reset flow - #147 by @dominik-zeglen +- Add support for multiple values in filters - #160 by @dominik-zeglen