Add product type filter
This commit is contained in:
parent
0a58c3a5e1
commit
3bdd0dab6f
6 changed files with 154 additions and 26 deletions
|
@ -15,6 +15,7 @@ export enum ProductFilterKeys {
|
||||||
collections = "collections",
|
collections = "collections",
|
||||||
status = "status",
|
status = "status",
|
||||||
price = "price",
|
price = "price",
|
||||||
|
productType = "productType",
|
||||||
stock = "stock"
|
stock = "stock"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ export interface ProductListFilterOpts {
|
||||||
categories: FilterOpts<string[]> & AutocompleteFilterOpts;
|
categories: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||||
collections: FilterOpts<string[]> & AutocompleteFilterOpts;
|
collections: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||||
price: FilterOpts<MinMax>;
|
price: FilterOpts<MinMax>;
|
||||||
|
productType: FilterOpts<string[]> & AutocompleteFilterOpts;
|
||||||
status: FilterOpts<ProductStatus>;
|
status: FilterOpts<ProductStatus>;
|
||||||
stockStatus: FilterOpts<StockAvailability>;
|
stockStatus: FilterOpts<StockAvailability>;
|
||||||
}
|
}
|
||||||
|
@ -147,6 +149,24 @@ export function createFilterStructure(
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
active: opts.collections.active
|
active: opts.collections.active
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...createAutocompleteField(
|
||||||
|
ProductFilterKeys.productType,
|
||||||
|
intl.formatMessage(sectionNames.productTypes),
|
||||||
|
opts.productType.value,
|
||||||
|
opts.productType.displayValues,
|
||||||
|
true,
|
||||||
|
opts.productType.choices,
|
||||||
|
{
|
||||||
|
hasMore: opts.productType.hasMore,
|
||||||
|
initialSearch: "",
|
||||||
|
loading: opts.productType.loading,
|
||||||
|
onFetchMore: opts.productType.onFetchMore,
|
||||||
|
onSearchChange: opts.productType.onSearchChange
|
||||||
|
}
|
||||||
|
),
|
||||||
|
active: opts.productType.active
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,8 +215,12 @@ export const fragmentVariant = gql`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const initialProductFilterDataQuery = gql`
|
const initialProductFilterDataQuery = gql`
|
||||||
query InitialProductFilterData($categories: [ID!], $collections: [ID!]) {
|
query InitialProductFilterData(
|
||||||
categories(first: 20, filter: { ids: $categories }) {
|
$categories: [ID!]
|
||||||
|
$collections: [ID!]
|
||||||
|
$productTypes: [ID!]
|
||||||
|
) {
|
||||||
|
categories(first: 100, filter: { ids: $categories }) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
|
@ -224,7 +228,15 @@ const initialProductFilterDataQuery = gql`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collections(first: 20, filter: { ids: $collections }) {
|
collections(first: 100, filter: { ids: $collections }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
productTypes(first: 100, filter: { ids: $productTypes }) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
|
|
|
@ -38,12 +38,30 @@ export interface InitialProductFilterData_collections {
|
||||||
edges: InitialProductFilterData_collections_edges[];
|
edges: InitialProductFilterData_collections_edges[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InitialProductFilterData_productTypes_edges_node {
|
||||||
|
__typename: "ProductType";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InitialProductFilterData_productTypes_edges {
|
||||||
|
__typename: "ProductTypeCountableEdge";
|
||||||
|
node: InitialProductFilterData_productTypes_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InitialProductFilterData_productTypes {
|
||||||
|
__typename: "ProductTypeCountableConnection";
|
||||||
|
edges: InitialProductFilterData_productTypes_edges[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface InitialProductFilterData {
|
export interface InitialProductFilterData {
|
||||||
categories: InitialProductFilterData_categories | null;
|
categories: InitialProductFilterData_categories | null;
|
||||||
collections: InitialProductFilterData_collections | null;
|
collections: InitialProductFilterData_collections | null;
|
||||||
|
productTypes: InitialProductFilterData_productTypes | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InitialProductFilterDataVariables {
|
export interface InitialProductFilterDataVariables {
|
||||||
categories?: string[] | null;
|
categories?: string[] | null;
|
||||||
collections?: string[] | null;
|
collections?: string[] | null;
|
||||||
|
productTypes?: string[] | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ export enum ProductListUrlFiltersEnum {
|
||||||
}
|
}
|
||||||
export enum ProductListUrlFiltersWithMultipleValues {
|
export enum ProductListUrlFiltersWithMultipleValues {
|
||||||
categories = "categories",
|
categories = "categories",
|
||||||
collections = "collections"
|
collections = "collections",
|
||||||
|
productTypes = "productTypes"
|
||||||
}
|
}
|
||||||
export type ProductListUrlFilters = Filters<ProductListUrlFiltersEnum> &
|
export type ProductListUrlFilters = Filters<ProductListUrlFiltersEnum> &
|
||||||
FiltersWithMultipleValues<ProductListUrlFiltersWithMultipleValues>;
|
FiltersWithMultipleValues<ProductListUrlFiltersWithMultipleValues>;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandl
|
||||||
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
|
import createFilterHandlers from "@saleor/utils/handlers/filterHandlers";
|
||||||
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
import useCategorySearch from "@saleor/searches/useCategorySearch";
|
||||||
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
import useCollectionSearch from "@saleor/searches/useCollectionSearch";
|
||||||
|
import useProductTypeSearch from "@saleor/searches/useProductTypeSearch";
|
||||||
import ProductListPage from "../../components/ProductListPage";
|
import ProductListPage from "../../components/ProductListPage";
|
||||||
import {
|
import {
|
||||||
TypedProductBulkDeleteMutation,
|
TypedProductBulkDeleteMutation,
|
||||||
|
@ -81,17 +82,34 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { data: initialFilterData } = useInitialProductFilterDataQuery({
|
const { data: initialFilterData } = useInitialProductFilterDataQuery({
|
||||||
skip: !(!!params.categories || !!params.collections),
|
skip: !(
|
||||||
|
!!params.categories ||
|
||||||
|
!!params.collections ||
|
||||||
|
!!params.productTypes
|
||||||
|
),
|
||||||
variables: {
|
variables: {
|
||||||
categories: params.categories,
|
categories: params.categories,
|
||||||
collections: params.collections
|
collections: params.collections,
|
||||||
|
productTypes: params.productTypes
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const searchCategories = useCategorySearch({
|
const searchCategories = useCategorySearch({
|
||||||
variables: DEFAULT_INITIAL_SEARCH_DATA
|
variables: {
|
||||||
|
...DEFAULT_INITIAL_SEARCH_DATA,
|
||||||
|
first: 5
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const searchCollections = useCollectionSearch({
|
const searchCollections = useCollectionSearch({
|
||||||
variables: DEFAULT_INITIAL_SEARCH_DATA
|
variables: {
|
||||||
|
...DEFAULT_INITIAL_SEARCH_DATA,
|
||||||
|
first: 5
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const searchProductTypes = useProductTypeSearch({
|
||||||
|
variables: {
|
||||||
|
...DEFAULT_INITIAL_SEARCH_DATA,
|
||||||
|
first: 5
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
|
@ -191,6 +209,13 @@ export const ProductList: React.FC<ProductListProps> = ({ params }) => {
|
||||||
[]
|
[]
|
||||||
),
|
),
|
||||||
search: searchCollections
|
search: searchCollections
|
||||||
|
},
|
||||||
|
{
|
||||||
|
initial: maybe(
|
||||||
|
() => initialFilterData.productTypes.edges.map(edge => edge.node),
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
search: searchProductTypes
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,17 @@ import {
|
||||||
} from "@saleor/searches/types/SearchCategories";
|
} from "@saleor/searches/types/SearchCategories";
|
||||||
import {
|
import {
|
||||||
InitialProductFilterData_categories_edges_node,
|
InitialProductFilterData_categories_edges_node,
|
||||||
InitialProductFilterData_collections_edges_node
|
InitialProductFilterData_collections_edges_node,
|
||||||
|
InitialProductFilterData_productTypes_edges_node
|
||||||
} from "@saleor/products/types/InitialProductFilterData";
|
} from "@saleor/products/types/InitialProductFilterData";
|
||||||
import {
|
import {
|
||||||
SearchCollections,
|
SearchCollections,
|
||||||
SearchCollectionsVariables
|
SearchCollectionsVariables
|
||||||
} from "@saleor/searches/types/SearchCollections";
|
} from "@saleor/searches/types/SearchCollections";
|
||||||
|
import {
|
||||||
|
SearchProductTypes,
|
||||||
|
SearchProductTypesVariables
|
||||||
|
} from "@saleor/searches/types/SearchProductTypes";
|
||||||
import { IFilterElement } from "../../../components/Filter";
|
import { IFilterElement } from "../../../components/Filter";
|
||||||
import {
|
import {
|
||||||
ProductFilterInput,
|
ProductFilterInput,
|
||||||
|
@ -29,7 +34,8 @@ import {
|
||||||
getMinMaxQueryParam,
|
getMinMaxQueryParam,
|
||||||
getSingleEnumValueQueryParam,
|
getSingleEnumValueQueryParam,
|
||||||
dedupeFilter,
|
dedupeFilter,
|
||||||
getMultipleValueQueryParam
|
getMultipleValueQueryParam,
|
||||||
|
getSingleValueQueryParam
|
||||||
} from "../../../utils/filters";
|
} from "../../../utils/filters";
|
||||||
import {
|
import {
|
||||||
ProductListUrlFilters,
|
ProductListUrlFilters,
|
||||||
|
@ -49,6 +55,10 @@ export function getFilterOpts(
|
||||||
collections: {
|
collections: {
|
||||||
initial: InitialProductFilterData_collections_edges_node[];
|
initial: InitialProductFilterData_collections_edges_node[];
|
||||||
search: UseSearchResult<SearchCollections, SearchCollectionsVariables>;
|
search: UseSearchResult<SearchCollections, SearchCollectionsVariables>;
|
||||||
|
},
|
||||||
|
productTypes: {
|
||||||
|
initial: InitialProductFilterData_productTypes_edges_node[];
|
||||||
|
search: UseSearchResult<SearchProductTypes, SearchProductTypesVariables>;
|
||||||
}
|
}
|
||||||
): ProductListFilterOpts {
|
): ProductListFilterOpts {
|
||||||
return {
|
return {
|
||||||
|
@ -62,14 +72,16 @@ export function getFilterOpts(
|
||||||
})),
|
})),
|
||||||
[]
|
[]
|
||||||
),
|
),
|
||||||
displayValues: maybe(
|
displayValues: !!params.categories
|
||||||
|
? maybe(
|
||||||
() =>
|
() =>
|
||||||
categories.initial.map(category => ({
|
categories.initial.map(category => ({
|
||||||
label: category.name,
|
label: category.name,
|
||||||
value: category.id
|
value: category.id
|
||||||
})),
|
})),
|
||||||
[]
|
[]
|
||||||
),
|
)
|
||||||
|
: [],
|
||||||
hasMore: maybe(
|
hasMore: maybe(
|
||||||
() => categories.search.result.data.search.pageInfo.hasNextPage,
|
() => categories.search.result.data.search.pageInfo.hasNextPage,
|
||||||
false
|
false
|
||||||
|
@ -90,14 +102,16 @@ export function getFilterOpts(
|
||||||
})),
|
})),
|
||||||
[]
|
[]
|
||||||
),
|
),
|
||||||
displayValues: maybe(
|
displayValues: !!params.collections
|
||||||
|
? maybe(
|
||||||
() =>
|
() =>
|
||||||
collections.initial.map(category => ({
|
collections.initial.map(category => ({
|
||||||
label: category.name,
|
label: category.name,
|
||||||
value: category.id
|
value: category.id
|
||||||
})),
|
})),
|
||||||
[]
|
[]
|
||||||
),
|
)
|
||||||
|
: undefined,
|
||||||
hasMore: maybe(
|
hasMore: maybe(
|
||||||
() => collections.search.result.data.search.pageInfo.hasNextPage,
|
() => collections.search.result.data.search.pageInfo.hasNextPage,
|
||||||
false
|
false
|
||||||
|
@ -119,6 +133,36 @@ export function getFilterOpts(
|
||||||
min: maybe(() => params.priceFrom, "0")
|
min: maybe(() => params.priceFrom, "0")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
productType: {
|
||||||
|
active: !!params.productTypes,
|
||||||
|
choices: maybe(
|
||||||
|
() =>
|
||||||
|
productTypes.search.result.data.search.edges.map(edge => ({
|
||||||
|
label: edge.node.name,
|
||||||
|
value: edge.node.id
|
||||||
|
})),
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
displayValues: !!params.productTypes
|
||||||
|
? maybe(
|
||||||
|
() =>
|
||||||
|
productTypes.initial.map(productType => ({
|
||||||
|
label: productType.name,
|
||||||
|
value: productType.id
|
||||||
|
})),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
: [],
|
||||||
|
hasMore: maybe(
|
||||||
|
() => productTypes.search.result.data.search.pageInfo.hasNextPage,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
initialSearch: "",
|
||||||
|
loading: productTypes.search.result.loading,
|
||||||
|
onFetchMore: productTypes.search.loadMore,
|
||||||
|
onSearchChange: productTypes.search.search,
|
||||||
|
value: maybe(() => dedupeFilter(params.productTypes), [])
|
||||||
|
},
|
||||||
status: {
|
status: {
|
||||||
active: maybe(() => params.status !== undefined, false),
|
active: maybe(() => params.status !== undefined, false),
|
||||||
value: maybe(() => findValueInEnum(params.status, ProductStatus))
|
value: maybe(() => findValueInEnum(params.status, ProductStatus))
|
||||||
|
@ -144,6 +188,8 @@ export function getFilterVariables(
|
||||||
gte: parseFloat(params.priceFrom),
|
gte: parseFloat(params.priceFrom),
|
||||||
lte: parseFloat(params.priceTo)
|
lte: parseFloat(params.priceTo)
|
||||||
}),
|
}),
|
||||||
|
productType:
|
||||||
|
params.productTypes !== undefined ? params.productTypes[0] : null,
|
||||||
search: params.query,
|
search: params.query,
|
||||||
stockAvailability:
|
stockAvailability:
|
||||||
params.stockStatus !== undefined
|
params.stockStatus !== undefined
|
||||||
|
@ -177,6 +223,12 @@ export function getFilterQueryParam(
|
||||||
ProductListUrlFiltersEnum.priceTo
|
ProductListUrlFiltersEnum.priceTo
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case ProductFilterKeys.productType:
|
||||||
|
return getMultipleValueQueryParam(
|
||||||
|
filter,
|
||||||
|
ProductListUrlFiltersWithMultipleValues.productTypes
|
||||||
|
);
|
||||||
|
|
||||||
case ProductFilterKeys.status:
|
case ProductFilterKeys.status:
|
||||||
return getSingleEnumValueQueryParam(
|
return getSingleEnumValueQueryParam(
|
||||||
filter,
|
filter,
|
||||||
|
|
Loading…
Reference in a new issue