diff --git a/.changeset/silver-items-unite.md b/.changeset/silver-items-unite.md
new file mode 100644
index 00000000000..cf2c90d891f
--- /dev/null
+++ b/.changeset/silver-items-unite.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+List of draft orders now use new filters
diff --git a/.featureFlags/draft_orders_filters.md b/.featureFlags/draft_orders_filters.md
new file mode 100644
index 00000000000..55b7ef0183c
--- /dev/null
+++ b/.featureFlags/draft_orders_filters.md
@@ -0,0 +1,11 @@
+---
+name: draft_orders_filters
+displayName: Draft orders filtering
+enabled: true
+payload: "default"
+visible: true
+---
+
+![new filters](./images/draft-orders-filters.png)
+Experience the new look and enhanced abilities of new fitering mechanism.
+Easily combine any criteria you want, and quickly browse their values.
\ No newline at end of file
diff --git a/.featureFlags/generated.tsx b/.featureFlags/generated.tsx
index bb13a6888d6..d8b3972b051 100644
--- a/.featureFlags/generated.tsx
+++ b/.featureFlags/generated.tsx
@@ -1,15 +1,20 @@
// @ts-nocheck
-import L78751 from "./images/discounts-list.png"
-import H47779 from "./images/improved_refunds.png"
-import D04851 from "./images/page-filters.png"
-import X74083 from "./images/vouchers-filters.png"
+import V92679 from "./images/discounts-list.png"
+import Z34507 from "./images/draft-orders-filters.png"
+import R14220 from "./images/improved_refunds.png"
+import T12026 from "./images/page-filters.png"
+import Q15387 from "./images/vouchers-filters.png"
-const discounts_rules = () => (<>
![Discount rules]({L78751})
+const discounts_rules = () => (<>![Discount rules]({V92679})
Apply the new discounts rules to narrow your promotions audience.
Set up conditions and channels that must be fulfilled to apply defined reward.
>)
-const improved_refunds = () => (<>![Improved refunds]({H47779})
+const draft_orders_filters = () => (<>
+Experience the new look and enhanced abilities of new fitering mechanism.
+Easily combine any criteria you want, and quickly browse their values.
+>)
+const improved_refunds = () => (<>![Improved refunds]({R14220})
Enable the enhanced refund feature to streamline your refund process:
>)
-const pages_filters = () => (<>
+const pages_filters = () => (<>
Experience the new look and enhanced abilities of new fitering mechanism.
Easily combine any criteria you want, and quickly browse their values.
>)
-const vouchers_filters = () => (<>
+const vouchers_filters = () => (<>
Experience the new look and enhanced abilities of new fitering mechanism.
Easily combine any criteria you want, and quickly browse their values.
>)
@@ -37,6 +42,15 @@ export const AVAILABLE_FLAGS = [{
enabled: true,
payload: "default",
}
+},{
+ name: "draft_orders_filters",
+ displayName: "Draft orders filtering",
+ component: draft_orders_filters,
+ visible: true,
+ content: {
+ enabled: true,
+ payload: "default",
+ }
},{
name: "improved_refunds",
displayName: "Improved refunds",
diff --git a/.featureFlags/images/draft-orders-filters.png b/.featureFlags/images/draft-orders-filters.png
new file mode 100644
index 00000000000..05fd7a412e0
Binary files /dev/null and b/.featureFlags/images/draft-orders-filters.png differ
diff --git a/src/components/ConditionalFilter/API/DraftOrderFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/DraftOrderFilterAPIProvider.tsx
new file mode 100644
index 00000000000..70d14c9d653
--- /dev/null
+++ b/src/components/ConditionalFilter/API/DraftOrderFilterAPIProvider.tsx
@@ -0,0 +1,15 @@
+import { FilterAPIProvider } from "@dashboard/components/ConditionalFilter/API/FilterAPIProvider";
+
+export const useDraftOrderFilterAPIProvider = (): FilterAPIProvider => {
+ const fetchRightOptions = async () => {
+ return [];
+ };
+ const fetchLeftOptions = async () => {
+ return [];
+ };
+
+ return {
+ fetchRightOptions,
+ fetchLeftOptions,
+ };
+};
diff --git a/src/components/ConditionalFilter/API/InitialStateResponse.ts b/src/components/ConditionalFilter/API/InitialStateResponse.ts
index 6597c779e89..b9fe30f96bb 100644
--- a/src/components/ConditionalFilter/API/InitialStateResponse.ts
+++ b/src/components/ConditionalFilter/API/InitialStateResponse.ts
@@ -31,6 +31,9 @@ export interface InitialState {
giftCard: ItemOption[];
}
+const isDateField = (name: string) =>
+ ["created", "updatedAt", "startDate", "endDate"].includes(name);
+
export class InitialStateResponse implements InitialState {
constructor(
public category: ItemOption[] = [],
@@ -58,6 +61,10 @@ export class InitialStateResponse implements InitialState {
return this.attribute[token.name].choices.filter(({ value }) => token.value.includes(value));
}
+ if (isDateField(token.name)) {
+ return token.value;
+ }
+
if (token.isAttribute()) {
const attr = this.attribute[token.name];
diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts
index aab7ae06781..8caea170a26 100644
--- a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts
+++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts
@@ -133,7 +133,9 @@ export const toPageFetchingParams = (p: PageFetchingParams, c: UrlToken) => {
return p;
};
-export const getFetchingPrams = (type: "product" | "order" | "discount" | "voucher" | "page") => {
+export const getFetchingPrams = (
+ type: "product" | "order" | "discount" | "voucher" | "page" | "draft-order",
+) => {
switch (type) {
case "product":
return emptyFetchingParams;
diff --git a/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts b/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts
index 6bb03820234..6c97536004a 100644
--- a/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts
+++ b/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts
@@ -21,7 +21,7 @@ import { prepareStructure } from "./utils";
export const useUrlValueProvider = (
locationSearch: string,
- type: "product" | "order" | "discount" | "voucher" | "page",
+ type: "product" | "order" | "discount" | "voucher" | "page" | "draft-order",
initialState?:
| InitialAPIState
| InitialOrderAPIState
diff --git a/src/components/ConditionalFilter/constants.ts b/src/components/ConditionalFilter/constants.ts
index bedf86e11c2..55e68d72ae4 100644
--- a/src/components/ConditionalFilter/constants.ts
+++ b/src/components/ConditionalFilter/constants.ts
@@ -348,12 +348,28 @@ export const STATIC_PAGE_OPTIONS: LeftOperand[] = [
},
];
+export const STATIC_DRAFT_ORDER_OPTIONS: LeftOperand[] = [
+ {
+ value: "customer",
+ label: "Customer",
+ type: "customer",
+ slug: "customer",
+ },
+ {
+ value: "created",
+ label: "Created",
+ type: "created",
+ slug: "created",
+ },
+];
+
export const STATIC_OPTIONS = [
...STATIC_PRODUCT_OPTIONS,
...STATIC_DISCOUNT_OPTIONS,
...STATIC_ORDER_OPTIONS,
...STATIC_VOUCHER_OPTIONS,
...STATIC_PAGE_OPTIONS,
+ ...STATIC_DRAFT_ORDER_OPTIONS,
];
export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
diff --git a/src/components/ConditionalFilter/context/provider.tsx b/src/components/ConditionalFilter/context/provider.tsx
index 28f5b64bda9..f3da7948d55 100644
--- a/src/components/ConditionalFilter/context/provider.tsx
+++ b/src/components/ConditionalFilter/context/provider.tsx
@@ -1,6 +1,7 @@
import React, { FC } from "react";
import { useDiscountFilterAPIProvider } from "../API/DiscountFiltersAPIProvider";
+import { useDraftOrderFilterAPIProvider } from "../API/DraftOrderFilterAPIProvider";
import { useInitialOrderState } from "../API/initialState/orders/useInitialOrderState";
import { useInitialPageState } from "../API/initialState/page/useInitialPageState";
import { useProductInitialAPIState } from "../API/initialState/useInitialAPIState";
@@ -11,6 +12,7 @@ import { useProductFilterAPIProvider } from "../API/ProductFilterAPIProvider";
import { useVoucherAPIProvider } from "../API/VoucherFilterAPIProvider";
import {
STATIC_DISCOUNT_OPTIONS,
+ STATIC_DRAFT_ORDER_OPTIONS,
STATIC_ORDER_OPTIONS,
STATIC_PAGE_OPTIONS,
STATIC_PRODUCT_OPTIONS,
@@ -149,3 +151,28 @@ export const ConditionalPageFilterProvider: FC<{
);
};
+
+export const ConditionalDraftOrderFilterProvider: FC<{
+ locationSearch: string;
+}> = ({ children, locationSearch }) => {
+ const apiProvider = useDraftOrderFilterAPIProvider();
+
+ const valueProvider = useUrlValueProvider(locationSearch, "draft-order");
+ const leftOperandsProvider = useFilterLeftOperandsProvider(STATIC_DRAFT_ORDER_OPTIONS);
+ const containerState = useContainerState(valueProvider);
+ const filterWindow = useFilterWindow();
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/components/ConditionalFilter/queryVariables.test.ts b/src/components/ConditionalFilter/queryVariables.test.ts
index 0aac3632dcb..07a1a44dd3f 100644
--- a/src/components/ConditionalFilter/queryVariables.test.ts
+++ b/src/components/ConditionalFilter/queryVariables.test.ts
@@ -3,6 +3,7 @@ import { ConditionOptions } from "./FilterElement/ConditionOptions";
import { ConditionSelected } from "./FilterElement/ConditionSelected";
import { ExpressionValue } from "./FilterElement/FilterElement";
import {
+ creatDraftOrderQueryVariables,
createPageQueryVariables,
createProductQueryVariables,
creatVoucherQueryVariables,
@@ -243,6 +244,63 @@ describe("ConditionalFilter / queryVariables / createPageQueryVariables", () =>
});
});
+describe("ConditionalFilter / queryVariables / creatDraftOrderQueryVariables", () => {
+ it("should return empty variables for empty filters", () => {
+ // Arrange
+ const filters: FilterContainer = [];
+ const expectedOutput = {};
+ // Act
+ const result = creatDraftOrderQueryVariables(filters);
+
+ // Assert
+ expect(result).toEqual(expectedOutput);
+ });
+
+ it("should create variables with selected filters", () => {
+ // Arrange
+ const filters: FilterContainer = [
+ new FilterElement(
+ new ExpressionValue("customer", "Customer", "customer"),
+ new Condition(
+ ConditionOptions.fromStaticElementName("customer"),
+ new ConditionSelected(
+ { label: "customer1", slug: "customer1", value: "value1" },
+ { type: "text", label: "is", value: "input-1" },
+ [],
+ false,
+ ),
+ false,
+ ),
+ false,
+ ),
+ "AND",
+ new FilterElement(
+ new ExpressionValue("created", "Created", "created"),
+ new Condition(
+ ConditionOptions.fromStaticElementName("customer"),
+ new ConditionSelected(
+ ["2025-02-01", "2025-02-05"],
+ { type: "date.range", label: "between", value: "input-3" },
+ [],
+ false,
+ ),
+ false,
+ ),
+ false,
+ ),
+ ];
+ const expectedOutput = {
+ created: { gte: "2025-02-01", lte: "2025-02-05" },
+ customer: "value1",
+ };
+ // Act
+ const result = creatDraftOrderQueryVariables(filters);
+
+ // Assert
+ expect(result).toEqual(expectedOutput);
+ });
+});
+
describe("ConditionalFilter / queryVariables / mapStaticQueryPartToLegacyVariables", () => {
it("should return queryPart if it is not an object", () => {
// Arrange
diff --git a/src/components/ConditionalFilter/queryVariables.ts b/src/components/ConditionalFilter/queryVariables.ts
index 82b2a24bf05..1ce93f7299d 100644
--- a/src/components/ConditionalFilter/queryVariables.ts
+++ b/src/components/ConditionalFilter/queryVariables.ts
@@ -5,6 +5,7 @@ import {
DateTimeRangeInput,
DecimalFilterInput,
GlobalIdFilterInput,
+ OrderDraftFilterInput,
PageFilterInput,
ProductWhereInput,
PromotionWhereInput,
@@ -93,6 +94,7 @@ const getRangeQueryPartByType = (value: [string, string], type: string) => {
return { valuesRange: { lte: parseFloat(lte), gte: parseFloat(gte) } };
}
};
+
const getQueryPartByType = (value: string, type: string, what: "lte" | "gte") => {
switch (type) {
case "datetime":
@@ -103,6 +105,7 @@ const getQueryPartByType = (value: string, type: string, what: "lte" | "gte") =>
return { valuesRange: { [what]: parseFloat(value) } };
}
};
+
const createAttributeQueryPart = (
attributeSlug: string,
selected: ConditionSelected,
@@ -284,3 +287,15 @@ export const createPageQueryVariables = (value: FilterContainer): PageFilterInpu
return p;
}, {} as PageFilterInput);
};
+
+export const creatDraftOrderQueryVariables = (value: FilterContainer): OrderDraftFilterInput => {
+ return value.reduce((p, c) => {
+ if (typeof c === "string" || Array.isArray(c)) return p;
+
+ p[c.value.value as keyof OrderDraftFilterInput] = mapStaticQueryPartToLegacyVariables(
+ createStaticQueryPart(c.condition.selected),
+ );
+
+ return p;
+ }, {} as OrderDraftFilterInput);
+};
diff --git a/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx b/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx
index 535fca25951..eefb29dca64 100644
--- a/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx
+++ b/src/orders/components/OrderDraftListPage/OrderDraftListPage.tsx
@@ -2,6 +2,7 @@
import { ListFilters } from "@dashboard/components/AppLayout/ListFilters";
import { BulkDeleteButton } from "@dashboard/components/BulkDeleteButton";
import { DashboardCard } from "@dashboard/components/Card";
+import { useFlag } from "@dashboard/featureFlags";
import { OrderDraftListQuery, RefreshLimitsQuery } from "@dashboard/graphql";
import { OrderDraftListUrlSortField } from "@dashboard/orders/urls";
import { FilterPagePropsWithPresets, PageListProps, RelayToFlat, SortPage } from "@dashboard/types";
@@ -54,6 +55,7 @@ const OrderDraftListPage: React.FC = ({
const [isFilterPresetOpen, setFilterPresetOpen] = useState(false);
const filterStructure = createFilterStructure(intl, filterOpts);
const limitsReached = isLimitReached(limits, "orders");
+ const { enabled: isDraftOrdersFilteringEnabled } = useFlag("draft_orders_filters");
return (
<>
@@ -83,30 +85,54 @@ const OrderDraftListPage: React.FC = ({
alignItems="stretch"
justifyContent="space-between"
>
-
- {selectedOrderDraftIds.length > 0 && (
-
- {intl.formatMessage({
- id: "+b/qJ9",
- defaultMessage: "Delete draft orders",
- })}
-
- )}
-
- }
- />
+ {isDraftOrdersFilteringEnabled ? (
+
+ {selectedOrderDraftIds.length > 0 && (
+
+ {intl.formatMessage({
+ id: "+b/qJ9",
+ defaultMessage: "Delete draft orders",
+ })}
+
+ )}
+
+ }
+ />
+ ) : (
+
+ {selectedOrderDraftIds.length > 0 && (
+
+ {intl.formatMessage({
+ id: "+b/qJ9",
+ defaultMessage: "Delete draft orders",
+ })}
+
+ )}
+
+ }
+ />
+ )}
> = ({ location }) => {
false,
);
- return ;
+ return (
+
+
+
+ );
};
const OrderDetails: React.FC> = ({ location, match }) => {
const qs = parseQs(location.search.substr(1)) as any;
diff --git a/src/orders/views/OrderDraftList/OrderDraftList.tsx b/src/orders/views/OrderDraftList/OrderDraftList.tsx
index a5df5590dcd..3c715aa153d 100644
--- a/src/orders/views/OrderDraftList/OrderDraftList.tsx
+++ b/src/orders/views/OrderDraftList/OrderDraftList.tsx
@@ -3,9 +3,12 @@ import { useUser } from "@dashboard/auth";
import ChannelPickerDialog from "@dashboard/channels/components/ChannelPickerDialog";
import ActionDialog from "@dashboard/components/ActionDialog";
import useAppChannel from "@dashboard/components/AppLayout/AppChannelContext";
+import { useConditionalFilterContext } from "@dashboard/components/ConditionalFilter";
+import { creatDraftOrderQueryVariables } from "@dashboard/components/ConditionalFilter/queryVariables";
import DeleteFilterTabDialog from "@dashboard/components/DeleteFilterTabDialog";
import SaveFilterTabDialog from "@dashboard/components/SaveFilterTabDialog";
import { useShopLimitsQuery } from "@dashboard/components/Shop/queries";
+import { useFlag } from "@dashboard/featureFlags";
import { useOrderDraftCreateMutation, useOrderDraftListQuery } from "@dashboard/graphql";
import { useFilterPresets } from "@dashboard/hooks/useFilterPresets";
import useListSettings from "@dashboard/hooks/useListSettings";
@@ -48,6 +51,9 @@ export const OrderDraftList: React.FC = ({ params }) => {
const notify = useNotifier();
const intl = useIntl();
const { updateListSettings, settings } = useListSettings(ListViews.DRAFT_LIST);
+ const { enabled: isDraftOrdersFilteringEnabled } = useFlag("draft_orders_filters");
+ const { valueProvider } = useConditionalFilterContext();
+ const filter = creatDraftOrderQueryVariables(valueProvider.value);
usePaginationReset(orderDraftListUrl, params, settings.rowNumber);
@@ -119,9 +125,22 @@ export const OrderDraftList: React.FC = ({ params }) => {
}),
[paginationState, params],
);
+
+ const newFiltersQueryVariables = React.useMemo(
+ () => ({
+ ...paginationState,
+ filter: {
+ ...filter,
+ search: params.query,
+ },
+ sort: getSortQueryVariables(params),
+ }),
+ [params, settings.rowNumber, valueProvider.value],
+ );
+
const { data, refetch } = useOrderDraftListQuery({
displayLoader: true,
- variables: queryVariables,
+ variables: isDraftOrdersFilteringEnabled ? newFiltersQueryVariables : queryVariables,
});
const orderDrafts = mapEdgesToItems(data?.draftOrders);
const paginationValues = usePaginator({