From 264b8fd9b68b5a1f0889b7c6c2b55b0e10e6353c Mon Sep 17 00:00:00 2001 From: Artur Gunca Date: Wed, 23 Aug 2023 14:53:44 +0300 Subject: [PATCH] moved to API from editor --- .../src/Elements/filters/index.ts | 134 ++++++++++++++++++ public/editor-client/src/api/index.ts | 38 +++++ public/editor-client/src/config.ts | 8 +- public/editor-client/src/index.ts | 14 ++ public/editor-client/src/types/Filters.ts | 61 ++++++++ public/editor-client/src/types/global.d.ts | 9 ++ 6 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 public/editor-client/src/Elements/filters/index.ts create mode 100644 public/editor-client/src/types/Filters.ts diff --git a/public/editor-client/src/Elements/filters/index.ts b/public/editor-client/src/Elements/filters/index.ts new file mode 100644 index 0000000000..554333b32c --- /dev/null +++ b/public/editor-client/src/Elements/filters/index.ts @@ -0,0 +1,134 @@ +import { getFields } from "../../api"; +import { + Choice, + FilterFieldsData, + Filters, + PossibleValue, + QueryTypeSource +} from "../../types/Filters"; +import { t } from "../../utils/i18n"; + +export const handler: Filters["handler"] = async (res, rej, data) => { + try { + const result = await getFields(data); + + const convertedValue = converter(result); + + res(convertedValue ?? []); + } catch (e) { + rej(t("Failed to load sources")); + } +}; + +export const possibleValues: Filters["possibleValues"] = async ( + res, + rej, + { type, search, optionSource, postId, loopAttributes } +) => { + try { + const result = await getFields({ postId, loopAttributes }); + + const convertPossibleValues = parseFields( + result, + optionSource, + type, + search + ); + + res(convertPossibleValues ?? []); + } catch (e) { + rej(t("Failed to load sources")); + } +}; + +const createQueryTypeSource = ( + query: string, + type: string, + source: string, + filterBy: string +): QueryTypeSource => { + return `${query}|||${type}|||${source}|||${filterBy}` as QueryTypeSource; +}; + +const converter = (data: FilterFieldsData): Choice[] => { + const arr = Object.values(data).reduce((acc: Choice[], cur) => { + const field = cur.map((item) => { + return { + value: createQueryTypeSource( + item.filterQuery + ? item.filterQuery + : item.optionQuery + ? item.optionQuery + : `metaKey=${item.optionSource}`, + item.type, + item.optionSource, + item.filterBy + ), + title: item.label + }; + }); + return [...acc, ...field]; + }, []); + + return arr ?? []; +}; + +const parseFields = ( + data: FilterFieldsData, + optionSource: string, + type: string, + search?: string +): Choice[] => { + const allItem = { value: "all", title: type === "inc" ? "All" : "None" }; + + const selectedItem = Object.values(data).reduce((acc, cur) => { + const field = cur.filter((item) => item.optionQuery === optionSource); + + return [...acc, ...field]; + }, [])[0]; + + if (selectedItem.optionSource === "tax") { + const items: Choice[] = ( + selectedItem.possibleValues as PossibleValue[] + ).map((it: PossibleValue) => ({ + value: it.term_id, + title: it.name + })); + + if (search) { + return [ + allItem, + ...items.filter((it) => + it.title.toLocaleLowerCase().includes(search.toLocaleLowerCase()) + ) + ]; + } + + if (checkNotNullOrUndefinedValues(items)) { + return [allItem, ...items]; + } + } + + if (selectedItem.optionSource === "meta") { + const items = selectedItem.possibleValues as Choice[]; + + if (search) { + return [ + allItem, + ...items.filter((it) => + it.title.toLocaleLowerCase().includes(search.toLocaleLowerCase()) + ) + ]; + } + + if (checkNotNullOrUndefinedValues(items)) { + return [allItem, ...items]; + } + } + + return [allItem]; +}; + +function checkNotNullOrUndefinedValues(arr: unknown[]) { + return arr.every((value) => value !== null && value !== undefined); +} diff --git a/public/editor-client/src/api/index.ts b/public/editor-client/src/api/index.ts index bedc6751e3..86679bd973 100644 --- a/public/editor-client/src/api/index.ts +++ b/public/editor-client/src/api/index.ts @@ -589,6 +589,7 @@ export const uploadSaveLayouts = async ( formData.append("version", editorVersion); formData.append("hash", hash); + formData.append("action", actions.uploadBlocks); const r = await request(url, { method: "POST", body: formData }); @@ -763,3 +764,40 @@ export const updatePopupRules = async ( }; //#endregion + +//#region FiltersFields + +export const getFields = async (data: { + postId: string; + loopAttributes: string; +}) => { + try { + const config = getConfig(); + + if (!config) { + throw new Error(t("Invalid __BRZ_PLUGIN_ENV__")); + } + + const { editorVersion, url, hash, actions } = config; + + const body = new URLSearchParams({ + hash: hash, + version: editorVersion, + action: actions.filterFields ?? "brizy_filter_fields", + ...data + }); + + const result = await request(url, { + method: "POST", + body: body + }); + + const r = await result.json(); + + return r.data; + } catch (e) { + throw new Error(t("Fail to load fields!")); + } +}; + +//#endregion diff --git a/public/editor-client/src/config.ts b/public/editor-client/src/config.ts index 8d09aabd49..92af087f59 100644 --- a/public/editor-client/src/config.ts +++ b/public/editor-client/src/config.ts @@ -39,6 +39,8 @@ interface Actions { getPostObjects: string; searchPosts: string; + + filterFields: string; } interface API { @@ -178,7 +180,11 @@ const actionsReader = parseStrict({ ), searchPosts: pipe( mPipe(Obj.readKey("searchPosts"), Str.read), - throwOnNullish("INvalid actions: searchPosts") + throwOnNullish("Invalid actions: searchPosts") + ), + filterFields: pipe( + mPipe(Obj.readKey("filterFields"), Str.read), + throwOnNullish("Invalid actions: filterFields") ) }); diff --git a/public/editor-client/src/index.ts b/public/editor-client/src/index.ts index 8b9338aea3..fe016183a0 100644 --- a/public/editor-client/src/index.ts +++ b/public/editor-client/src/index.ts @@ -12,6 +12,7 @@ import { } from "./defaultTemplates"; import { explodePlaceholder } from "./dynamicContent/explodePlaceholder"; import { makePlaceholder } from "./dynamicContent/makePlaceholder"; +import { handler as filters, possibleValues } from "./Elements/filters"; import { addMedia } from "./media/addMedia"; import { addMediaGallery } from "./media/addMediaGallery"; import { onChange } from "./onChange"; @@ -75,4 +76,17 @@ if (window.__VISUAL_CONFIG__) { window.__VISUAL_CONFIG__.dynamicContent.explodePlaceholder = explodePlaceholder; } + + // Elements + if ( + window.__VISUAL_CONFIG__.elements && + window.__VISUAL_CONFIG__.elements.filters + ) { + window.__VISUAL_CONFIG__.elements.filters.handler = filters; + window.__VISUAL_CONFIG__.elements.filters.possibleValues = possibleValues; + } else { + window.__VISUAL_CONFIG__.elements = { + filters: { handler: filters, possibleValues: possibleValues } + }; + } } diff --git a/public/editor-client/src/types/Filters.ts b/public/editor-client/src/types/Filters.ts new file mode 100644 index 0000000000..edcd71598c --- /dev/null +++ b/public/editor-client/src/types/Filters.ts @@ -0,0 +1,61 @@ +import { NewType } from "./NewType"; +import { Response } from "./Response"; + +export type Choice = { title: string; value: string | number }; + +export type QueryTypeSource = NewType; + +interface FieldsCommon { + filterQuery: string; + label: string; + optionQuery: string; + optionSource: string; + filterBy: string; + type: string; +} + +export interface FilterField extends FieldsCommon { + possibleValues: PossibleValue[] | Choice[]; +} + +export type PossibleValue = { + count: number; + description: string; + filter: string; + name: string; + parent: number; + slug: string; + taxonomy: string; + term_group: number; + term_id: number; + term_taxonomy_id: number; +}; + +export type FilterFieldsData = { + fields: FilterField[]; + taxonomies: FilterField[]; + metaFields: FilterField[]; + authors: FilterField[]; +}; + +export interface Filters { + handler: ( + res: Response, + rej: Response, + args: { + postId: string; + loopAttributes: string; + } + ) => void; + possibleValues: ( + res: Response, + rej: Response, + data: { + postId: string; + loopAttributes: string; + optionSource: string; + type: string; + search?: string; + } + ) => void; +} diff --git a/public/editor-client/src/types/global.d.ts b/public/editor-client/src/types/global.d.ts index 68b35673c6..6df8dddfd1 100644 --- a/public/editor-client/src/types/global.d.ts +++ b/public/editor-client/src/types/global.d.ts @@ -17,6 +17,7 @@ import { OnChange } from "./OnChange"; import { PopupConditions } from "./PopupConditions"; import { PublishData } from "./Project"; import { SavedBlocks, SavedLayouts, SavedPopups } from "./SavedBlocks"; +import { Filters } from "./Filters"; declare class WPMediaLibrary { get: (selector: string) => import("backbone").Collection; @@ -146,6 +147,14 @@ export interface VISUAL_CONFIG { }; //#endregion + + // #region Elements + + elements?: { + filters: Filters; + }; + + //#endregion } declare global {