Add all static fields to be used in filtering products (#3912)

* Add all static fields

* Changeset

* Add all static fields

* Fix types

* Remove unused entries
This commit is contained in:
Patryk Andrzejewski 2023-07-14 15:27:44 +02:00 committed by GitHub
parent 423858e86f
commit a7d39d7f19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 173 additions and 53 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---
Add all static fields for product filtering

View file

@ -24,8 +24,6 @@ import { ItemOption } from "../FilterElement/ConditionValue";
import { LeftOperand } from "../LeftOperandsProvider";
export interface Handler {
client: ApolloClient<unknown>;
query: string;
fetch: () => Promise<ItemOption[]>;
}
@ -167,3 +165,11 @@ export class AttributesHandler implements Handler {
);
};
}
export class BooleanValuesHandler implements Handler {
constructor(public options: LeftOperand[]) {}
fetch = async (): Promise<LeftOperand[]> => {
return this.options
};
}

View file

@ -15,24 +15,34 @@ export interface InitialState {
attribute: Record<string, AttributeDTO>;
channel: ItemOption[];
collection: ItemOption[];
producttype: ItemOption[];
productType: ItemOption[];
isAvailable: ItemOption[];
isPublished: ItemOption[];
isVisibleInListing: ItemOption[];
hasCategory: ItemOption[];
giftCard: ItemOption[];
}
export class InitialStateResponse implements InitialState {
constructor(
public category: ItemOption[],
public attribute: Record<string, AttributeDTO>,
public channel: ItemOption[],
public collection: ItemOption[],
public producttype: ItemOption[],
) {}
public category: ItemOption[] = [],
public attribute: Record<string, AttributeDTO> = {},
public channel: ItemOption[] = [],
public collection: ItemOption[] = [],
public productType: ItemOption[] = [],
public isAvailable: ItemOption[] = [],
public isPublished: ItemOption[] = [],
public isVisibleInListing: ItemOption[] = [],
public hasCategory: ItemOption[] = [],
public giftCard: ItemOption[] = []
) { }
public attributeByName(name: string) {
return this.attribute[name];
}
public static empty() {
return new InitialStateResponse([], {}, [], [], []);
return new InitialStateResponse();
}
public filterByUrlToken(token: UrlToken) {
@ -57,10 +67,20 @@ export class InitialStateResponse implements InitialState {
return this.category;
case "collection":
return this.collection;
case "producttype":
return this.producttype;
case "productType":
return this.productType;
case "channel":
return this.channel;
case "isAvailable":
return this.isAvailable;
case "isPublished":
return this.isPublished;
case "isVisibleInListing":
return this.isVisibleInListing;
case "hasCategory":
return this.hasCategory;
case "giftCard":
return this.giftCard;
default:
return [];
}

View file

@ -1,10 +1,12 @@
import { ApolloClient, useApolloClient } from "@apollo/client";
import { RowType } from "../constants";
import { FilterContainer, FilterElement } from "../FilterElement";
import { FilterAPIProvider } from "./FilterAPIProvider";
import {
AttributeChoicesHandler,
AttributesHandler,
BooleanValuesHandler,
CategoryHandler,
ChannelHandler,
CollectionHandler,
@ -27,12 +29,24 @@ const getFilterElement = (
throw new Error("Unknown filter element used to create API handler");
};
const isStaticBoolean = (rowType: RowType) => {
return [
"isAvailable",
"isPublished",
"isVisibleInListing",
"hasCategory",
"giftCard"
].includes(rowType)
}
const createAPIHandler = (
selectedRow: FilterElement,
client: ApolloClient<unknown>,
inputValue: string,
): Handler => {
if (selectedRow.isAttribute()) {
const rowType = selectedRow.rowType()
if (rowType === "attribute") {
return new AttributeChoicesHandler(
client,
selectedRow.value.value,
@ -40,19 +54,36 @@ const createAPIHandler = (
);
}
if (selectedRow.isCollection()) {
if (rowType && isStaticBoolean(rowType)) {
return new BooleanValuesHandler([
{
label: "Yes",
value: "true",
type: rowType,
slug: "true"
},
{
label: "No",
value: "false",
type: rowType,
slug: "false"
}
])
}
if (rowType === "collection") {
return new CollectionHandler(client, inputValue);
}
if (selectedRow.isCategory()) {
if (rowType === "category") {
return new CategoryHandler(client, inputValue);
}
if (selectedRow.isProductType()) {
if (rowType === "productType") {
return new ProductTypeHandler(client, inputValue);
}
if (selectedRow.isChannel()) {
if (rowType === "channel") {
return new ChannelHandler(client, inputValue);
}

View file

@ -7,6 +7,7 @@ import {
_SearchProductTypesOperandsQuery,
} from "@dashboard/graphql";
import { createBooleanOptions } from "../../constants";
import { createOptionsFromAPI } from "../Handler";
import { InitialState } from "../InitialStateResponse";
import { InitialAPIResponse } from "./types";
@ -70,7 +71,7 @@ export const createInitialStateFromData = (
if (isProductTypeQuery(query)) {
return {
...acc,
producttype: createOptionsFromAPI(
productType: createOptionsFromAPI(
query.data?.productTypes?.edges ?? [],
),
};
@ -102,7 +103,12 @@ export const createInitialStateFromData = (
channel: [],
collection: [],
category: [],
producttype: [],
productType: [],
isAvailable: createBooleanOptions(),
isPublished: createBooleanOptions(),
isVisibleInListing: createBooleanOptions(),
hasCategory: createBooleanOptions(),
giftCard: createBooleanOptions(),
attribute: {},
},
);

View file

@ -40,7 +40,7 @@ export const useProductInitialAPIState = (): InitialAPIState => {
const fetchQueries = async ({
category,
collection,
producttype,
productType,
channel,
attribute,
}: FetchingParams) => {
@ -85,7 +85,7 @@ export const useProductInitialAPIState = (): InitialAPIState => {
);
}
if (producttype.length > 0) {
if (productType.length > 0) {
queriesToRun.push(
client.query<
_SearchProductTypesOperandsQuery,
@ -93,8 +93,8 @@ export const useProductInitialAPIState = (): InitialAPIState => {
>({
query: _SearchProductTypesOperandsDocument,
variables: {
productTypesSlugs: producttype,
first: producttype.length,
productTypesSlugs: productType,
first: productType.length,
},
}),
);
@ -124,7 +124,12 @@ export const useProductInitialAPIState = (): InitialAPIState => {
initialState.attribute,
initialState.channel,
initialState.collection,
initialState.producttype,
initialState.productType,
initialState.isAvailable,
initialState.isPublished,
initialState.isVisibleInListing,
initialState.hasCategory,
initialState.giftCard
),
);
setLoading(false);

View file

@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { InitialStateResponse } from "../API/InitialStateResponse";
import { RowType, STATIC_OPTIONS } from "../constants";
import { LeftOperand } from "../LeftOperandsProvider";
import { TokenType, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
import { Condition } from "./Condition";
@ -23,9 +24,15 @@ class ExpressionValue {
}
public static fromUrlToken(token: UrlToken) {
const option = STATIC_OPTIONS.find(o => o.slug === token.name)
if (!option) {
return new ExpressionValue(token.name, token.name, token.name);
}
return new ExpressionValue(token.name, option.label, token.name);
}
public static forAttribute(
attributeName: string,
response: InitialStateResponse,
@ -106,23 +113,18 @@ export class FilterElement {
return ConditionOptions.isAttributeInputType(this.value.type);
}
public isCollection() {
return this.value.value === "collection";
public rowType (): RowType | null {
if (this.isStatic()) {
return this.value.value as RowType
}
public isCategory() {
return this.value.value === "category";
if (this.isAttribute()) {
return "attribute"
}
public isProductType() {
return this.value.value === "producttype";
return null;
}
public isChannel() {
return this.value.value === "channel";
}
public asUrlEntry(): UrlEntry {
if (this.isAttribute()) {
return UrlEntry.forAttribute(this.condition.selected, this.value.value);

View file

@ -4,7 +4,7 @@ export interface FetchingParams {
category: string[];
collection: string[];
channel: string[];
producttype: string[];
productType: string[];
attribute: Record<string, string[]>;
}
@ -14,7 +14,7 @@ export const emptyFetchingParams: FetchingParams = {
category: [],
collection: [],
channel: [],
producttype: [],
productType: [],
attribute: {},
};

View file

@ -5,7 +5,17 @@ import { slugFromConditionValue } from "../FilterElement/ConditionValue";
export const CONDITIONS = ["is", "equals", "in", "between", "lower", "greater"];
const STATIC_TO_LOAD = ["category", "collection", "channel", "producttype"];
const STATIC_TO_LOAD = [
"category",
"collection",
"channel",
"productType",
"isAvailable",
"isPublished",
"isVisibleInListing",
"hasCategory",
"giftCard"
];
export const TokenType = {
ATTRIBUTE: "a",

View file

@ -1,3 +1,6 @@
import { ItemOption } from "./FilterElement/ConditionValue";
import { LeftOperand } from "./LeftOperandsProvider";
export const STATIC_CONDITIONS = {
category: [
{ type: "combobox", label: "is", value: "input-1" },
@ -10,10 +13,36 @@ export const STATIC_CONDITIONS = {
{ type: "number.range", label: "between", value: "input-4" },
],
collection: [{ type: "multiselect", label: "in", value: "input-4" }],
producttype: [{ type: "multiselect", label: "in", value: "input-4" }],
channel: [{ type: "select", label: "is", value: "input-5" }],
productType: [
{ type: "combobox", label: "is", value: "input-1" },
{ type: "multiselect", label: "in", value: "input-2" }
],
isAvailable: [{ type: "select", label: "is", value: "input-1" }],
isPublished: [{ type: "select", label: "is", value: "input-1" }],
isVisibleInListing: [{ type: "select", label: "is", value: "input-1" }],
hasCategory: [{ type: "select", label: "is", value: "input-1" }],
giftCard: [{ type: "select", label: "is", value: "input-1" }],
};
export const STATIC_OPTIONS: LeftOperand[] = [
{ value: "price", label: "Price", type: "price", slug: "price" },
{ value: "category", label: "Category", type: "category", slug: "category" },
{
value: "collection",
label: "Collection",
type: "collection",
slug: "collection",
},
{ value: "channel", label: "Channel", type: "channel", slug: "channel" },
{ value: "productType", label: "Product Type", type: "productType", slug: "productType" },
{ value: "isAvailable", label: "Is available", type: "isAvailable", slug: "isAvailable" },
{ value: "isPublished", label: "Is published", type: "isPublished", slug: "isPublished" },
{ value: "isVisibleInListing", label: "Visible in listing", type: "isVisibleInListing", slug: "isVisibleInListing" },
{ value: "hasCategory", label: "Has category", type: "hasCategory", slug: "hasCategory" },
{ value: "giftCard", label: "Has giftcard", type: "giftCard", slug: "giftCard" },
];
export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
DROPDOWN: [{ type: "multiselect", label: "in", value: "input-2" }],
MULTISELECT: [{ type: "multiselect", label: "in", value: "input-2" }],
@ -28,3 +57,19 @@ export const ATTRIBUTE_INPUT_TYPE_CONDITIONS = {
DATE: [{ type: "date", label: "is", value: "input-1" }],
SWATCH: [{ type: "multiselect", label: "in", value: "input-2" }],
};
export type RowType = keyof typeof STATIC_CONDITIONS | "attribute"
export const createBooleanOptions = (): ItemOption[] => [
{
label: "Yes",
value: "true",
slug: "true"
},
{
label: "No",
value: "false",
slug: "false"
}
]

View file

@ -1,18 +1,8 @@
import { useState } from "react";
import { STATIC_OPTIONS } from "./constants";
import { LeftOperand, LeftOperandsProvider } from "./LeftOperandsProvider";
const STATIC_OPTIONS: LeftOperand[] = [
{ value: "price", label: "Price", type: "price", slug: "price" },
{ value: "category", label: "Category", type: "category", slug: "category" },
{
value: "collection",
label: "Collection",
type: "collection",
slug: "collection",
},
{ value: "channel", label: "Channel", type: "channel", slug: "channel" },
];
export const useFilterLeftOperandsProvider = (): LeftOperandsProvider => {
const [operands, setOperands] = useState<LeftOperand[]>(STATIC_OPTIONS);