Make order filters work

This commit is contained in:
dominik-zeglen 2019-12-20 11:44:41 +01:00
parent aafa6b62dc
commit 32cdb56e6f
14 changed files with 208 additions and 589 deletions

View file

@ -26,18 +26,16 @@ const props: MultiAutocompleteSelectFieldProps = {
value: undefined value: undefined
}; };
const Story: React.FC< const Story: React.FC<Partial<
Partial<
MultiAutocompleteSelectFieldProps & { MultiAutocompleteSelectFieldProps & {
enableLoadMore: boolean; enableLoadMore: boolean;
} }
> >> = ({ allowCustomValues, enableLoadMore }) => {
> = ({ allowCustomValues, enableLoadMore }) => {
const { change, data: countries } = useMultiAutocomplete([suggestions[0]]); const { change, data: countries } = useMultiAutocomplete([suggestions[0]]);
return ( return (
<ChoiceProvider choices={suggestions}> <ChoiceProvider choices={suggestions}>
{({ choices, fetchChoices, fetchMore, hasMore, loading }) => ( {({ choices, fetchChoices, onFetchMore, hasMore, loading }) => (
<MultiAutocompleteSelectField <MultiAutocompleteSelectField
{...props} {...props}
displayValues={countries} displayValues={countries}
@ -50,7 +48,7 @@ const Story: React.FC<
value={countries.map(country => country.value)} value={countries.map(country => country.value)}
loading={loading} loading={loading}
hasMore={enableLoadMore ? hasMore : false} hasMore={enableLoadMore ? hasMore : false}
onFetchMore={enableLoadMore ? fetchMore : undefined} onFetchMore={enableLoadMore ? onFetchMore : undefined}
allowCustomValues={allowCustomValues} allowCustomValues={allowCustomValues}
/> />
)} )}

View file

@ -27,20 +27,18 @@ const props: SingleAutocompleteSelectFieldProps = {
value: suggestions[0].value value: suggestions[0].value
}; };
const Story: React.FC< const Story: React.FC<Partial<
Partial<
SingleAutocompleteSelectFieldProps & { SingleAutocompleteSelectFieldProps & {
enableLoadMore: boolean; enableLoadMore: boolean;
} }
> >> = ({ allowCustomValues, emptyOption, enableLoadMore }) => {
> = ({ allowCustomValues, emptyOption, enableLoadMore }) => {
const [displayValue, setDisplayValue] = React.useState(suggestions[0].label); const [displayValue, setDisplayValue] = React.useState(suggestions[0].label);
return ( return (
<Form initial={{ country: suggestions[0].value }}> <Form initial={{ country: suggestions[0].value }}>
{({ change, data }) => ( {({ change, data }) => (
<ChoiceProvider choices={suggestions}> <ChoiceProvider choices={suggestions}>
{({ choices, fetchChoices, fetchMore, hasMore, loading }) => { {({ choices, fetchChoices, onFetchMore, hasMore, loading }) => {
const handleSelect = createSingleAutocompleteSelectHandler( const handleSelect = createSingleAutocompleteSelectHandler(
change, change,
setDisplayValue, setDisplayValue,
@ -58,7 +56,7 @@ const Story: React.FC<
onChange={handleSelect} onChange={handleSelect}
value={data.country} value={data.country}
hasMore={enableLoadMore ? hasMore : false} hasMore={enableLoadMore ? hasMore : false}
onFetchMore={enableLoadMore ? fetchMore : undefined} onFetchMore={enableLoadMore ? onFetchMore : undefined}
allowCustomValues={allowCustomValues} allowCustomValues={allowCustomValues}
emptyOption={emptyOption} emptyOption={emptyOption}
/> />

View file

@ -115,7 +115,7 @@ export const transformPaymentStatus = (status: string, intl: IntlShape) => {
} }
}; };
const orderStatusMessages = defineMessages({ export const orderStatusMessages = defineMessages({
cancelled: { cancelled: {
defaultMessage: "Cancelled", defaultMessage: "Cancelled",
description: "order status" description: "order status"

View file

@ -1,169 +0,0 @@
import moment from "moment-timezone";
import React from "react";
import { useIntl } from "react-intl";
import { DateContext } from "@saleor/components/Date/DateContext";
import { FieldType, IFilter } from "@saleor/components/Filter";
import FilterBar from "@saleor/components/FilterBar";
import TimezoneContext from "@saleor/components/Timezone";
import { FilterProps } from "../../../types";
import { OrderStatusFilter } from "../../../types/globalTypes";
type OrderListFilterProps = FilterProps<OrderFilterKeys>;
export enum OrderFilterKeys {
date = "date",
dateEqual = "dateEqual",
dateRange = "dateRange",
dateLastWeek = "dateLastWeek",
dateLastMonth = "dateLastMonth",
dateLastYear = "dateLastYear",
status = "status"
}
const OrderListFilter: React.FC<OrderListFilterProps> = props => {
const date = React.useContext(DateContext);
const tz = React.useContext(TimezoneContext);
const intl = useIntl();
const filterMenu: IFilter<OrderFilterKeys> = [
{
children: [
{
children: [],
data: {
fieldLabel: null,
type: FieldType.hidden,
value: (tz ? moment(date).tz(tz) : moment(date))
.subtract(7, "days")
.toISOString()
.split("T")[0] // Remove timezone
},
label: intl.formatMessage({
defaultMessage: "Last 7 Days"
}),
value: OrderFilterKeys.dateLastWeek
},
{
children: [],
data: {
fieldLabel: null,
type: FieldType.hidden,
value: (tz ? moment(date).tz(tz) : moment(date))
.subtract(30, "days")
.toISOString()
.split("T")[0] // Remove timezone
},
label: intl.formatMessage({
defaultMessage: "Last 30 Days"
}),
value: OrderFilterKeys.dateLastMonth
},
{
children: [],
data: {
fieldLabel: null,
type: FieldType.hidden,
value: (tz ? moment(date).tz(tz) : moment(date))
.subtract(1, "years")
.toISOString()
.split("T")[0] // Remove timezone
},
label: intl.formatMessage({
defaultMessage: "Last Year"
}),
value: OrderFilterKeys.dateLastYear
},
{
children: [],
data: {
additionalText: intl.formatMessage({
defaultMessage: "equals"
}),
fieldLabel: null,
type: FieldType.date
},
label: intl.formatMessage({
defaultMessage: "Specific Date"
}),
value: OrderFilterKeys.dateEqual
},
{
children: [],
data: {
fieldLabel: intl.formatMessage({
defaultMessage: "Range"
}),
type: FieldType.rangeDate
},
label: intl.formatMessage({
defaultMessage: "Range"
}),
value: OrderFilterKeys.dateRange
}
],
data: {
fieldLabel: intl.formatMessage({
defaultMessage: "Date"
}),
type: FieldType.select
},
label: intl.formatMessage({
defaultMessage: "Date"
}),
value: OrderFilterKeys.date
},
{
children: [],
data: {
additionalText: intl.formatMessage({
defaultMessage: "is set as",
description: "date is set as"
}),
fieldLabel: intl.formatMessage({
defaultMessage: "Status",
description: "order fulfillment status"
}),
options: [
{
label: intl.formatMessage({
defaultMessage: "Fulfilled",
description: "order fulfillment status"
}),
value: OrderStatusFilter.FULFILLED.toString()
},
{
label: intl.formatMessage({
defaultMessage: "Partially Fulfilled",
description: "order fulfillment status"
}),
value: OrderStatusFilter.PARTIALLY_FULFILLED.toString()
},
{
label: intl.formatMessage({
defaultMessage: "Unfulfilled",
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: "Order Status"
}),
value: OrderFilterKeys.status
}
];
return <FilterBar {...props} filterMenu={filterMenu} />;
};
OrderListFilter.displayName = "OrderListFilter";
export default OrderListFilter;

View file

@ -1,2 +0,0 @@
export { default } from "./OrderListFilter";
export * from "./OrderListFilter";

View file

@ -14,9 +14,13 @@ import {
SortPage SortPage
} from "@saleor/types"; } from "@saleor/types";
import { OrderListUrlSortField } from "@saleor/orders/urls"; import { OrderListUrlSortField } from "@saleor/orders/urls";
import {
OrderFilterKeys,
createFilterStructure
} from "@saleor/orders/views/OrderList/filters";
import FilterBar from "@saleor/components/FilterBar";
import { OrderList_orders_edges_node } from "../../types/OrderList"; import { OrderList_orders_edges_node } from "../../types/OrderList";
import OrderList from "../OrderList"; import OrderList from "../OrderList";
import OrderListFilter, { OrderFilterKeys } from "../OrderListFilter";
export interface OrderListPageProps export interface OrderListPageProps
extends PageListProps, extends PageListProps,
@ -29,13 +33,12 @@ export interface OrderListPageProps
const OrderListPage: React.FC<OrderListPageProps> = ({ const OrderListPage: React.FC<OrderListPageProps> = ({
currencySymbol, currencySymbol,
currentTab, currentTab,
filtersList,
initialSearch, initialSearch,
tabs, tabs,
onAdd, onAdd,
onAll, onAll,
onSearchChange, onSearchChange,
onFilterAdd, onFilterChange,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
onTabSave, onTabSave,
@ -43,6 +46,8 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const filterStructure = createFilterStructure(intl);
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.orders)}> <PageHeader title={intl.formatMessage(sectionNames.orders)}>
@ -54,28 +59,25 @@ const OrderListPage: React.FC<OrderListPageProps> = ({
</Button> </Button>
</PageHeader> </PageHeader>
<Card> <Card>
<OrderListFilter <FilterBar
allTabLabel={intl.formatMessage({
defaultMessage: "All Orders",
description: "tab name"
})}
currencySymbol={currencySymbol} currencySymbol={currencySymbol}
currentTab={currentTab} currentTab={currentTab}
filterLabel={intl.formatMessage({
defaultMessage: "Select all orders where:"
})}
tabs={tabs}
filtersList={filtersList}
initialSearch={initialSearch} initialSearch={initialSearch}
searchPlaceholder={intl.formatMessage({
defaultMessage: "Search Orders..."
})}
onAll={onAll} onAll={onAll}
onFilterChange={onFilterChange}
onSearchChange={onSearchChange} onSearchChange={onSearchChange}
onFilterAdd={onFilterAdd}
onTabChange={onTabChange} onTabChange={onTabChange}
onTabDelete={onTabDelete} onTabDelete={onTabDelete}
onTabSave={onTabSave} onTabSave={onTabSave}
tabs={tabs}
allTabLabel={intl.formatMessage({
defaultMessage: "All Products",
description: "tab name"
})}
filterStructure={filterStructure}
searchPlaceholder={intl.formatMessage({
defaultMessage: "Search Products..."
})}
/> />
<OrderList {...listProps} /> <OrderList {...listProps} />
</Card> </Card>

View file

@ -17,8 +17,8 @@ const orderSectionUrl = "/orders";
export const orderListPath = orderSectionUrl; export const orderListPath = orderSectionUrl;
export enum OrderListUrlFiltersEnum { export enum OrderListUrlFiltersEnum {
dateFrom = "dateFrom", createdFrom = "createdFrom",
dateTo = "dateTo", createdTo = "createdTo",
email = "email", email = "email",
payment = "payment", payment = "payment",
query = "query" query = "query"

View file

@ -7,7 +7,6 @@ import SaveFilterTabDialog, {
SaveFilterTabDialogFormData SaveFilterTabDialogFormData
} from "@saleor/components/SaveFilterTabDialog"; } from "@saleor/components/SaveFilterTabDialog";
import useBulkActions from "@saleor/hooks/useBulkActions"; import useBulkActions from "@saleor/hooks/useBulkActions";
import useDateLocalize from "@saleor/hooks/useDateLocalize";
import useListSettings from "@saleor/hooks/useListSettings"; import useListSettings from "@saleor/hooks/useListSettings";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -20,6 +19,7 @@ import { ListViews } from "@saleor/types";
import createSortHandler from "@saleor/utils/handlers/sortHandler"; import createSortHandler from "@saleor/utils/handlers/sortHandler";
import { getSortParams } from "@saleor/utils/sort"; import { getSortParams } from "@saleor/utils/sort";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { IFilter } from "@saleor/components/Filter";
import OrderBulkCancelDialog from "../../components/OrderBulkCancelDialog"; import OrderBulkCancelDialog from "../../components/OrderBulkCancelDialog";
import OrderListPage from "../../components/OrderListPage/OrderListPage"; import OrderListPage from "../../components/OrderListPage/OrderListPage";
import { import {
@ -38,13 +38,13 @@ import {
} from "../../urls"; } from "../../urls";
import { import {
areFiltersApplied, areFiltersApplied,
createFilter,
createFilterChips,
deleteFilterTab, deleteFilterTab,
getActiveFilters, getActiveFilters,
getFilterTabs, getFilterTabs,
getFilterVariables, getFilterVariables,
saveFilterTab saveFilterTab,
OrderFilterKeys,
createFilterQueryParams
} from "./filters"; } from "./filters";
import { getSortQueryVariables } from "./sort"; import { getSortQueryVariables } from "./sort";
@ -53,7 +53,6 @@ interface OrderListProps {
} }
export const OrderList: React.FC<OrderListProps> = ({ params }) => { export const OrderList: React.FC<OrderListProps> = ({ params }) => {
const formatDate = useDateLocalize();
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const paginate = usePaginator(); const paginate = usePaginator();
@ -90,20 +89,36 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
const changeFilters = (filters: OrderListUrlFilters) => { const changeFilters = (filters: OrderListUrlFilters) => {
reset(); reset();
navigate(orderListUrl(filters)); navigate(
orderListUrl({
...params,
...filters
})
);
}; };
const changeFilterField = (filter: OrderListUrlFilters) => { const changeFilterField = (filter: IFilter<OrderFilterKeys>) => {
reset(); reset();
navigate( navigate(
orderListUrl({ orderListUrl({
...getActiveFilters(params), ...params,
...filter, ...createFilterQueryParams(filter),
activeTab: undefined activeTab: undefined
}) })
); );
}; };
const handleSearchChange = (query: string) => {
reset();
navigate(
orderListUrl({
...params,
activeTab: undefined,
query
})
);
};
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
OrderListUrlDialog, OrderListUrlDialog,
OrderListUrlQueryParams OrderListUrlQueryParams
@ -183,14 +198,6 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
<OrderListPage <OrderListPage
currencySymbol={currencySymbol} currencySymbol={currencySymbol}
settings={settings} settings={settings}
filtersList={createFilterChips(
params,
{
formatDate
},
changeFilterField,
intl
)}
currentTab={currentTab} currentTab={currentTab}
disabled={loading} disabled={loading}
orders={maybe(() => data.orders.edges.map(edge => edge.node))} orders={maybe(() => data.orders.edges.map(edge => edge.node))}
@ -221,10 +228,8 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
/> />
</Button> </Button>
} }
onSearchChange={query => changeFilterField({ query })} onSearchChange={handleSearchChange}
onFilterAdd={data => onFilterChange={filter => changeFilterField(filter)}
changeFilterField(createFilter(params, data))
}
onTabSave={() => openModal("save-search")} onTabSave={() => openModal("save-search")}
onTabDelete={() => openModal("delete-search")} onTabDelete={() => openModal("delete-search")}
onTabChange={handleTabChange} onTabChange={handleTabChange}

View file

@ -1,150 +1,10 @@
import { createIntl } from "react-intl"; import { OrderStatus } from "@saleor/types/globalTypes";
import { getFilterVariables } from "./filters";
import { OrderFilterKeys } from "@saleor/orders/components/OrderListFilter"; test("Get filter variables", () => {
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.status,
value: OrderStatusFilter.PARTIALLY_FULFILLED
}
);
expect(filter).toMatchSnapshot();
});
it("with multiple values", () => {
const filter = createFilter(
{
status: [OrderStatusFilter.FULFILLED]
},
{
name: OrderFilterKeys.status,
value: OrderStatusFilter.PARTIALLY_FULFILLED
}
);
expect(filter).toMatchSnapshot();
});
it("with multiple deduped values", () => {
const filter = createFilter(
{
status: [OrderStatusFilter.FULFILLED]
},
{
name: OrderFilterKeys.status,
value: OrderStatusFilter.FULFILLED
}
);
expect(filter).toMatchSnapshot();
});
});
test("Crate filter chips", () => {
const chips = createFilterChips(
{
dateFrom: "2019-09-01",
dateTo: "2019-09-10",
email: "email@example.com",
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({ const filter = getFilterVariables({
dateFrom: "2019-09-01", createdFrom: "2019-09-01",
dateTo: "2019-09-10", createdTo: "2019-09-10",
email: "email@example.com",
query: "24",
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", email: "email@example.com",
query: "24", query: "24",
status: [ status: [
@ -154,5 +14,4 @@ describe("Get filter variables", () => {
}); });
expect(filter).toMatchSnapshot(); expect(filter).toMatchSnapshot();
});
}); });

View file

@ -1,78 +1,92 @@
import { defineMessages, IntlShape } from "react-intl"; import { IntlShape } from "react-intl";
import { findInEnum } from "@saleor/misc"; import { findInEnum, maybe, orderStatusMessages } from "@saleor/misc";
import { removeAtIndex } from "@saleor/utils/lists"; import {
import { FilterContentSubmitData } from "../../../components/Filter"; createDateField,
import { Filter } from "../../../components/TableFilter"; createOptionsField
} from "@saleor/utils/filters/fields";
import { IFilter, IFilterElement } from "../../../components/Filter";
import { import {
OrderFilterInput, OrderFilterInput,
OrderStatusFilter OrderStatusFilter,
OrderStatus
} from "../../../types/globalTypes"; } from "../../../types/globalTypes";
import { import {
arrayOrUndefined,
arrayOrValue,
createFilterTabUtils, createFilterTabUtils,
createFilterUtils, createFilterUtils,
dedupeFilter, dedupeFilter
valueOrFirst
} from "../../../utils/filters"; } from "../../../utils/filters";
import { OrderFilterKeys } from "../../components/OrderListFilter";
import { import {
OrderListUrlFilters, OrderListUrlFilters,
OrderListUrlFiltersEnum, OrderListUrlFiltersEnum,
OrderListUrlFiltersWithMultipleValuesEnum, OrderListUrlFiltersWithMultipleValuesEnum,
OrderListUrlQueryParams OrderListUrlQueryParams
} from "../../urls"; } from "../../urls";
import messages from "./messages";
export const ORDER_FILTERS_KEY = "orderFilters"; export const ORDER_FILTERS_KEY = "orderFilters";
const filterMessages = defineMessages({ export enum OrderFilterKeys {
dateFrom: { created = "created",
defaultMessage: "Date from {date}", status = "status"
description: "filter by date" }
},
dateIs: { export function createFilterStructure(
defaultMessage: "Date is {date}", intl: IntlShape,
description: "filter by date" params: OrderListUrlFilters
}, ): IFilter<OrderFilterKeys> {
dateTo: { return [
defaultMessage: "Date to {date}", {
description: "filter by date" ...createDateField(
}, OrderFilterKeys.created,
fulfilled: { intl.formatMessage(messages.placed),
defaultMessage: "Fulfilled", {
description: "order status" max: maybe(() => params.createdTo, ""),
}, min: maybe(() => params.createdFrom, "")
partiallyFulfilled: {
defaultMessage: "Partially Fulfilled",
description: "order status"
},
readyToCapture: {
defaultMessage: "Ready to Capture",
description: "order status"
},
unfulfilled: {
defaultMessage: "Unfulfilled",
description: "order status"
} }
}); ),
active: maybe(
function getStatusLabel(status: string, intl: IntlShape): string { () =>
switch (status) { [params.createdFrom, params.createdTo].some(
case OrderStatusFilter.FULFILLED.toString(): field => field !== undefined
return intl.formatMessage(filterMessages.fulfilled); ),
false
case OrderStatusFilter.PARTIALLY_FULFILLED.toString(): )
return intl.formatMessage(filterMessages.partiallyFulfilled); },
{
case OrderStatusFilter.UNFULFILLED.toString(): ...createOptionsField(
return intl.formatMessage(filterMessages.unfulfilled); OrderFilterKeys.status,
intl.formatMessage(messages.status),
case OrderStatusFilter.READY_TO_CAPTURE.toString(): maybe(
return intl.formatMessage(filterMessages.readyToCapture); () =>
dedupeFilter(
params.status.map(status => findInEnum(status, OrderStatusFilter))
),
[]
),
true,
[
{
label: intl.formatMessage(orderStatusMessages.cancelled),
value: OrderStatusFilter.CANCELED
},
{
label: intl.formatMessage(orderStatusMessages.fulfilled),
value: OrderStatusFilter.FULFILLED
},
{
label: intl.formatMessage(orderStatusMessages.partiallyFulfilled),
value: OrderStatusFilter.PARTIALLY_FULFILLED
},
{
label: intl.formatMessage(orderStatusMessages.unfulfilled),
value: OrderStatusFilter.UNFULFILLED
} }
]
return ""; ),
active: maybe(() => params.status !== undefined, false)
}
];
} }
export function getFilterVariables( export function getFilterVariables(
@ -80,159 +94,47 @@ export function getFilterVariables(
): OrderFilterInput { ): OrderFilterInput {
return { return {
created: { created: {
gte: params.dateFrom, gte: params.createdFrom,
lte: params.dateTo lte: params.createdTo
}, },
customer: params.email, customer: params.email,
search: params.query, search: params.query,
status: Array.isArray(params.status) status: maybe(() =>
? params.status.map(status => findInEnum(status, OrderStatusFilter)) params.status.map(status => findInEnum(status, OrderStatusFilter))
: params.status )
? [findInEnum(params.status, OrderStatusFilter)]
: undefined
}; };
} }
export function createFilter( export function getFilterQueryParam(
filter: OrderListUrlFilters, filter: IFilterElement<OrderFilterKeys>
data: FilterContentSubmitData<OrderFilterKeys>
): OrderListUrlFilters { ): OrderListUrlFilters {
const { name: filterName, value } = data; const { active, name, value } = filter;
if (filterName === OrderFilterKeys.dateEqual) {
if (active) {
switch (name) {
case OrderFilterKeys.created:
return { return {
dateFrom: valueOrFirst(value), createdFrom: value[0],
dateTo: valueOrFirst(value) createdTo: value[1]
}; };
} else if (filterName === OrderFilterKeys.dateRange) {
case OrderFilterKeys.status:
return { return {
dateFrom: value[0], status: value.map(val => findInEnum(val, OrderStatus))
dateTo: value[1]
};
} else if (
[
OrderFilterKeys.dateLastWeek,
OrderFilterKeys.dateLastMonth,
OrderFilterKeys.dateLastYear
].includes(filterName)
) {
return {
dateFrom: valueOrFirst(value),
dateTo: undefined
};
} else if (filterName === OrderFilterKeys.status) {
return {
status: dedupeFilter(
filter.status
? [...(filter.status as string[]), valueOrFirst(value)]
: arrayOrValue(value)
)
}; };
} }
}
} }
export function createFilterQueryParams(
interface OrderListChipFormatData { filter: IFilter<OrderFilterKeys>
formatDate: (date: string) => string; ): OrderListUrlFilters {
} return filter.reduce(
export function createFilterChips( (acc, filterField) => ({
filters: OrderListUrlFilters, ...acc,
formatData: OrderListChipFormatData, ...getFilterQueryParam(filterField)
onFilterDelete: (filters: OrderListUrlFilters) => void,
intl: IntlShape
): Filter[] {
let filterChips: Filter[] = [];
if (!!filters.dateFrom || !!filters.dateTo) {
if (filters.dateFrom === filters.dateTo) {
filterChips = [
...filterChips,
{
label: intl.formatMessage(filterMessages.dateIs, {
date: formatData.formatDate(filters.dateFrom)
}), }),
onClick: () => {}
onFilterDelete({ );
...filters,
dateFrom: undefined,
dateTo: undefined
})
}
];
} else {
if (!!filters.dateFrom) {
filterChips = [
...filterChips,
{
label: intl.formatMessage(filterMessages.dateFrom, {
date: formatData.formatDate(filters.dateFrom)
}),
onClick: () =>
onFilterDelete({
...filters,
dateFrom: undefined
})
}
];
}
if (!!filters.dateTo) {
filterChips = [
...filterChips,
{
label: intl.formatMessage(filterMessages.dateTo, {
date: formatData.formatDate(filters.dateTo)
}),
onClick: () =>
onFilterDelete({
...filters,
dateTo: undefined
})
}
];
}
}
}
if (!!filters.email) {
filterChips = [
...filterChips,
{
label: filters.email,
onClick: () =>
onFilterDelete({
...filters,
email: undefined
})
}
];
}
if (!!filters.status) {
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;
} }
export const { export const {

View file

@ -0,0 +1,29 @@
import { defineMessages } from "react-intl";
const messages = defineMessages({
fulfilled: {
defaultMessage: "Fulfilled",
description: "order status"
},
partiallyFulfilled: {
defaultMessage: "Partially Fulfilled",
description: "order status"
},
placed: {
defaultMessage: "Placed",
description: "order"
},
readyToCapture: {
defaultMessage: "Ready to Capture",
description: "order status"
},
status: {
defaultMessage: "Order Status"
},
unfulfilled: {
defaultMessage: "Unfulfilled",
description: "order status"
}
});
export default messages;

View file

@ -161,9 +161,6 @@ export const ProductListPage: React.FC<ProductListPageProps> = props => {
description: "tab name" description: "tab name"
})} })}
filterStructure={filterStructure} filterStructure={filterStructure}
filterLabel={intl.formatMessage({
defaultMessage: "Select all products where:"
})}
searchPlaceholder={intl.formatMessage({ searchPlaceholder={intl.formatMessage({
defaultMessage: "Search Products..." defaultMessage: "Search Products..."
})} })}

View file

@ -13,7 +13,7 @@ import Decorator from "../../Decorator";
const props: FilterContentProps = { const props: FilterContentProps = {
currencySymbol: "USD", currencySymbol: "USD",
filters: [ filters: [
createPriceField("price", "Price", "USD", { createPriceField("price", "Price", {
max: "100.00", max: "100.00",
min: "20.00" min: "20.00"
}), }),

View file

@ -136,7 +136,7 @@ export type Filters<TFilters extends string> = Partial<
Record<TFilters, string> Record<TFilters, string>
>; >;
export type FiltersWithMultipleValues<TFilters extends string> = Partial< export type FiltersWithMultipleValues<TFilters extends string> = Partial<
Record<TFilters, string | string[]> Record<TFilters, string[]>
>; >;
export type SingleAction = Partial<{ export type SingleAction = Partial<{
id: string; id: string;