From 97e4401897354a9c842339d13b90fe3fe77106fb Mon Sep 17 00:00:00 2001 From: Patryk Andrzejewski Date: Wed, 5 Jul 2023 13:28:46 +0200 Subject: [PATCH] Implement url management, clan up UrlEntry (#3858) * UrlEntry clean up, fix types * Changeset --- .changeset/nasty-papayas-brake.md | 5 ++ package-lock.json | 6 +- .../ConditionalFilter/API/Handler.ts | 3 +- .../API/InitialStateResponse.ts | 2 +- .../FilterElement/ConditionSelected.ts | 14 +--- .../FilterElement/ConditionValue.ts | 25 ++++++ .../FilterElement/FilterElement.ts | 46 ++--------- .../ValueProvider/TokenArray/index.ts | 6 +- .../ValueProvider/UrlToken.ts | 78 +++++++++++++++---- .../ConditionalFilter/controlsType.ts | 3 +- src/components/ConditionalFilter/index.tsx | 2 +- .../ConditionalFilter/useFilterContainer.ts | 2 +- 12 files changed, 113 insertions(+), 79 deletions(-) create mode 100644 .changeset/nasty-papayas-brake.md create mode 100644 src/components/ConditionalFilter/FilterElement/ConditionValue.ts diff --git a/.changeset/nasty-papayas-brake.md b/.changeset/nasty-papayas-brake.md new file mode 100644 index 000000000..513c582f7 --- /dev/null +++ b/.changeset/nasty-papayas-brake.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": minor +--- + +Implement url management for filters, clean up types diff --git a/package-lock.json b/package-lock.json index f081a1428..ac858b30e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20767,8 +20767,8 @@ }, "node_modules/extend": { "version": "3.0.2", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/extend-shallow": { "version": "3.0.2", @@ -50194,7 +50194,7 @@ }, "extend": { "version": "3.0.2", - "optional": true + "devOptional": true }, "extend-shallow": { "version": "3.0.2", diff --git a/src/components/ConditionalFilter/API/Handler.ts b/src/components/ConditionalFilter/API/Handler.ts index fefba6597..903277a5c 100644 --- a/src/components/ConditionalFilter/API/Handler.ts +++ b/src/components/ConditionalFilter/API/Handler.ts @@ -20,7 +20,8 @@ import { _GetProductTypesChoicesQueryVariables, } from "@dashboard/graphql"; -import { ItemOption } from "../FilterElement/ConditionSelected"; +import { ItemOption } from "../FilterElement/ConditionValue"; + export interface Handler { client: ApolloClient; diff --git a/src/components/ConditionalFilter/API/InitialStateResponse.ts b/src/components/ConditionalFilter/API/InitialStateResponse.ts index 1f24cb4f4..db29e9ece 100644 --- a/src/components/ConditionalFilter/API/InitialStateResponse.ts +++ b/src/components/ConditionalFilter/API/InitialStateResponse.ts @@ -1,5 +1,5 @@ import { AttributeInputType } from "../FilterElement/ConditionOptions"; -import { ItemOption } from "../FilterElement/ConditionSelected"; +import { ItemOption } from "../FilterElement/ConditionValue"; import { UrlToken } from "../ValueProvider/UrlToken"; interface AttributeDTO { diff --git a/src/components/ConditionalFilter/FilterElement/ConditionSelected.ts b/src/components/ConditionalFilter/FilterElement/ConditionSelected.ts index 7b6e02706..ceb047b71 100644 --- a/src/components/ConditionalFilter/FilterElement/ConditionSelected.ts +++ b/src/components/ConditionalFilter/FilterElement/ConditionSelected.ts @@ -1,18 +1,6 @@ import { getDefaultByControlName } from "../controlsType"; import { ConditionItem } from "./ConditionOptions"; - -export interface ItemOption { - label: string; - value: string; - slug: string; -} - -export type ConditionValue = - | ItemOption - | ItemOption[] - | string - | string[] - | [string, string]; +import { ConditionValue } from "./ConditionValue"; export class ConditionSelected { diff --git a/src/components/ConditionalFilter/FilterElement/ConditionValue.ts b/src/components/ConditionalFilter/FilterElement/ConditionValue.ts new file mode 100644 index 000000000..bbdf46a5f --- /dev/null +++ b/src/components/ConditionalFilter/FilterElement/ConditionValue.ts @@ -0,0 +1,25 @@ +export interface ItemOption { + label: string; + value: string; + slug: string; +} + +export type ConditionValue = + | ItemOption + | ItemOption[] + | string + | string[] + | [string, string]; + + +export const slugFromConditionValue = (rawEntry: ConditionValue): string | string[] => { + if (typeof rawEntry === "string") { + return rawEntry; + } + + if (Array.isArray(rawEntry)) { + return rawEntry.map(el => (typeof el === "string" ? el : el.slug)); + } + + return rawEntry.slug; +}; \ No newline at end of file diff --git a/src/components/ConditionalFilter/FilterElement/FilterElement.ts b/src/components/ConditionalFilter/FilterElement/FilterElement.ts index ee40bfa15..18ae0d176 100644 --- a/src/components/ConditionalFilter/FilterElement/FilterElement.ts +++ b/src/components/ConditionalFilter/FilterElement/FilterElement.ts @@ -1,10 +1,11 @@ /* eslint-disable @typescript-eslint/member-ordering */ import { InitialStateResponse } from "../API/InitialStateResponse"; import { LeftOperand } from "./../useLeftOperands"; -import { CONDITIONS, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken"; +import { UrlEntry, UrlToken } from "./../ValueProvider/UrlToken"; import { Condition } from "./Condition"; import { ConditionItem, ConditionOptions } from "./ConditionOptions"; -import { ConditionSelected, ConditionValue, ItemOption } from "./ConditionSelected"; +import { ConditionSelected } from "./ConditionSelected"; +import { ConditionValue, ItemOption } from "./ConditionValue"; interface ExpressionValue { value: string; @@ -12,30 +13,6 @@ interface ExpressionValue { type: string; } -const createStaticEntry = (rawEntry: ConditionValue) => { - if (typeof rawEntry === "string") { - return rawEntry; - } - - if (Array.isArray(rawEntry)) { - return rawEntry.map(el => (typeof el === "string" ? el : el.slug)); - } - - return rawEntry.slug; -}; - -const createAttributeEntry = (rawEntry: ConditionValue) => { - if (typeof rawEntry === "string") { - return rawEntry; - } - - if (Array.isArray(rawEntry)) { - return rawEntry.map(el => (typeof el === "string" ? el : el.slug)); - } - - return rawEntry.slug; -}; - export class FilterElement { private constructor( public value: ExpressionValue, @@ -119,24 +96,11 @@ export class FilterElement { } public asUrlEntry(): UrlEntry { - const { conditionValue } = this.condition.selected; - const conditionIndex = CONDITIONS.findIndex( - el => conditionValue && el === conditionValue.label, - ); - if (this.isAttribute()) { - return { - [`a${conditionIndex}.${this.value.value}`]: createAttributeEntry( - this.condition.selected.value, - ), - }; + return UrlEntry.forAttribute(this.condition.selected, this.value.value) } - return { - [`s${conditionIndex}.${this.value.value}`]: createStaticEntry( - this.condition.selected.value, - ), - }; + return UrlEntry.forStatic(this.condition.selected, this.value.value) } public static fromValueEntry(valueEntry: any) { diff --git a/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts b/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts index 8aff39860..cc03facc2 100644 --- a/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts +++ b/src/components/ConditionalFilter/ValueProvider/TokenArray/index.ts @@ -6,7 +6,7 @@ import { useRef } from "react"; import { InitialStateResponse } from "../../API/InitialStateResponse"; import { FilterElement } from "../../FilterElement"; import { FilterContainer } from "../../useFilterContainer"; -import { UrlToken } from "../UrlToken"; +import { UrlEntry, UrlToken } from "../UrlToken"; import { emptyFetchingParams, FetchingParams, @@ -38,7 +38,9 @@ const mapToTokens = (urlEntries: Array): TokenArray => return mapToTokens(entry); } - return UrlToken.fromUrlEntry(entry); + return UrlToken.fromUrlEntry( + UrlEntry.fromQs(entry) + ); }) as TokenArray; const tokenizeUrl = (urlParams: string) => { diff --git a/src/components/ConditionalFilter/ValueProvider/UrlToken.ts b/src/components/ConditionalFilter/ValueProvider/UrlToken.ts index b7e3ad207..0294e39c7 100644 --- a/src/components/ConditionalFilter/ValueProvider/UrlToken.ts +++ b/src/components/ConditionalFilter/ValueProvider/UrlToken.ts @@ -1,46 +1,94 @@ -// @ts-strict-ignore +import { ParsedQs } from "qs"; + +import { ConditionSelected } from "../FilterElement/ConditionSelected"; +import { slugFromConditionValue } from "../FilterElement/ConditionValue"; export const CONDITIONS = ["is", "equals", "in", "between", "lower", "greater"]; const STATIC_TO_LOAD = ["category", "collection", "channel", "producttype"]; -type TokenType = "a" | "s"; +export const TokenType = { + ATTRIBUTE: "a", + STATIC: "s" +} as const + +export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType] -// export type UrlEntry = Record -// eslint-disable-next-line @typescript-eslint/no-extraneous-class export class UrlEntry { constructor(key: string, value: string | string[]) { - this[key] = value; + (this as unknown as Record)[key] = value; } + public static fromQs(entry: ParsedQs) { + const key = Object.keys(entry)[0] + const value = entry[key] as string | string[] + + return new UrlEntry(key, value) + } + + public static forAttribute (condition: ConditionSelected, paramName: string) { + return UrlEntry.fromConditionSelected(condition, paramName, TokenType.ATTRIBUTE) + } + + public static forStatic (condition: ConditionSelected, paramName: string) { + return UrlEntry.fromConditionSelected(condition, paramName, TokenType.STATIC) + } + + public getInfo () { + const [key, value] = Object.entries(this)[0] as [ + string, + string | string[], + ]; + const [identifier, entryName] = key.split("."); + const [type, control] = identifier.split("") as [TokenTypeValue, number]; + const conditionKid = CONDITIONS[control] + + return { key, value, entryName, type, conditionKid } + } + + private static fromConditionSelected ( + condition: ConditionSelected, + paramName: string, + tokenSlug: TokenTypeValue + ) { + const { conditionValue } = condition; + const conditionIndex = CONDITIONS.findIndex( + el => conditionValue && el === conditionValue.label, + ); + + return new UrlEntry( + `${tokenSlug}${conditionIndex}.${paramName}`, + slugFromConditionValue(condition.value) + ) + } } export class UrlToken { private constructor( public name: string, public value: string | string[], - public type: TokenType, + public type: TokenTypeValue, public conditionKind: string, ) {} public static fromUrlEntry(entry: UrlEntry) { - const [key, value] = Object.entries(entry)[0] as [ - string, - string | string[], - ]; - const [identifier, entryName] = key.split("."); - const [type, control] = identifier.split("") as [TokenType, string]; + const { + entryName, + value, + type, + conditionKid + } = entry.getInfo() - return new UrlToken(entryName, value, type, CONDITIONS[control]); + return new UrlToken(entryName, value, type, conditionKid); } public isStatic() { - return this.type === "s"; + return this.type === TokenType.STATIC; } public isAttribute() { - return this.type === "a"; + return this.type === TokenType.ATTRIBUTE; } public isLoadable() { diff --git a/src/components/ConditionalFilter/controlsType.ts b/src/components/ConditionalFilter/controlsType.ts index 7f56e4fa3..76e064197 100644 --- a/src/components/ConditionalFilter/controlsType.ts +++ b/src/components/ConditionalFilter/controlsType.ts @@ -1,5 +1,6 @@ // @ts-strict-ignore -import { ConditionValue } from "./FilterElement/ConditionSelected"; + +import { ConditionValue } from "./FilterElement/ConditionValue"; export const CONTROL_DEFAULTS = { text: "", diff --git a/src/components/ConditionalFilter/index.tsx b/src/components/ConditionalFilter/index.tsx index 68e85128b..4b7dccfab 100644 --- a/src/components/ConditionalFilter/index.tsx +++ b/src/components/ConditionalFilter/index.tsx @@ -9,7 +9,7 @@ import { getLeftOperatorOptions, getRightOperatorOptionsByQuery, } from "./API/getAPIOptions"; -import { ConditionValue } from "./FilterElement/ConditionSelected"; +import { ConditionValue } from "./FilterElement/ConditionValue"; import { useFilterContainer } from "./useFilterContainer"; import { useLeftOperands } from "./useLeftOperands"; import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider"; diff --git a/src/components/ConditionalFilter/useFilterContainer.ts b/src/components/ConditionalFilter/useFilterContainer.ts index 7b3847f8d..f93a90868 100644 --- a/src/components/ConditionalFilter/useFilterContainer.ts +++ b/src/components/ConditionalFilter/useFilterContainer.ts @@ -2,7 +2,7 @@ import { useState } from "react"; import { FilterElement } from "./FilterElement"; -import { ConditionValue, ItemOption } from "./FilterElement/ConditionSelected"; +import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue"; export type FilterContainer = Array;