diff --git a/.changeset/late-parents-cross.md b/.changeset/late-parents-cross.md new file mode 100644 index 00000000000..05caa0bbf80 --- /dev/null +++ b/.changeset/late-parents-cross.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +Collection list filters have been ported to expression filtering. This means you can now use new filters in the Collection list. diff --git a/.featureFlags/collection_filters.md b/.featureFlags/collection_filters.md new file mode 100644 index 00000000000..039a48e704b --- /dev/null +++ b/.featureFlags/collection_filters.md @@ -0,0 +1,11 @@ +--- +name: collection_filters +displayName: Collection filtering +enabled: true +payload: "default" +visible: true +--- + +![new filters](./images/collection-filters.jpg) +Experience the new look and enhanced abilities of new filtering 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 979585bde3b..ffa25c70ac1 100644 --- a/.featureFlags/generated.tsx +++ b/.featureFlags/generated.tsx @@ -1,30 +1,35 @@ // @ts-nocheck -import J53093 from "./images/customers-filters.png" -import Q09991 from "./images/discounts-list.png" -import Z15989 from "./images/draft-orders-filters.png" -import C33827 from "./images/gift-cards-filters.png" -import H90846 from "./images/improved_refunds.png" -import A12919 from "./images/page-filters.png" -import X74531 from "./images/vouchers-filters.png" +import W24585 from "./images/collection-filters.jpg" +import L16463 from "./images/customers-filters.png" +import L94878 from "./images/discounts-list.png" +import E09437 from "./images/draft-orders-filters.png" +import E78766 from "./images/gift-cards-filters.png" +import X68306 from "./images/improved_refunds.png" +import E85468 from "./images/page-filters.png" +import B37301 from "./images/vouchers-filters.png" -const customers_filters = () => (<>

new filters +const collection_filters = () => (<>

new filters +Experience the new look and enhanced abilities of new filtering mechanism. +Easily combine any criteria you want, and quickly browse their values.

+) +const customers_filters = () => (<>

new filters Experience the new look and enhanced abilities of new fitering mechanism. Easily combine any criteria you want, and quickly browse their values.

) -const discounts_rules = () => (<>

Discount rules

+const discounts_rules = () => (<>

Discount rules

Apply the new discounts rules to narrow your promotions audience. Set up conditions and channels that must be fulfilled to apply defined reward.

) -const draft_orders_filters = () => (<>

new filters +const draft_orders_filters = () => (<>

new filters Experience the new look and enhanced abilities of new fitering mechanism. Easily combine any criteria you want, and quickly browse their values.

) -const gift_cards_filters = () => (<>

new filters +const gift_cards_filters = () => (<>

new 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

+const improved_refunds = () => (<>

Improved refunds

Enable the enhanced refund feature to streamline your refund process:

) -const pages_filters = () => (<>

new filters +const pages_filters = () => (<>

new 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 = () => (<>

new filters +const vouchers_filters = () => (<>

new filters Experience the new look and enhanced abilities of new fitering mechanism. Easily combine any criteria you want, and quickly browse their values.

) export const AVAILABLE_FLAGS = [{ + name: "collection_filters", + displayName: "Collection filtering", + component: collection_filters, + visible: true, + content: { + enabled: true, + payload: "default", + } +},{ name: "customers_filters", displayName: "Customers filtering", component: customers_filters, diff --git a/.featureFlags/images/collection-filters.jpg b/.featureFlags/images/collection-filters.jpg new file mode 100644 index 00000000000..cca098d5707 Binary files /dev/null and b/.featureFlags/images/collection-filters.jpg differ diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index 6cae3ea2ec4..a32f6309c4e 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -4938,6 +4938,9 @@ "context": "tax classes card header", "string": "General information" }, + "ThUvIL": { + "string": "Hidden" + }, "TjGYna": { "context": "product inventory, checkbox", "string": "Track Inventory" @@ -9262,6 +9265,9 @@ "w7jT4W": { "string": "No channels selected" }, + "w7tf2z": { + "string": "Published" + }, "w9xgN9": { "context": "see error log label in notification", "string": "See error log" diff --git a/src/collections/components/CollectionListPage/CollectionListPage.tsx b/src/collections/components/CollectionListPage/CollectionListPage.tsx index 887ffb8dbf2..0dd2290735e 100644 --- a/src/collections/components/CollectionListPage/CollectionListPage.tsx +++ b/src/collections/components/CollectionListPage/CollectionListPage.tsx @@ -12,6 +12,7 @@ import { DashboardCard } from "@dashboard/components/Card"; import { getByName } from "@dashboard/components/Filter/utils"; import { FilterPresetsSelect } from "@dashboard/components/FilterPresetsSelect"; import { ListPageLayout } from "@dashboard/components/Layouts"; +import { useFlag } from "@dashboard/featureFlags"; import { getPrevLocationState } from "@dashboard/hooks/useBackLinkWithState"; import useNavigator from "@dashboard/hooks/useNavigator"; import { sectionNames } from "@dashboard/intl"; @@ -65,6 +66,7 @@ const CollectionListPage: React.FC = ({ const navigate = useNavigator(); const filterStructure = createFilterStructure(intl, filterOpts); const [isFilterPresetOpen, setFilterPresetOpen] = useState(false); + const { enabled: isNewCollectionListEnabled } = useFlag("collection_filters"); const filterDependency = filterStructure.find(getByName("channel")); return ( @@ -116,27 +118,47 @@ const CollectionListPage: React.FC = ({ - - {selectedCollectionIds.length > 0 && ( - - - - )} - - } - /> + {isNewCollectionListEnabled ? ( + + {selectedCollectionIds.length > 0 && ( + + + + )} + + } + /> + ) : ( + + {selectedCollectionIds.length > 0 && ( + + + + )} + + } + onFilterChange={onFilterChange} + onFilterAttributeFocus={onFilterAttributeFocus} + filterStructure={filterStructure} + /> + )} > = ({ location }) => { const qs = parseQs(location.search.substr(1)) as any; const params: CollectionListUrlQueryParams = asSortParams(qs, CollectionListUrlSortField); - return ; + return ( + + + + ); }; interface CollectionDetailsRouteProps { diff --git a/src/collections/views/CollectionList/CollectionList.tsx b/src/collections/views/CollectionList/CollectionList.tsx index 8298131cf9a..950956f631f 100644 --- a/src/collections/views/CollectionList/CollectionList.tsx +++ b/src/collections/views/CollectionList/CollectionList.tsx @@ -1,8 +1,11 @@ // @ts-strict-ignore import ActionDialog from "@dashboard/components/ActionDialog"; import useAppChannel from "@dashboard/components/AppLayout/AppChannelContext"; +import { useConditionalFilterContext } from "@dashboard/components/ConditionalFilter"; +import { createCollectionsQueryVariables } from "@dashboard/components/ConditionalFilter/queryVariables"; import DeleteFilterTabDialog from "@dashboard/components/DeleteFilterTabDialog"; import SaveFilterTabDialog from "@dashboard/components/SaveFilterTabDialog"; +import { useFlag } from "@dashboard/featureFlags"; import { useCollectionBulkDeleteMutation, useCollectionListQuery } from "@dashboard/graphql"; import { useFilterPresets } from "@dashboard/hooks/useFilterPresets"; import useListSettings from "@dashboard/hooks/useListSettings"; @@ -44,10 +47,11 @@ export const CollectionList: React.FC = ({ params }) => { const intl = useIntl(); const notify = useNotifier(); const { updateListSettings, settings } = useListSettings(ListViews.COLLECTION_LIST); + const { enabled: isNewCollectionFilterEnabled } = useFlag("collection_filters"); + const { valueProvider } = useConditionalFilterContext(); usePaginationReset(collectionListUrl, params, settings.rowNumber); - const { channel } = useAppChannel(false); const { clearRowSelection, selectedRowIds, @@ -62,11 +66,10 @@ export const CollectionList: React.FC = ({ params }) => { params, keepActiveTab: true, }); - const { availableChannels } = useAppChannel(false); + const { availableChannels, channel } = useAppChannel(false); const channelOpts = availableChannels ? mapNodeToChoice(availableChannels, channel => channel.slug) : null; - const selectedChannel = availableChannels.find(channel => channel.slug === params.channel); const { selectedPreset, presets, @@ -84,14 +87,28 @@ export const CollectionList: React.FC = ({ params }) => { storageUtils, }); const paginationState = createPaginationState(settings.rowNumber, params); - const queryVariables = React.useMemo( - () => ({ + const selectedChannel_legacy = availableChannels.find(channel => channel.slug === params.channel); + const queryVariables = React.useMemo(() => { + if (!isNewCollectionFilterEnabled) { + return { + ...paginationState, + filter: getFilterVariables(params), + sort: getSortQueryVariables(params), + channel: selectedChannel_legacy?.slug, + }; + } + + const { channel, ...variables } = createCollectionsQueryVariables(valueProvider.value); + + return { ...paginationState, - filter: getFilterVariables(params), + filter: variables, sort: getSortQueryVariables(params), - channel: selectedChannel?.slug, - }), - [params, settings.rowNumber], + channel, // Saleor docs say 'channel' in filter is deprecated and should be moved to root + }; + }, [params, settings.rowNumber, valueProvider.value, isNewCollectionFilterEnabled]); + const selectedChannel = availableChannels.find( + channel => channel.slug === queryVariables.channel, ); const { data, refetch } = useCollectionListQuery({ displayLoader: true, @@ -111,10 +128,9 @@ export const CollectionList: React.FC = ({ params }) => { } }, }); - const filterOpts = getFilterOpts(params, channelOpts); useEffect(() => { - if (!canBeSorted(params.sort, !!selectedChannel)) { + if (!canBeSorted(params.sort, !!queryVariables.channel)) { navigate( collectionListUrl({ ...params, @@ -160,6 +176,11 @@ export const CollectionList: React.FC = ({ params }) => { clearRowSelection(); }, [selectedRowIds]); + const filterOpts = getFilterOpts(params, channelOpts); + const selectedChannelId = isNewCollectionFilterEnabled + ? selectedChannel?.id + : selectedChannel_legacy?.id; + return ( = ({ params }) => { onSort={handleSort} onUpdateListSettings={updateListSettings} sort={getSortParams(params)} - selectedChannelId={selectedChannel?.id} + selectedChannelId={selectedChannelId} filterOpts={filterOpts} onFilterChange={changeFilters} selectedCollectionIds={selectedRowIds} diff --git a/src/components/ConditionalFilter/API/Handler.ts b/src/components/ConditionalFilter/API/Handler.ts index 4484dcce716..f4cd517120b 100644 --- a/src/components/ConditionalFilter/API/Handler.ts +++ b/src/components/ConditionalFilter/API/Handler.ts @@ -39,7 +39,7 @@ import { IntlShape } from "react-intl"; import { ItemOption } from "../FilterElement/ConditionValue"; import { LeftOperand } from "../LeftOperandsProvider"; -import { getLocalizedLabel } from "./initialState/orders/intl"; +import { getLocalizedLabel } from "./intl"; export interface Handler { fetch: () => Promise; diff --git a/src/components/ConditionalFilter/API/index.ts b/src/components/ConditionalFilter/API/index.ts deleted file mode 100644 index ff44d0671a5..00000000000 --- a/src/components/ConditionalFilter/API/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./initialState"; diff --git a/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.test.ts b/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.test.ts new file mode 100644 index 00000000000..a960a0bd633 --- /dev/null +++ b/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.test.ts @@ -0,0 +1,72 @@ +import { CollectionPublished } from "@dashboard/graphql"; + +import { UrlEntry, UrlToken } from "../../../ValueProvider/UrlToken"; +import { InitialCollectionStateResponse } from "./InitialCollectionState"; + +describe("ConditionalFilter / API / Page / InitialCollectionStateResponse", () => { + it("should filter by channel", () => { + // Arrange + const initialCollectionState = InitialCollectionStateResponse.empty(); + + initialCollectionState.channel = [ + { + label: "Channel 1", + value: "chan-1", + slug: "chan-1", + }, + { + label: "Channel 2", + value: "chan-2", + slug: "chan-2", + }, + ]; + + const token = UrlToken.fromUrlEntry(new UrlEntry("s0.channel", "chan-1")); + const expectedOutput = [ + { + label: "Channel 1", + value: "chan-1", + slug: "chan-1", + }, + ]; + + // Act + const result = initialCollectionState.filterByUrlToken(token); + + // Assert + expect(result).toEqual(expectedOutput); + }); + + it("should filter by published", () => { + // Arrange + const initialCollectionState = InitialCollectionStateResponse.empty(); + + initialCollectionState.published = [ + { + label: CollectionPublished.PUBLISHED, + value: CollectionPublished.PUBLISHED, + slug: CollectionPublished.PUBLISHED, + }, + { + label: CollectionPublished.HIDDEN, + value: CollectionPublished.HIDDEN, + slug: CollectionPublished.HIDDEN, + }, + ]; + + const token = UrlToken.fromUrlEntry(new UrlEntry("s0.published", "HIDDEN")); + const expectedOutput = [ + { + label: CollectionPublished.HIDDEN, + value: CollectionPublished.HIDDEN, + slug: CollectionPublished.HIDDEN, + }, + ]; + + // Act + const result = initialCollectionState.filterByUrlToken(token); + + // Assert + expect(result).toEqual(expectedOutput); + }); +}); diff --git a/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.ts b/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.ts new file mode 100644 index 00000000000..bd063dd54aa --- /dev/null +++ b/src/components/ConditionalFilter/API/initialState/collections/InitialCollectionState.ts @@ -0,0 +1,49 @@ +import { ItemOption } from "@dashboard/components/ConditionalFilter/FilterElement/ConditionValue"; +import { UrlToken } from "@dashboard/components/ConditionalFilter/ValueProvider/UrlToken"; + +export interface InitialCollectionState { + channel: ItemOption[]; + published: ItemOption[]; + metadata: ItemOption[]; +} + +export class InitialCollectionStateResponse implements InitialCollectionState { + constructor( + public channel: ItemOption[] = [], + public published: ItemOption[] = [], + public metadata: ItemOption[] = [], + ) {} + + static empty() { + return new InitialCollectionStateResponse(); + } + + public filterByUrlToken(token: UrlToken) { + const entry = this.getEntryByName(token.name); + + if (!token.isLoadable()) { + return [token.value] as string[]; + } + + return entry.filter(({ slug }) => { + if (Array.isArray(token.value)) { + return token.value.includes(slug); + } + + return slug === token.value; + }); + } + + private getEntryByName(name: string): ItemOption[] { + switch (name) { + case "channel": + return this.channel; + case "published": + return this.published; + case "metadata": + return this.metadata; + default: + return []; + } + } +} diff --git a/src/components/ConditionalFilter/API/initialState/collections/useInitialCollectionsState.ts b/src/components/ConditionalFilter/API/initialState/collections/useInitialCollectionsState.ts new file mode 100644 index 00000000000..44ef37b8f96 --- /dev/null +++ b/src/components/ConditionalFilter/API/initialState/collections/useInitialCollectionsState.ts @@ -0,0 +1,66 @@ +import { useApolloClient } from "@apollo/client"; +import { CollectionFetchingParams } from "@dashboard/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams"; +import { + _GetChannelOperandsDocument, + _GetChannelOperandsQuery, + _GetChannelOperandsQueryVariables, + CollectionPublished, +} from "@dashboard/graphql"; +import { useState } from "react"; +import { useIntl } from "react-intl"; + +import { EnumValuesHandler } from "../../Handler"; +import { createInitialCollectionState } from "../helpers"; +import { InitialCollectionAPIResponse } from "../types"; +import { InitialCollectionStateResponse } from "./InitialCollectionState"; + +export interface InitialCollectionAPIState { + data: InitialCollectionStateResponse; + loading: boolean; + fetchQueries: (params: CollectionFetchingParams) => Promise; +} + +export const useInitialCollectionState = (): InitialCollectionAPIState => { + const client = useApolloClient(); + const intl = useIntl(); + + const [data, setData] = useState( + InitialCollectionStateResponse.empty(), + ); + const [loading, setLoading] = useState(true); + + const queriesToRun: Array> = []; + + const fetchQueries = async ({ channel }: CollectionFetchingParams) => { + if (channel?.length > 0) { + queriesToRun.push( + client.query<_GetChannelOperandsQuery, _GetChannelOperandsQueryVariables>({ + query: _GetChannelOperandsDocument, + }), + ); + } + + const publishedInit = new EnumValuesHandler(CollectionPublished, "published", intl); + + const data = await Promise.all(queriesToRun); + const initialState = { + ...createInitialCollectionState(data, channel), + published: await publishedInit.fetch(), + }; + + setData( + new InitialCollectionStateResponse( + initialState.channel, + initialState.published, + initialState.metadata, + ), + ); + setLoading(false); + }; + + return { + data, + loading, + fetchQueries, + }; +}; diff --git a/src/components/ConditionalFilter/API/initialState/helpers.test.ts b/src/components/ConditionalFilter/API/initialState/helpers.test.ts index 59b5498d8ad..0499641e48c 100644 --- a/src/components/ConditionalFilter/API/initialState/helpers.test.ts +++ b/src/components/ConditionalFilter/API/initialState/helpers.test.ts @@ -7,7 +7,7 @@ import { _SearchProductTypesOperandsQuery, } from "@dashboard/graphql"; -import { createInitialStateFromData } from "./helpers"; +import { createInitialProductStateFromData } from "./helpers"; describe("ConditionalFilter / API / createInitialStateFromData", () => { it("should create initial state from queries", () => { @@ -99,7 +99,7 @@ describe("ConditionalFilter / API / createInitialStateFromData", () => { const data = [channelQuery, collectionQuery, categoryQuery, productTypeQuery, attributeQuery]; const channel = ["channel-1"]; // Act - const result = createInitialStateFromData(data, channel); + const result = createInitialProductStateFromData(data, channel); // Assert expect(result).toMatchSnapshot(); diff --git a/src/components/ConditionalFilter/API/initialState/helpers.ts b/src/components/ConditionalFilter/API/initialState/helpers.ts index 7295921a66c..450ff9ca57c 100644 --- a/src/components/ConditionalFilter/API/initialState/helpers.ts +++ b/src/components/ConditionalFilter/API/initialState/helpers.ts @@ -1,7 +1,4 @@ import { ApolloQueryResult } from "@apollo/client"; -import { InitialGiftCardsState } from "@dashboard/components/ConditionalFilter/API/initialState/giftCards/InitialGiftCardsState"; -import { InitialPageState } from "@dashboard/components/ConditionalFilter/API/initialState/page/InitialPageState"; -import { InitialVouchersState } from "@dashboard/components/ConditionalFilter/API/initialState/vouchers/InitialVouchersState"; import { _GetChannelOperandsQuery, _GetLegacyChannelOperandsQuery, @@ -17,33 +14,38 @@ import { import { createBooleanOptions } from "../../constants"; import { createCustomerOptionsFromAPI, createOptionsFromAPI } from "../Handler"; -import { InitialState } from "../InitialStateResponse"; +import { InitialCollectionState } from "./collections/InitialCollectionState"; +import { InitialGiftCardsState } from "./giftCards/InitialGiftCardsState"; import { InitialOrderState } from "./orders/InitialOrderState"; +import { InitialPageState } from "./page/InitialPageState"; +import { InitialProductState } from "./product/InitialProductStateResponse"; import { - InitialAPIResponse, + InitialCollectionAPIResponse, InitialGiftCardsAPIResponse, InitialOrderAPIResponse, InitialPageAPIResponse, + InitialProductAPIResponse, InitialVoucherAPIResponse, } from "./types"; +import { InitialVouchersState } from "./vouchers/InitialVouchersState"; const isChannelQuery = ( - query: InitialAPIResponse, + query: InitialProductAPIResponse, ): query is ApolloQueryResult<_GetChannelOperandsQuery> => "channels" in query.data; const isChannelsQuery = ( query: InitialOrderAPIResponse, ): query is ApolloQueryResult<_GetLegacyChannelOperandsQuery> => "channels" in query.data; const isCollectionQuery = ( - query: InitialAPIResponse, + query: InitialProductAPIResponse, ): query is ApolloQueryResult<_SearchCollectionsOperandsQuery> => "collections" in query.data; const isCategoryQuery = ( - query: InitialAPIResponse, + query: InitialProductAPIResponse, ): query is ApolloQueryResult<_SearchCategoriesOperandsQuery> => "categories" in query.data; const isProductTypeQuery = ( - query: InitialAPIResponse, + query: InitialProductAPIResponse, ): query is ApolloQueryResult<_SearchProductTypesOperandsQuery> => "productTypes" in query.data; const isAttributeQuery = ( - query: InitialAPIResponse, + query: InitialProductAPIResponse, ): query is ApolloQueryResult<_SearchAttributeOperandsQuery> => "attributes" in query.data; const isPageTypesQuery = ( query: InitialPageAPIResponse, @@ -58,8 +60,11 @@ const isCurrencyQuery = ( query: InitialGiftCardsAPIResponse, ): query is ApolloQueryResult => "shop" in query.data; -export const createInitialStateFromData = (data: InitialAPIResponse[], channel: string[]) => - data.reduce( +export const createInitialProductStateFromData = ( + data: InitialProductAPIResponse[], + channel: string[], +) => + data.reduce( (acc, query) => { if (isChannelQuery(query)) { return { @@ -244,3 +249,27 @@ export const createInitialGiftCardsState = ( } as InitialGiftCardsState, ); }; + +export const createInitialCollectionState = ( + data: InitialCollectionAPIResponse[], + channel: string[], +) => + data.reduce( + (acc, query) => { + if (isChannelQuery(query)) { + return { + ...acc, + channel: (query.data?.channels ?? []) + .filter(({ slug }) => channel.includes(slug)) + .map(({ id, name, slug }) => ({ label: name, value: id, slug })), + }; + } + + return acc; + }, + { + channel: [], + published: [], + metadata: [], + }, + ); diff --git a/src/components/ConditionalFilter/API/initialState/index.ts b/src/components/ConditionalFilter/API/initialState/index.ts deleted file mode 100644 index 174987ad9f9..00000000000 --- a/src/components/ConditionalFilter/API/initialState/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./useInitialAPIState"; diff --git a/src/components/ConditionalFilter/API/InitalStateResponse.test.ts b/src/components/ConditionalFilter/API/initialState/product/InitalProductStateResponse.test.ts similarity index 83% rename from src/components/ConditionalFilter/API/InitalStateResponse.test.ts rename to src/components/ConditionalFilter/API/initialState/product/InitalProductStateResponse.test.ts index be2439ff2a3..018b762ffbe 100644 --- a/src/components/ConditionalFilter/API/InitalStateResponse.test.ts +++ b/src/components/ConditionalFilter/API/initialState/product/InitalProductStateResponse.test.ts @@ -1,10 +1,10 @@ -import { UrlEntry, UrlToken } from "../ValueProvider/UrlToken"; -import { InitialStateResponse } from "./InitialStateResponse"; +import { UrlEntry, UrlToken } from "../../../ValueProvider/UrlToken"; +import { InitialProductStateResponse } from "./InitialProductStateResponse"; -describe("ConditionalFilter / API / InitialStateResponse", () => { +describe("ConditionalFilter / API / InitialProductStateResponse", () => { it("should filter by dynamic attribute token", () => { // Arrange - const initialState = InitialStateResponse.empty(); + const initialState = InitialProductStateResponse.empty(); initialState.attribute = { "attribute-1": { @@ -29,7 +29,7 @@ describe("ConditionalFilter / API / InitialStateResponse", () => { }); it("should filter by static token type", () => { // Arrange - const initialState = InitialStateResponse.empty(); + const initialState = InitialProductStateResponse.empty(); initialState.category = [{ label: "Category 1", value: "1", slug: "category-1" }]; @@ -43,7 +43,7 @@ describe("ConditionalFilter / API / InitialStateResponse", () => { }); it("should filter by boolean attribute token", () => { // Arrange - const initialState = InitialStateResponse.empty(); + const initialState = InitialProductStateResponse.empty(); initialState.attribute = { "attribute-2": { @@ -73,7 +73,7 @@ describe("ConditionalFilter / API / InitialStateResponse", () => { }); it("should filter by static attribute token", () => { // Arrange - const initialState = InitialStateResponse.empty(); + const initialState = InitialProductStateResponse.empty(); initialState.attribute = { size: { diff --git a/src/components/ConditionalFilter/API/InitialStateResponse.ts b/src/components/ConditionalFilter/API/initialState/product/InitialProductStateResponse.ts similarity index 86% rename from src/components/ConditionalFilter/API/InitialStateResponse.ts rename to src/components/ConditionalFilter/API/initialState/product/InitialProductStateResponse.ts index b9fe30f96bb..758c7845430 100644 --- a/src/components/ConditionalFilter/API/InitialStateResponse.ts +++ b/src/components/ConditionalFilter/API/initialState/product/InitialProductStateResponse.ts @@ -1,9 +1,9 @@ import { AttributeInputTypeEnum } from "@dashboard/graphql"; -import { createBooleanOption } from "../constants"; -import { AttributeInputType } from "../FilterElement/ConditionOptions"; -import { ItemOption } from "../FilterElement/ConditionValue"; -import { UrlToken } from "../ValueProvider/UrlToken"; +import { createBooleanOption } from "../../../constants"; +import { AttributeInputType } from "../../../FilterElement/ConditionOptions"; +import { ItemOption } from "../../../FilterElement/ConditionValue"; +import { UrlToken } from "../../../ValueProvider/UrlToken"; export interface AttributeDTO { choices: Array<{ @@ -18,7 +18,7 @@ export interface AttributeDTO { value: string; } -export interface InitialState { +export interface InitialProductState { category: ItemOption[]; attribute: Record; channel: ItemOption[]; @@ -34,7 +34,7 @@ export interface InitialState { const isDateField = (name: string) => ["created", "updatedAt", "startDate", "endDate"].includes(name); -export class InitialStateResponse implements InitialState { +export class InitialProductStateResponse implements InitialProductState { constructor( public category: ItemOption[] = [], public attribute: Record = {}, @@ -53,7 +53,7 @@ export class InitialStateResponse implements InitialState { } public static empty() { - return new InitialStateResponse(); + return new InitialProductStateResponse(); } public filterByUrlToken(token: UrlToken) { diff --git a/src/components/ConditionalFilter/API/initialState/useInitialAPIState.tsx b/src/components/ConditionalFilter/API/initialState/product/useProductInitialAPIState.tsx similarity index 81% rename from src/components/ConditionalFilter/API/initialState/useInitialAPIState.tsx rename to src/components/ConditionalFilter/API/initialState/product/useProductInitialAPIState.tsx index 44d3c398d34..cc4b4753cb8 100644 --- a/src/components/ConditionalFilter/API/initialState/useInitialAPIState.tsx +++ b/src/components/ConditionalFilter/API/initialState/product/useProductInitialAPIState.tsx @@ -18,22 +18,24 @@ import { } from "@dashboard/graphql"; import { useState } from "react"; -import { FetchingParams } from "../../ValueProvider/TokenArray/fetchingParams"; -import { InitialStateResponse } from "../InitialStateResponse"; -import { createInitialStateFromData } from "./helpers"; -import { InitialAPIResponse } from "./types"; +import { FetchingParams } from "../../../ValueProvider/TokenArray/fetchingParams"; +import { createInitialProductStateFromData } from "../helpers"; +import { InitialProductAPIResponse } from "../types"; +import { InitialProductStateResponse } from "./InitialProductStateResponse"; -export interface InitialAPIState { - data: InitialStateResponse; +export interface InitialProductAPIState { + data: InitialProductStateResponse; loading: boolean; fetchQueries: (params: FetchingParams) => Promise; } -export const useProductInitialAPIState = (): InitialAPIState => { +export const useProductInitialAPIState = (): InitialProductAPIState => { const client = useApolloClient(); - const [data, setData] = useState(InitialStateResponse.empty()); + const [data, setData] = useState( + InitialProductStateResponse.empty(), + ); const [loading, setLoading] = useState(true); - const queriesToRun: Array> = []; + const queriesToRun: Array> = []; const fetchQueries = async ({ category, collection, @@ -99,10 +101,10 @@ export const useProductInitialAPIState = (): InitialAPIState => { } const data = await Promise.all(queriesToRun); - const initialState = createInitialStateFromData(data, channel); + const initialState = createInitialProductStateFromData(data, channel); setData( - new InitialStateResponse( + new InitialProductStateResponse( initialState.category, initialState.attribute, initialState.channel, diff --git a/src/components/ConditionalFilter/API/initialState/types.ts b/src/components/ConditionalFilter/API/initialState/types.ts index 5631d752f4e..9b2dd4260d8 100644 --- a/src/components/ConditionalFilter/API/initialState/types.ts +++ b/src/components/ConditionalFilter/API/initialState/types.ts @@ -11,7 +11,7 @@ import { ChannelCurrenciesQuery, } from "@dashboard/graphql"; -export type InitialAPIResponse = ApolloQueryResult< +export type InitialProductAPIResponse = ApolloQueryResult< | _GetChannelOperandsQuery | _SearchCollectionsOperandsQuery | _SearchCategoriesOperandsQuery @@ -27,3 +27,5 @@ export type InitialPageAPIResponse = ApolloQueryResult<_SearchPageTypesOperandsQ export type InitialGiftCardsAPIResponse = ApolloQueryResult< _SearchProductOperandsQuery | _SearchCustomersOperandsQuery | ChannelCurrenciesQuery >; + +export type InitialCollectionAPIResponse = ApolloQueryResult<_GetChannelOperandsQuery>; diff --git a/src/components/ConditionalFilter/API/initialState/orders/intl.ts b/src/components/ConditionalFilter/API/intl.ts similarity index 87% rename from src/components/ConditionalFilter/API/initialState/orders/intl.ts rename to src/components/ConditionalFilter/API/intl.ts index 14eec7a21bc..4d25ab101d2 100644 --- a/src/components/ConditionalFilter/API/initialState/orders/intl.ts +++ b/src/components/ConditionalFilter/API/intl.ts @@ -1,5 +1,6 @@ import { LeftOperand } from "@dashboard/components/ConditionalFilter/LeftOperandsProvider"; import { + CollectionPublished, DiscountStatusEnum, OrderAuthorizeStatusEnum, OrderChargeStatusEnum, @@ -13,6 +14,7 @@ import { IntlShape } from "react-intl"; import { authorizeStatusMessages, chargeStatusMessages, + collectionFilterMessages, discountTypeMessages, voucherStatusMessages, } from "./messages"; @@ -81,6 +83,17 @@ const getVoucherStatusLabel = (status: DiscountStatusEnum, intl: IntlShape) => { } }; +const getPublishedLabel = (status: CollectionPublished, intl: IntlShape) => { + switch (status) { + case CollectionPublished.PUBLISHED: + return intl.formatMessage(collectionFilterMessages.published); + case CollectionPublished.HIDDEN: + return intl.formatMessage(collectionFilterMessages.hidden); + default: + return status; + } +}; + export const getLocalizedLabel = (rowType: LeftOperand["type"], value: string, intl: IntlShape) => { switch (rowType) { case "paymentStatus": @@ -91,6 +104,8 @@ export const getLocalizedLabel = (rowType: LeftOperand["type"], value: string, i return getAuthorizeStatusLabel(value as OrderAuthorizeStatusEnum, intl); case "chargeStatus": return getChargeStatusLabel(value as OrderChargeStatusEnum, intl); + case "published": + return getPublishedLabel(value as CollectionPublished, intl); case "discountType": return getDiscountTypeLabel(value as VoucherDiscountType, intl); case "voucherStatus": diff --git a/src/components/ConditionalFilter/API/initialState/orders/messages.ts b/src/components/ConditionalFilter/API/messages.ts similarity index 89% rename from src/components/ConditionalFilter/API/initialState/orders/messages.ts rename to src/components/ConditionalFilter/API/messages.ts index 44d650d3d2d..b70e6216a24 100644 --- a/src/components/ConditionalFilter/API/initialState/orders/messages.ts +++ b/src/components/ConditionalFilter/API/messages.ts @@ -76,3 +76,14 @@ export const voucherStatusMessages = defineMessages({ description: "voucher status scheduled", }, }); + +export const collectionFilterMessages = defineMessages({ + published: { + defaultMessage: "Published", + id: "w7tf2z", + }, + hidden: { + defaultMessage: "Hidden", + id: "ThUvIL", + }, +}); diff --git a/src/components/ConditionalFilter/API/providers/CollectionFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/CollectionFilterAPIProvider.tsx new file mode 100644 index 00000000000..db7ed0afcad --- /dev/null +++ b/src/components/ConditionalFilter/API/providers/CollectionFilterAPIProvider.tsx @@ -0,0 +1,65 @@ +import { ApolloClient, useApolloClient } from "@apollo/client"; +import { CollectionPublished } from "@dashboard/graphql/types.generated"; +import { IntlShape, useIntl } from "react-intl"; + +import { FilterContainer, FilterElement } from "../../FilterElement"; +import { FilterAPIProvider } from "../FilterAPIProvider"; +import { ChannelHandler, EnumValuesHandler, Handler, NoopValuesHandler } from "../Handler"; + +const getFilterElement = (value: FilterContainer, index: number): FilterElement => { + const possibleFilterElement = value[index]; + + if (typeof possibleFilterElement !== "string" && !Array.isArray(possibleFilterElement)) { + return possibleFilterElement; + } + + throw new Error("Unknown filter element used to create API handler"); +}; +const createAPIHandler = ( + selectedRow: FilterElement, + client: ApolloClient, + inputValue: string, + intl: IntlShape, +): Handler => { + const rowType = selectedRow.rowType(); + + if (rowType === "published") { + return new EnumValuesHandler(CollectionPublished, "published", intl); + } + + if (rowType === "metadata") { + return new NoopValuesHandler([]); + } + + if (rowType === "channel") { + return new ChannelHandler(client, inputValue); + } + + throw new Error(`Unknown filter element: "${rowType}"`); +}; + +export const useCollectionFilterAPIProvider = (): FilterAPIProvider => { + const intl = useIntl(); + const client = useApolloClient(); + + const fetchRightOptions = async ( + position: string, + value: FilterContainer, + inputValue: string, + ) => { + const index = parseInt(position, 10); + const filterElement = getFilterElement(value, index); + + const handler = createAPIHandler(filterElement, client, inputValue, intl); + + return handler.fetch(); + }; + const fetchLeftOptions = async () => { + return []; + }; + + return { + fetchRightOptions, + fetchLeftOptions, + }; +}; diff --git a/src/components/ConditionalFilter/API/CustomerFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/CustomerFilterAPIProvider.tsx similarity index 81% rename from src/components/ConditionalFilter/API/CustomerFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/CustomerFilterAPIProvider.tsx index 5bc80d3c68a..db66287a4c8 100644 --- a/src/components/ConditionalFilter/API/CustomerFilterAPIProvider.tsx +++ b/src/components/ConditionalFilter/API/providers/CustomerFilterAPIProvider.tsx @@ -1,4 +1,4 @@ -import { FilterAPIProvider } from "./FilterAPIProvider"; +import { FilterAPIProvider } from "../FilterAPIProvider"; export const useCustomerAPIProvider = (): FilterAPIProvider => { const fetchRightOptions = async () => { diff --git a/src/components/ConditionalFilter/API/DiscountFiltersAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/DiscountFiltersAPIProvider.tsx similarity index 100% rename from src/components/ConditionalFilter/API/DiscountFiltersAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/DiscountFiltersAPIProvider.tsx diff --git a/src/components/ConditionalFilter/API/DraftOrderFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/DraftOrderFilterAPIProvider.tsx similarity index 100% rename from src/components/ConditionalFilter/API/DraftOrderFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/DraftOrderFilterAPIProvider.tsx diff --git a/src/components/ConditionalFilter/API/GiftCardsFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/GiftCardsFilterAPIProvider.tsx similarity index 100% rename from src/components/ConditionalFilter/API/GiftCardsFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/GiftCardsFilterAPIProvider.tsx diff --git a/src/components/ConditionalFilter/API/OrderFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/OrderFilterAPIProvider.tsx similarity index 95% rename from src/components/ConditionalFilter/API/OrderFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/OrderFilterAPIProvider.tsx index 6547b935a07..102b960bbd6 100644 --- a/src/components/ConditionalFilter/API/OrderFilterAPIProvider.tsx +++ b/src/components/ConditionalFilter/API/providers/OrderFilterAPIProvider.tsx @@ -8,8 +8,8 @@ import { } from "@dashboard/graphql"; import { IntlShape, useIntl } from "react-intl"; -import { RowType } from "../constants"; -import { FilterContainer, FilterElement } from "../FilterElement"; +import { RowType } from "../../constants"; +import { FilterContainer, FilterElement } from "../../FilterElement"; import { BooleanValuesHandler, EnumValuesHandler, @@ -17,7 +17,7 @@ import { LegacyChannelHandler, NoopValuesHandler, TextInputValuesHandler, -} from "./Handler"; +} from "../Handler"; const getFilterElement = (value: FilterContainer, index: number): FilterElement => { const possibleFilterElement = value[index]; diff --git a/src/components/ConditionalFilter/API/PageFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/PageFilterAPIProvider.tsx similarity index 95% rename from src/components/ConditionalFilter/API/PageFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/PageFilterAPIProvider.tsx index d9069c2db3b..25f4432c695 100644 --- a/src/components/ConditionalFilter/API/PageFilterAPIProvider.tsx +++ b/src/components/ConditionalFilter/API/providers/PageFilterAPIProvider.tsx @@ -5,7 +5,7 @@ import { FilterElement, } from "@dashboard/components/ConditionalFilter/FilterElement"; -import { FilterAPIProvider } from "./FilterAPIProvider"; +import { FilterAPIProvider } from "../FilterAPIProvider"; const getFilterElement = (value: FilterContainer, index: number): FilterElement => { const possibleFilterElement = value[index]; diff --git a/src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx b/src/components/ConditionalFilter/API/providers/ProductFilterAPIProvider.tsx similarity index 93% rename from src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx rename to src/components/ConditionalFilter/API/providers/ProductFilterAPIProvider.tsx index d55946486f4..0d68087751b 100644 --- a/src/components/ConditionalFilter/API/ProductFilterAPIProvider.tsx +++ b/src/components/ConditionalFilter/API/providers/ProductFilterAPIProvider.tsx @@ -1,9 +1,9 @@ import { ApolloClient, useApolloClient } from "@apollo/client"; import { AttributeInputTypeEnum } from "@dashboard/graphql"; -import { RowType } from "../constants"; -import { FilterContainer, FilterElement } from "../FilterElement"; -import { FilterAPIProvider } from "./FilterAPIProvider"; +import { RowType } from "../../constants"; +import { FilterContainer, FilterElement } from "../../FilterElement"; +import { FilterAPIProvider } from "../FilterAPIProvider"; import { AttributeChoicesHandler, AttributesHandler, @@ -13,7 +13,7 @@ import { CollectionHandler, Handler, ProductTypeHandler, -} from "./Handler"; +} from "../Handler"; const getFilterElement = (value: FilterContainer, index: number): FilterElement => { const possibleFilterElement = value[index]; diff --git a/src/components/ConditionalFilter/API/VoucherFilterAPIProvider.ts b/src/components/ConditionalFilter/API/providers/VoucherFilterAPIProvider.ts similarity index 97% rename from src/components/ConditionalFilter/API/VoucherFilterAPIProvider.ts rename to src/components/ConditionalFilter/API/providers/VoucherFilterAPIProvider.ts index b91fc1c33c6..9d9167720c5 100644 --- a/src/components/ConditionalFilter/API/VoucherFilterAPIProvider.ts +++ b/src/components/ConditionalFilter/API/providers/VoucherFilterAPIProvider.ts @@ -11,7 +11,7 @@ import { import { DiscountStatusEnum, VoucherDiscountType } from "@dashboard/graphql"; import { IntlShape, useIntl } from "react-intl"; -import { FilterAPIProvider } from "./FilterAPIProvider"; +import { FilterAPIProvider } from "../FilterAPIProvider"; const getFilterElement = (value: FilterContainer, index: number): FilterElement => { const possibleFilterElement = value[index]; diff --git a/src/components/ConditionalFilter/FilterElement/Condition.test.ts b/src/components/ConditionalFilter/FilterElement/Condition.test.ts index c282ccaf3a8..2648080bb1e 100644 --- a/src/components/ConditionalFilter/FilterElement/Condition.test.ts +++ b/src/components/ConditionalFilter/FilterElement/Condition.test.ts @@ -1,4 +1,4 @@ -import { InitialStateResponse } from "../API/InitialStateResponse"; +import { InitialProductStateResponse } from "../API/initialState/product/InitialProductStateResponse"; import { STATIC_CONDITIONS } from "../constants"; import { UrlToken } from "../ValueProvider/UrlToken"; import { Condition } from "./Condition"; @@ -24,7 +24,7 @@ describe("ConditionalFilter / FilterElement / Condition", () => { it.each([ { token: new UrlToken("category", ["cat1"], "s", "is"), - response: new InitialStateResponse([ + response: new InitialProductStateResponse([ { label: "Cat1", value: "cat-1-id", @@ -47,7 +47,7 @@ describe("ConditionalFilter / FilterElement / Condition", () => { }, { token: new UrlToken("some-attr1", ["some-attr-1z"], "m", "in"), - response: new InitialStateResponse([], { + response: new InitialProductStateResponse([], { "some-attr1": { choices: [ { diff --git a/src/components/ConditionalFilter/FilterElement/Condition.ts b/src/components/ConditionalFilter/FilterElement/Condition.ts index 67c9065ce7c..27e7262d4bf 100644 --- a/src/components/ConditionalFilter/FilterElement/Condition.ts +++ b/src/components/ConditionalFilter/FilterElement/Condition.ts @@ -1,9 +1,6 @@ -import { InitialGiftCardsStateResponse } from "../API/initialState/giftCards/InitialGiftCardsState"; -import { InitialOrderStateResponse } from "../API/initialState/orders/InitialOrderState"; -import { InitialPageStateResponse } from "../API/initialState/page/InitialPageState"; -import { InitialVouchersStateResponse } from "../API/initialState/vouchers/InitialVouchersState"; -import { InitialStateResponse } from "../API/InitialStateResponse"; +import { InitialProductStateResponse } from "../API/initialState/product/InitialProductStateResponse"; import { LeftOperand } from "../LeftOperandsProvider"; +import { InitialResponseType } from "../types"; import { UrlToken } from "./../ValueProvider/UrlToken"; import { ConditionOptions, StaticElementName } from "./ConditionOptions"; import { ConditionSelected } from "./ConditionSelected"; @@ -48,15 +45,7 @@ export class Condition { return new Condition(options, ConditionSelected.fromConditionItem(options.first()), false); } - public static fromUrlToken( - token: UrlToken, - response: - | InitialStateResponse - | InitialOrderStateResponse - | InitialVouchersStateResponse - | InitialPageStateResponse - | InitialGiftCardsStateResponse, - ) { + public static fromUrlToken(token: UrlToken, response: InitialResponseType) { if (ConditionOptions.isStaticName(token.name)) { const staticOptions = ConditionOptions.fromStaticElementName(token.name); const selectedOption = staticOptions.findByLabel(token.conditionKind); @@ -81,7 +70,7 @@ export class Condition { } if (token.isAttribute()) { - const attribute = (response as InitialStateResponse).attributeByName(token.name); + const attribute = (response as InitialProductStateResponse).attributeByName(token.name); const options = ConditionOptions.fromAttributeType(attribute.inputType); const option = options.find(item => item.label === token.conditionKind)!; const value = response.filterByUrlToken(token); diff --git a/src/components/ConditionalFilter/FilterElement/Constraint.test.ts b/src/components/ConditionalFilter/FilterElement/Constraint.test.ts index a44ab24ced4..228a0eb2bcc 100644 --- a/src/components/ConditionalFilter/FilterElement/Constraint.test.ts +++ b/src/components/ConditionalFilter/FilterElement/Constraint.test.ts @@ -21,7 +21,7 @@ describe("ConditionalFilter / FilterElement / Constraint", () => { // Assert expect(constraint).toEqual({ - dependsOn: ["price", "isVisibleInListing", "isAvailable", "isPublished"], + dependsOn: ["price", "isVisibleInListing", "isAvailable", "isPublished", "published"], disabled: ["left", "condition"], removable: false, }); diff --git a/src/components/ConditionalFilter/FilterElement/FilterElement.ts b/src/components/ConditionalFilter/FilterElement/FilterElement.ts index b07446d8c99..ea79aa31840 100644 --- a/src/components/ConditionalFilter/FilterElement/FilterElement.ts +++ b/src/components/ConditionalFilter/FilterElement/FilterElement.ts @@ -1,10 +1,7 @@ -import { InitialGiftCardsStateResponse } from "../API/initialState/giftCards/InitialGiftCardsState"; -import { InitialOrderStateResponse } from "../API/initialState/orders/InitialOrderState"; -import { InitialPageStateResponse } from "../API/initialState/page/InitialPageState"; -import { InitialVouchersStateResponse } from "../API/initialState/vouchers/InitialVouchersState"; -import { InitialStateResponse } from "../API/InitialStateResponse"; +import { InitialProductStateResponse } from "../API/initialState/product/InitialProductStateResponse"; import { RowType, STATIC_OPTIONS } from "../constants"; import { LeftOperand } from "../LeftOperandsProvider"; +import { InitialResponseType } from "../types"; import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken"; import { Condition } from "./Condition"; import { ConditionItem, ConditionOptions, StaticElementName } from "./ConditionOptions"; @@ -49,7 +46,7 @@ export class ExpressionValue { return new ExpressionValue(token.name, option.label, token.name); } - public static forAttribute(attributeName: string, response: InitialStateResponse) { + public static forAttribute(attributeName: string, response: InitialProductStateResponse) { const attribute = response.attributeByName(attributeName); return new ExpressionValue(attributeName, attribute.label, attribute.inputType); @@ -178,15 +175,7 @@ export class FilterElement { return new FilterElement(ExpressionValue.fromSlug(slug), Condition.emptyFromSlug(slug), false); } - public static fromUrlToken( - token: UrlToken, - response: - | InitialStateResponse - | InitialOrderStateResponse - | InitialVouchersStateResponse - | InitialPageStateResponse - | InitialGiftCardsStateResponse, - ) { + public static fromUrlToken(token: UrlToken, response: InitialResponseType) { if (token.isStatic()) { return new FilterElement( ExpressionValue.fromUrlToken(token), @@ -197,7 +186,7 @@ export class FilterElement { if (token.isAttribute()) { return new FilterElement( - ExpressionValue.forAttribute(token.name, response as InitialStateResponse), + ExpressionValue.forAttribute(token.name, response as InitialProductStateResponse), Condition.fromUrlToken(token, response), false, ); diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/TokenArray.test.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/TokenArray.test.ts index b29af42321f..63375e4af24 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/TokenArray.test.ts +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/TokenArray.test.ts @@ -1,4 +1,4 @@ -import { InitialStateResponse } from "../../API/InitialStateResponse"; +import { InitialProductStateResponse } from "../../API/initialState/product/InitialProductStateResponse"; import { TokenArray } from "."; import { FetchingParams } from "./fetchingParams"; @@ -15,7 +15,7 @@ describe("ConditionalFilter / ValueProvider / TokenArray", () => { // Arrange const url = new TokenArray(""); // Act - const fetchingParams = url.getFetchingParams(productParams); + const fetchingParams = url.getFetchingParams(productParams, "product"); // Assert expect(fetchingParams).toEqual({ @@ -44,7 +44,7 @@ describe("ConditionalFilter / ValueProvider / TokenArray", () => { }); // Act const url = new TokenArray(params.toString()); - const fetchingParams = url.getFetchingParams(productParams); + const fetchingParams = url.getFetchingParams(productParams, "product"); // Assert expect(fetchingParams).toEqual({ @@ -64,7 +64,7 @@ describe("ConditionalFilter / ValueProvider / TokenArray", () => { "1": "AND", "2[s0.channel]": "channel-pln", }); - const response = new InitialStateResponse( + const response = new InitialProductStateResponse( [ { label: "Cat1", @@ -93,7 +93,7 @@ describe("ConditionalFilter / ValueProvider / TokenArray", () => { const params = new URLSearchParams({ "0[s0.channel]": "channel-pln", }); - const response = new InitialStateResponse( + const response = new InitialProductStateResponse( [ { label: "Cat1", diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/__snapshots__/TokenArray.test.ts.snap b/src/components/ConditionalFilter/ValueProvider/TokenArray/__snapshots__/TokenArray.test.ts.snap index 75a346f834c..3e1e62796b8 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/__snapshots__/TokenArray.test.ts.snap +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/__snapshots__/TokenArray.test.ts.snap @@ -116,6 +116,7 @@ TokenArray [ "isVisibleInListing", "isAvailable", "isPublished", + "published", ], "disabled": Array [ "left", diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.test.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.test.ts index a5d1291d58d..e83e784d74a 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.test.ts +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.test.ts @@ -1,18 +1,19 @@ import { UrlToken } from "../UrlToken"; import { - getFetchingPrams, + getEmptyFetchingPrams, + toCollectionFetchingParams, toGiftCardsFetchingParams, toPageFetchingParams, toVouchersFetchingParams, } from "./fetchingParams"; -describe("TokenArray / fetchingParams / getFetchingPrams", () => { +describe("TokenArray / fetchingParams / getEmptyFetchingPrams", () => { it("should return product fetching params", () => { // Arrange const type = "product"; // Act - const fetchingParams = getFetchingPrams(type); + const fetchingParams = getEmptyFetchingPrams(type); // Assert expect(fetchingParams).toEqual({ @@ -29,7 +30,7 @@ describe("TokenArray / fetchingParams / getFetchingPrams", () => { const type = "order"; // Act - const fetchingParams = getFetchingPrams(type); + const fetchingParams = getEmptyFetchingPrams(type); // Assert expect(fetchingParams).toEqual({ @@ -48,7 +49,7 @@ describe("TokenArray / fetchingParams / getFetchingPrams", () => { const type = "voucher"; // Act - const fetchingParams = getFetchingPrams(type); + const fetchingParams = getEmptyFetchingPrams(type); // Assert expect(fetchingParams).toEqual({ @@ -63,7 +64,7 @@ describe("TokenArray / fetchingParams / getFetchingPrams", () => { const type = "page"; // Act - const fetchingParams = getFetchingPrams(type); + const fetchingParams = getEmptyFetchingPrams(type); // Assert expect(fetchingParams).toEqual({ @@ -76,7 +77,7 @@ describe("TokenArray / fetchingParams / getFetchingPrams", () => { const type = "gift-cards"; // Act - const fetchingParams = getFetchingPrams(type); + const fetchingParams = getEmptyFetchingPrams(type); // Assert expect(fetchingParams).toEqual({ @@ -169,3 +170,31 @@ describe("TokenArray / fetchingParams / toGiftCardsFetchingParams", () => { }); }); }); + +describe("TokenArray / fetchingParams / toCollectionFetchingParams", () => { + it("should return fetching params", () => { + // Arrange + const params = { + channel: [], + metadata: [], + published: [], + }; + + const token = { + conditionKind: "in", + name: "channel", + type: "s", + value: "chan-1", + } as UrlToken; + + // Act + const fetchingParams = toCollectionFetchingParams(params, token); + + // Assert + expect(fetchingParams).toEqual({ + channel: ["chan-1"], + metadata: [], + published: [], + }); + }); +}); diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts index a68e87f4cd4..b07d1f42ea8 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/fetchingParams.ts @@ -1,3 +1,4 @@ +import { FilterProviderType } from "../../types"; import { TokenType, UrlToken } from "../UrlToken"; export interface FetchingParams { @@ -35,6 +36,12 @@ export interface GiftCardsFetchingParams { usedBy: string[]; } +export interface CollectionFetchingParams { + channel: string[]; + metadata: string[]; + published: string[]; +} + type FetchingParamsKeys = keyof Omit; type OrderParamsKeys = keyof OrderFetchingParams; type VoucherParamsKeys = keyof VoucherFetchingParams; @@ -76,6 +83,12 @@ export const emptyGiftCardsFetchingParams: GiftCardsFetchingParams = { usedBy: [], }; +export const emptyCollectionFetchingParams: CollectionFetchingParams = { + channel: [], + metadata: [], + published: [], +}; + const unique = (array: Iterable) => Array.from(new Set(array)); const includedInParams = (c: UrlToken) => TokenType.ATTRIBUTE_DROPDOWN === c.type || TokenType.ATTRIBUTE_MULTISELECT === c.type; @@ -162,17 +175,27 @@ export const toGiftCardsFetchingParams = (p: GiftCardsFetchingParams, c: UrlToke return p; }; -export const getFetchingPrams = ( - type: - | "product" - | "order" - | "discount" - | "voucher" - | "page" - | "draft-order" - | "gift-cards" - | "customer", -) => { +export const toCollectionFetchingParams = (p: CollectionFetchingParams, c: UrlToken) => { + const key = c.name as keyof CollectionFetchingParams; + + if (!p[key]) { + p[key] = []; + } + + p[key] = unique(p[key].concat(c.value)); + + return p; +}; + +export type FetchingParamsType = + | OrderFetchingParams + | FetchingParams + | CollectionFetchingParams + | GiftCardsFetchingParams + | PageFetchingParams + | VoucherFetchingParams; + +export const getEmptyFetchingPrams = (type: FilterProviderType) => { switch (type) { case "product": return emptyFetchingParams; @@ -184,5 +207,7 @@ export const getFetchingPrams = ( return emptyPageFetchingParams; case "gift-cards": return emptyGiftCardsFetchingParams; + case "collection": + return emptyCollectionFetchingParams; } }; diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts index 26c47713790..0363230b796 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts @@ -1,17 +1,17 @@ import { parse, ParsedQs } from "qs"; -import { InitialGiftCardsStateResponse } from "../../API/initialState/giftCards/InitialGiftCardsState"; -import { InitialOrderStateResponse } from "../../API/initialState/orders/InitialOrderState"; -import { InitialPageStateResponse } from "../../API/initialState/page/InitialPageState"; -import { InitialVouchersStateResponse } from "../../API/initialState/vouchers/InitialVouchersState"; -import { InitialStateResponse } from "../../API/InitialStateResponse"; +import { InitialProductStateResponse } from "../../API/initialState/product/InitialProductStateResponse"; import { FilterContainer, FilterElement } from "../../FilterElement"; +import { FilterProviderType, InitialResponseType } from "../../types"; import { UrlEntry, UrlToken } from "../UrlToken"; import { + CollectionFetchingParams, FetchingParams, + FetchingParamsType, GiftCardsFetchingParams, OrderFetchingParams, PageFetchingParams, + toCollectionFetchingParams, toFetchingParams, toGiftCardsFetchingParams, toOrderFetchingParams, @@ -52,12 +52,7 @@ const tokenizeUrl = (urlParams: string) => { }; const mapUrlTokensToFilterValues = ( urlTokens: TokenArray, - response: - | InitialStateResponse - | InitialOrderStateResponse - | InitialVouchersStateResponse - | InitialPageStateResponse - | InitialGiftCardsStateResponse, + response: InitialResponseType, ): FilterContainer => urlTokens.map(el => { if (typeof el === "string") { @@ -76,55 +71,46 @@ export class TokenArray extends Array { super(...tokenizeUrl(url)); } - public getFetchingParams( - params: - | OrderFetchingParams - | FetchingParams - | VoucherFetchingParams - | PageFetchingParams - | GiftCardsFetchingParams, - ) { - if ("paymentStatus" in params) { - return this.asFlatArray() - .filter(token => token.isLoadable()) - .reduce(toOrderFetchingParams, params); + public getFetchingParams(params: FetchingParamsType, type: FilterProviderType) { + switch (type) { + case "order": + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce(toOrderFetchingParams, params as OrderFetchingParams); + case "collection": + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce( + toCollectionFetchingParams, + params as CollectionFetchingParams, + ); + case "voucher": + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce(toVouchersFetchingParams, params as VoucherFetchingParams); + case "page": + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce(toPageFetchingParams, params as PageFetchingParams); + case "gift-cards": + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce( + toGiftCardsFetchingParams, + params as GiftCardsFetchingParams, + ); + default: + return this.asFlatArray() + .filter(token => token.isLoadable()) + .reduce(toFetchingParams, params as FetchingParams); } - - if ("discountType" in params) { - return this.asFlatArray() - .filter(token => token.isLoadable()) - .reduce(toVouchersFetchingParams, params); - } - - if ("pageTypes" in params) { - return this.asFlatArray() - .filter(token => token.isLoadable()) - .reduce(toPageFetchingParams, params); - } - - if ("currency" in params) { - return this.asFlatArray() - .filter(token => token.isLoadable()) - .reduce(toGiftCardsFetchingParams, params); - } - - return this.asFlatArray() - .filter(token => token.isLoadable()) - .reduce(toFetchingParams, params); } public asFlatArray() { return flatenate(this); } - public asFilterValuesFromResponse( - response: - | InitialStateResponse - | InitialOrderStateResponse - | InitialVouchersStateResponse - | InitialPageStateResponse - | InitialGiftCardsStateResponse, - ): FilterContainer { + public asFilterValuesFromResponse(response: InitialResponseType): FilterContainer { return this.map(el => { if (typeof el === "string") { return el; @@ -145,6 +131,6 @@ export class TokenArray extends Array { } public asFilterValueFromEmpty(): FilterContainer { - return this.asFilterValuesFromResponse(InitialStateResponse.empty()); + return this.asFilterValuesFromResponse(InitialProductStateResponse.empty()); } } diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/ordersFetchingParams.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/ordersFetchingParams.ts deleted file mode 100644 index e3425d48408..00000000000 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/ordersFetchingParams.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { UrlToken } from "../UrlToken"; - -export interface OrdersFetchingParams { - paymentStatus: string[]; -} - -type FetchingParamsKeys = keyof Omit; - -export const emptyFetchingParams: OrdersFetchingParams = { - paymentStatus: [], -}; - -const unique = (array: Iterable) => Array.from(new Set(array)); - -export const toFetchingParams = (p: OrdersFetchingParams, c: UrlToken) => { - const key = c.name as FetchingParamsKeys; - - if (!c.isAttribute() && !p[key]) { - p[key] = []; - } - - p[key] = unique(p[key].concat(c.value)); - - return p; -}; diff --git a/src/components/ConditionalFilter/ValueProvider/UrlToken.ts b/src/components/ConditionalFilter/ValueProvider/UrlToken.ts index ec9a4728b94..676fc814bb0 100644 --- a/src/components/ConditionalFilter/ValueProvider/UrlToken.ts +++ b/src/components/ConditionalFilter/ValueProvider/UrlToken.ts @@ -6,6 +6,18 @@ import { slugFromConditionValue } from "../FilterElement/ConditionValue"; export const CONDITIONS = ["is", "equals", "in", "between", "lower", "greater"]; +const PRODUCT_STATICS = [ + "category", + "collection", + "channel", + "productType", + "isAvailable", + "isPublished", + "isVisibleInListing", + "hasCategory", + "giftCard", +]; + const ORDER_STATICS = [ "paymentStatus", "status", @@ -25,20 +37,15 @@ const PAGE_STATIC = ["pageTypes"]; const GIFT_CARDS_STATICS = ["currency", "products", "isActive", "tags", "usedBy"]; +const COLLECTION_STATICS = ["channel", "published"]; + const STATIC_TO_LOAD = [ - "category", - "collection", - "channel", - "productType", - "isAvailable", - "isPublished", - "isVisibleInListing", - "hasCategory", - "giftCard", + ...PRODUCT_STATICS, ...ORDER_STATICS, ...VOUCHER_STATICS, ...PAGE_STATIC, ...GIFT_CARDS_STATICS, + ...COLLECTION_STATICS, ]; export const TokenType = { diff --git a/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts b/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts index 65a4ba966da..fe48f3227d2 100644 --- a/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts +++ b/src/components/ConditionalFilter/ValueProvider/useUrlValueProvider.ts @@ -3,17 +3,20 @@ import { stringify } from "qs"; import { useEffect, useState } from "react"; import useRouter from "use-react-router"; -import { InitialAPIState } from "../API"; +import { InitialCollectionAPIState } from "../API/initialState/collections/useInitialCollectionsState"; import { InitialGiftCardsAPIState } from "../API/initialState/giftCards/useInitialGiftCardsState"; import { InitialOrderAPIState } from "../API/initialState/orders/useInitialOrderState"; import { InitialPageAPIState } from "../API/initialState/page/useInitialPageState"; +import { InitialProductAPIState } from "../API/initialState/product/useProductInitialAPIState"; import { InitialVoucherAPIState } from "../API/initialState/vouchers/useInitialVouchersState"; import { FilterContainer, FilterElement } from "../FilterElement"; import { FilterValueProvider } from "../FilterValueProvider"; +import { FilterProviderType, InitialAPIState } from "../types"; import { TokenArray } from "./TokenArray"; import { + CollectionFetchingParams, FetchingParams, - getFetchingPrams, + getEmptyFetchingPrams, GiftCardsFetchingParams, OrderFetchingParams, PageFetchingParams, @@ -23,21 +26,8 @@ import { prepareStructure } from "./utils"; export const useUrlValueProvider = ( locationSearch: string, - type: - | "product" - | "order" - | "discount" - | "voucher" - | "page" - | "draft-order" - | "gift-cards" - | "customer", - initialState?: - | InitialAPIState - | InitialOrderAPIState - | InitialVoucherAPIState - | InitialPageAPIState - | InitialGiftCardsAPIState, + type: FilterProviderType, + initialState?: InitialAPIState, ): FilterValueProvider => { const router = useRouter(); const params = new URLSearchParams(locationSearch); @@ -55,14 +45,16 @@ export const useUrlValueProvider = ( params.delete("after"); const tokenizedUrl = new TokenArray(params.toString()); - const paramsFromType = getFetchingPrams(type); - const fetchingParams = paramsFromType ? tokenizedUrl.getFetchingParams(paramsFromType) : null; + const paramsFromType = getEmptyFetchingPrams(type); + const fetchingParams = paramsFromType + ? tokenizedUrl.getFetchingParams(paramsFromType, type) + : null; useEffect(() => { if (initialState) { switch (type) { case "product": - (initialState as InitialAPIState).fetchQueries(fetchingParams as FetchingParams); + (initialState as InitialProductAPIState).fetchQueries(fetchingParams as FetchingParams); break; case "order": (initialState as InitialOrderAPIState).fetchQueries( @@ -82,6 +74,11 @@ export const useUrlValueProvider = ( fetchingParams as GiftCardsFetchingParams, ); break; + case "collection": + (initialState as InitialCollectionAPIState).fetchQueries( + fetchingParams as CollectionFetchingParams, + ); + break; } } }, [locationSearch]); diff --git a/src/components/ConditionalFilter/constants.ts b/src/components/ConditionalFilter/constants.ts index 5518f689761..acea0513748 100644 --- a/src/components/ConditionalFilter/constants.ts +++ b/src/components/ConditionalFilter/constants.ts @@ -182,11 +182,25 @@ export const STATIC_CONDITIONS = { products: [{ type: "multiselect", label: "in", value: "input-1" }], tags: [{ type: "multiselect", label: "in", value: "input-1" }], usedBy: [{ type: "multiselect", label: "in", value: "input-1" }], + published: [ + { + type: "select", + label: "is", + value: "input-1", + }, + ], + slugs: [ + { + type: "bulkselect", + label: "in", + value: "input-1", + }, + ], }; export const CONSTRAINTS = { channel: { - dependsOn: ["price", "isVisibleInListing", "isAvailable", "isPublished"], + dependsOn: ["price", "isVisibleInListing", "isAvailable", "isPublished", "published"], removable: false, disabled: ["left", "condition"], }, @@ -375,6 +389,27 @@ export const STATIC_VOUCHER_OPTIONS: LeftOperand[] = [ }, ]; +export const STATIC_COLLECTION_OPTIONS: LeftOperand[] = [ + { + value: "published", + label: "Published", + type: "published", + slug: "published", + }, + { + value: "metadata", + label: "Metadata", + type: "metadata", + slug: "metadata", + }, + { + value: "channel", + label: "Channel", + type: "channel", + slug: "channel", + }, +]; + export const STATIC_PAGE_OPTIONS: LeftOperand[] = [ { value: "pageTypes", @@ -468,6 +503,7 @@ export const STATIC_OPTIONS = [ ...STATIC_DRAFT_ORDER_OPTIONS, ...STATIC_GIFT_CARDS_OPTIONS, ...STATIC_CUSTOMER_OPTIONS, + ...STATIC_COLLECTION_OPTIONS, ]; export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = { diff --git a/src/components/ConditionalFilter/context/provider.tsx b/src/components/ConditionalFilter/context/provider.tsx index 7d6bfcd0c7d..71664358aaf 100644 --- a/src/components/ConditionalFilter/context/provider.tsx +++ b/src/components/ConditionalFilter/context/provider.tsx @@ -1,19 +1,22 @@ import React, { FC } from "react"; -import { useCustomerAPIProvider } from "../API/CustomerFilterAPIProvider"; -import { useDiscountFilterAPIProvider } from "../API/DiscountFiltersAPIProvider"; -import { useDraftOrderFilterAPIProvider } from "../API/DraftOrderFilterAPIProvider"; -import { useGiftCardsFiltersAPIProvider } from "../API/GiftCardsFilterAPIProvider"; +import { useInitialCollectionState } from "../API/initialState/collections/useInitialCollectionsState"; import { useInitialGiftCardsState } from "../API/initialState/giftCards/useInitialGiftCardsState"; import { useInitialOrderState } from "../API/initialState/orders/useInitialOrderState"; import { useInitialPageState } from "../API/initialState/page/useInitialPageState"; -import { useProductInitialAPIState } from "../API/initialState/useInitialAPIState"; +import { useProductInitialAPIState } from "../API/initialState/product/useProductInitialAPIState"; import { useInitialVouchersState } from "../API/initialState/vouchers/useInitialVouchersState"; -import { useOrderFilterAPIProvider } from "../API/OrderFilterAPIProvider"; -import { usePageAPIProvider } from "../API/PageFilterAPIProvider"; -import { useProductFilterAPIProvider } from "../API/ProductFilterAPIProvider"; -import { useVoucherAPIProvider } from "../API/VoucherFilterAPIProvider"; +import { useCollectionFilterAPIProvider } from "../API/providers/CollectionFilterAPIProvider"; +import { useCustomerAPIProvider } from "../API/providers/CustomerFilterAPIProvider"; +import { useDiscountFilterAPIProvider } from "../API/providers/DiscountFiltersAPIProvider"; +import { useDraftOrderFilterAPIProvider } from "../API/providers/DraftOrderFilterAPIProvider"; +import { useGiftCardsFiltersAPIProvider } from "../API/providers/GiftCardsFilterAPIProvider"; +import { useOrderFilterAPIProvider } from "../API/providers/OrderFilterAPIProvider"; +import { usePageAPIProvider } from "../API/providers/PageFilterAPIProvider"; +import { useProductFilterAPIProvider } from "../API/providers/ProductFilterAPIProvider"; +import { useVoucherAPIProvider } from "../API/providers/VoucherFilterAPIProvider"; import { + STATIC_COLLECTION_OPTIONS, STATIC_CUSTOMER_OPTIONS, STATIC_DISCOUNT_OPTIONS, STATIC_DRAFT_ORDER_OPTIONS, @@ -232,3 +235,30 @@ export const ConditionalCustomerFilterProvider: FC<{ ); }; + +export const ConditionalCollectionFilterProvider: FC<{ + locationSearch: string; +}> = ({ children, locationSearch }) => { + const apiProvider = useCollectionFilterAPIProvider(); + + const initialState = useInitialCollectionState(); + + const valueProvider = useUrlValueProvider(locationSearch, "collection", initialState); + const leftOperandsProvider = useFilterLeftOperandsProvider(STATIC_COLLECTION_OPTIONS); + const containerState = useContainerState(valueProvider); + const filterWindow = useFilterWindow(); + + return ( + + {children} + + ); +}; diff --git a/src/components/ConditionalFilter/queryVariables.ts b/src/components/ConditionalFilter/queryVariables.ts index 01a72346437..06eec2f249c 100644 --- a/src/components/ConditionalFilter/queryVariables.ts +++ b/src/components/ConditionalFilter/queryVariables.ts @@ -1,5 +1,6 @@ import { AttributeInput, + CollectionFilterInput, CustomerFilterInput, DateRangeInput, DateTimeFilterInput, @@ -340,3 +341,27 @@ export const createCustomerQueryVariables = (value: FilterContainer): CustomerFi return p; }, {} as CustomerFilterInput); }; + +type CollectionQueryVars = CollectionFilterInput & { channel?: { eq: string } }; + +export const createCollectionsQueryVariables = (value: FilterContainer): CollectionQueryVars => { + return value.reduce((p, c) => { + if (typeof c === "string" || Array.isArray(c)) return p; + + if (c.value.type === "metadata") { + p.metadata = p.metadata || []; + + const [key, value] = c.condition.selected.value as [string, string]; + + p.metadata.push({ key, value }); + + return p; + } + + p[c.value.value as keyof CollectionFilterInput] = mapStaticQueryPartToLegacyVariables( + createStaticQueryPart(c.condition.selected), + ); + + return p; + }, {} as CollectionQueryVars); +}; diff --git a/src/components/ConditionalFilter/types.ts b/src/components/ConditionalFilter/types.ts new file mode 100644 index 00000000000..762b6cab042 --- /dev/null +++ b/src/components/ConditionalFilter/types.ts @@ -0,0 +1,39 @@ +import { InitialCollectionStateResponse } from "./API/initialState/collections/InitialCollectionState"; +import { InitialCollectionAPIState } from "./API/initialState/collections/useInitialCollectionsState"; +import { InitialGiftCardsStateResponse } from "./API/initialState/giftCards/InitialGiftCardsState"; +import { InitialGiftCardsAPIState } from "./API/initialState/giftCards/useInitialGiftCardsState"; +import { InitialOrderStateResponse } from "./API/initialState/orders/InitialOrderState"; +import { InitialOrderAPIState } from "./API/initialState/orders/useInitialOrderState"; +import { InitialPageStateResponse } from "./API/initialState/page/InitialPageState"; +import { InitialPageAPIState } from "./API/initialState/page/useInitialPageState"; +import { InitialProductStateResponse } from "./API/initialState/product/InitialProductStateResponse"; +import { InitialProductAPIState } from "./API/initialState/product/useProductInitialAPIState"; +import { InitialVouchersStateResponse } from "./API/initialState/vouchers/InitialVouchersState"; +import { InitialVoucherAPIState } from "./API/initialState/vouchers/useInitialVouchersState"; + +export type InitialResponseType = + | InitialProductStateResponse + | InitialOrderStateResponse + | InitialCollectionStateResponse + | InitialVouchersStateResponse + | InitialPageStateResponse + | InitialGiftCardsStateResponse; + +export type InitialAPIState = + | InitialProductAPIState + | InitialOrderAPIState + | InitialVoucherAPIState + | InitialPageAPIState + | InitialGiftCardsAPIState + | InitialCollectionAPIState; + +export type FilterProviderType = + | "product" + | "order" + | "discount" + | "customer" + | "voucher" + | "page" + | "draft-order" + | "gift-cards" + | "collection";