Implement url management, clan up UrlEntry (#3858)
* UrlEntry clean up, fix types * Changeset
This commit is contained in:
parent
e37c8ce44c
commit
97e4401897
12 changed files with 113 additions and 79 deletions
5
.changeset/nasty-papayas-brake.md
Normal file
5
.changeset/nasty-papayas-brake.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-dashboard": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Implement url management for filters, clean up types
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -20767,8 +20767,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/extend": {
|
"node_modules/extend": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"license": "MIT",
|
"devOptional": true,
|
||||||
"optional": true
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/extend-shallow": {
|
"node_modules/extend-shallow": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
@ -50194,7 +50194,7 @@
|
||||||
},
|
},
|
||||||
"extend": {
|
"extend": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"optional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"extend-shallow": {
|
"extend-shallow": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
|
|
@ -20,7 +20,8 @@ import {
|
||||||
_GetProductTypesChoicesQueryVariables,
|
_GetProductTypesChoicesQueryVariables,
|
||||||
} from "@dashboard/graphql";
|
} from "@dashboard/graphql";
|
||||||
|
|
||||||
import { ItemOption } from "../FilterElement/ConditionSelected";
|
import { ItemOption } from "../FilterElement/ConditionValue";
|
||||||
|
|
||||||
|
|
||||||
export interface Handler {
|
export interface Handler {
|
||||||
client: ApolloClient<unknown>;
|
client: ApolloClient<unknown>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AttributeInputType } from "../FilterElement/ConditionOptions";
|
import { AttributeInputType } from "../FilterElement/ConditionOptions";
|
||||||
import { ItemOption } from "../FilterElement/ConditionSelected";
|
import { ItemOption } from "../FilterElement/ConditionValue";
|
||||||
import { UrlToken } from "../ValueProvider/UrlToken";
|
import { UrlToken } from "../ValueProvider/UrlToken";
|
||||||
|
|
||||||
interface AttributeDTO {
|
interface AttributeDTO {
|
||||||
|
|
|
@ -1,18 +1,6 @@
|
||||||
import { getDefaultByControlName } from "../controlsType";
|
import { getDefaultByControlName } from "../controlsType";
|
||||||
import { ConditionItem } from "./ConditionOptions";
|
import { ConditionItem } from "./ConditionOptions";
|
||||||
|
import { ConditionValue } from "./ConditionValue";
|
||||||
export interface ItemOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
slug: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ConditionValue =
|
|
||||||
| ItemOption
|
|
||||||
| ItemOption[]
|
|
||||||
| string
|
|
||||||
| string[]
|
|
||||||
| [string, string];
|
|
||||||
|
|
||||||
|
|
||||||
export class ConditionSelected {
|
export class ConditionSelected {
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
|
@ -1,10 +1,11 @@
|
||||||
/* eslint-disable @typescript-eslint/member-ordering */
|
/* eslint-disable @typescript-eslint/member-ordering */
|
||||||
import { InitialStateResponse } from "../API/InitialStateResponse";
|
import { InitialStateResponse } from "../API/InitialStateResponse";
|
||||||
import { LeftOperand } from "./../useLeftOperands";
|
import { LeftOperand } from "./../useLeftOperands";
|
||||||
import { CONDITIONS, UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
|
import { UrlEntry, UrlToken } from "./../ValueProvider/UrlToken";
|
||||||
import { Condition } from "./Condition";
|
import { Condition } from "./Condition";
|
||||||
import { ConditionItem, ConditionOptions } from "./ConditionOptions";
|
import { ConditionItem, ConditionOptions } from "./ConditionOptions";
|
||||||
import { ConditionSelected, ConditionValue, ItemOption } from "./ConditionSelected";
|
import { ConditionSelected } from "./ConditionSelected";
|
||||||
|
import { ConditionValue, ItemOption } from "./ConditionValue";
|
||||||
|
|
||||||
interface ExpressionValue {
|
interface ExpressionValue {
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -12,30 +13,6 @@ interface ExpressionValue {
|
||||||
type: string;
|
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 {
|
export class FilterElement {
|
||||||
private constructor(
|
private constructor(
|
||||||
public value: ExpressionValue,
|
public value: ExpressionValue,
|
||||||
|
@ -119,24 +96,11 @@ export class FilterElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public asUrlEntry(): UrlEntry {
|
public asUrlEntry(): UrlEntry {
|
||||||
const { conditionValue } = this.condition.selected;
|
|
||||||
const conditionIndex = CONDITIONS.findIndex(
|
|
||||||
el => conditionValue && el === conditionValue.label,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.isAttribute()) {
|
if (this.isAttribute()) {
|
||||||
return {
|
return UrlEntry.forAttribute(this.condition.selected, this.value.value)
|
||||||
[`a${conditionIndex}.${this.value.value}`]: createAttributeEntry(
|
|
||||||
this.condition.selected.value,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return UrlEntry.forStatic(this.condition.selected, this.value.value)
|
||||||
[`s${conditionIndex}.${this.value.value}`]: createStaticEntry(
|
|
||||||
this.condition.selected.value,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromValueEntry(valueEntry: any) {
|
public static fromValueEntry(valueEntry: any) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useRef } from "react";
|
||||||
import { InitialStateResponse } from "../../API/InitialStateResponse";
|
import { InitialStateResponse } from "../../API/InitialStateResponse";
|
||||||
import { FilterElement } from "../../FilterElement";
|
import { FilterElement } from "../../FilterElement";
|
||||||
import { FilterContainer } from "../../useFilterContainer";
|
import { FilterContainer } from "../../useFilterContainer";
|
||||||
import { UrlToken } from "../UrlToken";
|
import { UrlEntry, UrlToken } from "../UrlToken";
|
||||||
import {
|
import {
|
||||||
emptyFetchingParams,
|
emptyFetchingParams,
|
||||||
FetchingParams,
|
FetchingParams,
|
||||||
|
@ -38,7 +38,9 @@ const mapToTokens = (urlEntries: Array<ParsedQs | string>): TokenArray =>
|
||||||
return mapToTokens(entry);
|
return mapToTokens(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UrlToken.fromUrlEntry(entry);
|
return UrlToken.fromUrlEntry(
|
||||||
|
UrlEntry.fromQs(entry)
|
||||||
|
);
|
||||||
}) as TokenArray;
|
}) as TokenArray;
|
||||||
|
|
||||||
const tokenizeUrl = (urlParams: string) => {
|
const tokenizeUrl = (urlParams: string) => {
|
||||||
|
|
|
@ -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"];
|
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"];
|
||||||
|
|
||||||
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<string, string | string[]>
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
||||||
export class UrlEntry {
|
export class UrlEntry {
|
||||||
constructor(key: string, value: string | string[]) {
|
constructor(key: string, value: string | string[]) {
|
||||||
this[key] = value;
|
(this as unknown as Record<string, string | string[]>)[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 {
|
export class UrlToken {
|
||||||
private constructor(
|
private constructor(
|
||||||
public name: string,
|
public name: string,
|
||||||
public value: string | string[],
|
public value: string | string[],
|
||||||
public type: TokenType,
|
public type: TokenTypeValue,
|
||||||
public conditionKind: string,
|
public conditionKind: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public static fromUrlEntry(entry: UrlEntry) {
|
public static fromUrlEntry(entry: UrlEntry) {
|
||||||
const [key, value] = Object.entries(entry)[0] as [
|
const {
|
||||||
string,
|
entryName,
|
||||||
string | string[],
|
value,
|
||||||
];
|
type,
|
||||||
const [identifier, entryName] = key.split(".");
|
conditionKid
|
||||||
const [type, control] = identifier.split("") as [TokenType, string];
|
} = entry.getInfo()
|
||||||
|
|
||||||
return new UrlToken(entryName, value, type, CONDITIONS[control]);
|
return new UrlToken(entryName, value, type, conditionKid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isStatic() {
|
public isStatic() {
|
||||||
return this.type === "s";
|
return this.type === TokenType.STATIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAttribute() {
|
public isAttribute() {
|
||||||
return this.type === "a";
|
return this.type === TokenType.ATTRIBUTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isLoadable() {
|
public isLoadable() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { ConditionValue } from "./FilterElement/ConditionSelected";
|
|
||||||
|
import { ConditionValue } from "./FilterElement/ConditionValue";
|
||||||
|
|
||||||
export const CONTROL_DEFAULTS = {
|
export const CONTROL_DEFAULTS = {
|
||||||
text: "",
|
text: "",
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
getLeftOperatorOptions,
|
getLeftOperatorOptions,
|
||||||
getRightOperatorOptionsByQuery,
|
getRightOperatorOptionsByQuery,
|
||||||
} from "./API/getAPIOptions";
|
} from "./API/getAPIOptions";
|
||||||
import { ConditionValue } from "./FilterElement/ConditionSelected";
|
import { ConditionValue } from "./FilterElement/ConditionValue";
|
||||||
import { useFilterContainer } from "./useFilterContainer";
|
import { useFilterContainer } from "./useFilterContainer";
|
||||||
import { useLeftOperands } from "./useLeftOperands";
|
import { useLeftOperands } from "./useLeftOperands";
|
||||||
import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider";
|
import { useUrlValueProvider } from "./ValueProvider/useUrlValueProvider";
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { FilterElement } from "./FilterElement";
|
import { FilterElement } from "./FilterElement";
|
||||||
import { ConditionValue, ItemOption } from "./FilterElement/ConditionSelected";
|
import { ConditionValue, ItemOption } from "./FilterElement/ConditionValue";
|
||||||
|
|
||||||
export type FilterContainer = Array<string | FilterElement | FilterContainer>;
|
export type FilterContainer = Array<string | FilterElement | FilterContainer>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue