Saleor 1636 add possibility to filter through channels in order view (#929)

* Add possibility to filter through channels in order view

* Update storybook and locale

* Refactor

* Refactor to mapNodetoChoice

* Fix conditional value in array implicit syntax

Co-authored-by: Jakub Majorek <majorek.jakub@gmail.com>
This commit is contained in:
Marek Choiński 2021-01-13 10:50:54 +01:00 committed by GitHub
parent d0be941ade
commit 4a8ebd5b1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 103 additions and 45 deletions

View file

@ -3550,6 +3550,10 @@
"context": "tab name",
"string": "All Orders"
},
"src_dot_orders_dot_components_dot_OrderListPage_dot_channel": {
"context": "order",
"string": "Channel"
},
"src_dot_orders_dot_components_dot_OrderListPage_dot_customer": {
"context": "order",
"string": "Customer"

View file

@ -3042,6 +3042,7 @@ input OrderFilterInput {
customer: String
created: DateRangeInput
search: String
channels: [ID]
}
type OrderFulfill {

View file

@ -1,4 +1,5 @@
import Decorator from "@saleor/storybook/Decorator";
import { mapNodeToChoice } from "@saleor/utils/maps";
import { storiesOf } from "@storybook/react";
import React from "react";
@ -8,10 +9,7 @@ import ChannelDeleteDialog, {
} from "./ChannelDeleteDialog";
const props: ChannelDeleteDialogProps = {
channelsChoices: channelsList.map(channel => ({
label: channel.name,
value: channel.id
})),
channelsChoices: mapNodeToChoice(channelsList),
hasOrders: true,
confirmButtonState: "default",
onBack: () => undefined,

View file

@ -1,4 +1,5 @@
import Decorator from "@saleor/storybook/Decorator";
import { mapNodeToChoice } from "@saleor/utils/maps";
import { storiesOf } from "@storybook/react";
import React from "react";
@ -7,10 +8,7 @@ import ChannelPickerDialog, {
ChannelPickerDialogProps
} from "./ChannelPickerDialog";
const channelsChoices = channelsList.map(channel => ({
label: channel.name,
value: channel.id
}));
const channelsChoices = mapNodeToChoice(channelsList);
const props: ChannelPickerDialogProps = {
channelsChoices,

View file

@ -157,6 +157,7 @@ const FilterContent: React.FC<FilterContentProps> = ({
</div>
<Hr />
{filters
.filter(filter => !!filter)
.sort((a, b) => (a.name > b.name ? 1 : -1))
.map(filterField => (
<React.Fragment key={filterField.name}>

View file

@ -1,4 +1,5 @@
import { IFilter } from "@saleor/components/Filter";
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
import { commonMessages } from "@saleor/intl";
import { orderStatusMessages } from "@saleor/misc";
import { FilterOpts, MinMax } from "@saleor/types";
@ -13,16 +14,22 @@ import { defineMessages, IntlShape } from "react-intl";
export enum OrderFilterKeys {
created = "created",
customer = "customer",
status = "status"
status = "status",
channel = "channel"
}
export interface OrderListFilterOpts {
created: FilterOpts<MinMax>;
customer: FilterOpts<string>;
status: FilterOpts<OrderStatusFilter[]>;
channel?: FilterOpts<MultiAutocompleteChoiceType[]>;
}
const messages = defineMessages({
channel: {
defaultMessage: "Channel",
description: "order"
},
customer: {
defaultMessage: "Customer",
description: "order"
@ -88,6 +95,20 @@ export function createFilterStructure(
]
),
active: opts.status.active
}
},
...(opts?.channel?.value.length
? [
{
...createOptionsField(
OrderFilterKeys.channel,
intl.formatMessage(messages.channel),
[],
true,
opts.channel.value
),
active: opts.channel.active
}
]
: [])
];
}

View file

@ -6,6 +6,7 @@ import {
BulkAction,
Dialog,
Filters,
FiltersAsDictWithMultipleValues,
FiltersWithMultipleValues,
Pagination,
SingleAction,
@ -25,11 +26,17 @@ export enum OrderListUrlFiltersEnum {
payment = "payment",
query = "query"
}
export enum OrderListUrlFiltersWithMultipleValuesEnum {
export enum OrderListUrlFiltersWithMultipleValues {
status = "status"
}
export enum OrderListUrlFiltersDictWithMultipleValues {
channel = "channel"
}
export type OrderListUrlFilters = Filters<OrderListUrlFiltersEnum> &
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValuesEnum>;
FiltersWithMultipleValues<OrderListUrlFiltersWithMultipleValues> &
FiltersAsDictWithMultipleValues<OrderListUrlFiltersDictWithMultipleValues>;
export type OrderListUrlDialog = "cancel" | CreateOrderDialog | TabActionDialog;
export enum OrderListUrlSortField {
number = "number",

View file

@ -15,6 +15,7 @@ import { ListViews } from "@saleor/types";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
import createSortHandler from "@saleor/utils/handlers/sortHandler";
import { mapNodeToChoice } from "@saleor/utils/maps";
import { getSortParams } from "@saleor/utils/sort";
import React from "react";
import { useIntl } from "react-intl";
@ -72,6 +73,9 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
const { channel, availableChannels } = useAppChannel();
const noChannel = !channel && typeof channel !== "undefined";
const channelOpts = availableChannels
? mapNodeToChoice(availableChannels)
: null;
const tabs = getFilterTabs();
@ -132,7 +136,7 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
});
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
maybe(() => data.orders.pageInfo),
data?.orders?.pageInfo,
paginationState,
params
);
@ -145,7 +149,7 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
settings={settings}
currentTab={currentTab}
disabled={loading}
filterOpts={getFilterOpts(params)}
filterOpts={getFilterOpts(params, channelOpts)}
orders={maybe(() => data.orders.edges.map(edge => edge.node))}
pageInfo={pageInfo}
sort={getSortParams(params)}
@ -180,10 +184,7 @@ export const OrderList: React.FC<OrderListProps> = ({ params }) => {
/>
{!noChannel && (
<ChannelPickerDialog
channelsChoices={availableChannels.map(channel => ({
label: channel.name,
value: channel.id
}))}
channelsChoices={mapNodeToChoice(availableChannels)}
confirmButtonState="success"
defaultChoice={channel.id}
open={params.action === "create-order"}

View file

@ -2,6 +2,7 @@
exports[`Filtering URL params should not be empty if active filters are present 1`] = `
Object {
"channel": Array [],
"createdFrom": "2019-12-09",
"createdTo": "2019-12-38",
"customer": "email@example.com",

View file

@ -38,6 +38,15 @@ describe("Filtering URL params", () => {
const intl = createIntl(config);
const filters = createFilterStructure(intl, {
channel: {
active: false,
value: [
{
label: "Channel PLN",
value: "channelId"
}
]
},
created: {
active: false,
value: {

View file

@ -1,4 +1,5 @@
import { findInEnum, findValueInEnum, maybe } from "@saleor/misc";
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
import { findInEnum, findValueInEnum } from "@saleor/misc";
import {
OrderFilterKeys,
OrderListFilterOpts
@ -16,48 +17,49 @@ import {
getGteLteVariables,
getMinMaxQueryParam,
getMultipleEnumValueQueryParam,
getMultipleValueQueryParam,
getSingleValueQueryParam
} from "../../../utils/filters";
import {
OrderListUrlFilters,
OrderListUrlFiltersDictWithMultipleValues,
OrderListUrlFiltersEnum,
OrderListUrlFiltersWithMultipleValuesEnum,
OrderListUrlFiltersWithMultipleValues,
OrderListUrlQueryParams
} from "../../urls";
export const ORDER_FILTERS_KEY = "orderFilters";
export function getFilterOpts(
params: OrderListUrlFilters
params: OrderListUrlFilters,
channels: MultiAutocompleteChoiceType[]
): OrderListFilterOpts {
return {
channel: channels
? {
active: params?.channel !== undefined,
value: channels
}
: null,
created: {
active: maybe(
() =>
[params.createdFrom, params.createdTo].some(
field => field !== undefined
),
false
active: [params?.createdFrom, params?.createdTo].some(
field => field !== undefined
),
value: {
max: maybe(() => params.createdTo, ""),
min: maybe(() => params.createdFrom, "")
max: params?.createdTo || "",
min: params?.createdFrom || ""
}
},
customer: {
active: !!maybe(() => params.customer),
value: params.customer
active: !!params?.customer,
value: params?.customer
},
status: {
active: maybe(() => params.status !== undefined, false),
value: maybe(
() =>
dedupeFilter(
params.status.map(status =>
findValueInEnum(status, OrderStatusFilter)
)
),
[]
active: params?.status !== undefined,
value: dedupeFilter(
params?.status?.map(status =>
findValueInEnum(status, OrderStatusFilter)
)
)
}
};
@ -67,15 +69,14 @@ export function getFilterVariables(
params: OrderListUrlFilters
): OrderFilterInput {
return {
channels: (params.channel as unknown) as string[],
created: getGteLteVariables({
gte: params.createdFrom,
lte: params.createdTo
}),
customer: params.customer,
search: params.query,
status: maybe(() =>
params.status.map(status => findInEnum(status, OrderStatusFilter))
)
status: params?.status?.map(status => findInEnum(status, OrderStatusFilter))
};
}
@ -95,10 +96,16 @@ export function getFilterQueryParam(
case OrderFilterKeys.status:
return getMultipleEnumValueQueryParam(
filter,
OrderListUrlFiltersWithMultipleValuesEnum.status,
OrderListUrlFiltersWithMultipleValues.status,
OrderStatusFilter
);
case OrderFilterKeys.channel:
return getMultipleValueQueryParam(
filter,
OrderListUrlFiltersDictWithMultipleValues.channel
);
case OrderFilterKeys.customer:
return getSingleValueQueryParam(filter, OrderListUrlFiltersEnum.customer);
}
@ -115,5 +122,5 @@ export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
OrderListUrlFilters
>({
...OrderListUrlFiltersEnum,
...OrderListUrlFiltersWithMultipleValuesEnum
...OrderListUrlFiltersWithMultipleValues
});

View file

@ -21,6 +21,15 @@ const props: OrderListPageProps = {
...filterPageProps,
...sortPageProps,
filterOpts: {
channel: {
active: false,
value: [
{
label: "Channel PLN",
value: "channelId"
}
]
},
created: {
active: false,
value: {

View file

@ -1326,6 +1326,7 @@ export interface OrderFilterInput {
customer?: string | null;
created?: DateRangeInput | null;
search?: string | null;
channels?: (string | null)[] | null;
}
export interface OrderFulfillInput {