From b4deb60e1a8335447b3654c1b1c21babc1784bb3 Mon Sep 17 00:00:00 2001 From: DanielGherjavca Date: Fri, 27 Oct 2023 21:06:48 +0300 Subject: [PATCH] feat(ministry brands): handler in editor-client --- public/editor-client/src/config.ts | 6 +- public/editor-client/src/ekklesia/index.ts | 84 ++++++++++++++++++++++ public/editor-client/src/ekklesia/utils.ts | 64 +++++++++++++++++ public/editor-client/src/index.ts | 7 ++ public/editor-client/src/types/Ekklesia.ts | 57 +++++++++++++++ 5 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 public/editor-client/src/ekklesia/index.ts create mode 100644 public/editor-client/src/ekklesia/utils.ts create mode 100644 public/editor-client/src/types/Ekklesia.ts diff --git a/public/editor-client/src/config.ts b/public/editor-client/src/config.ts index 95a32f3711..3b87cb5c21 100644 --- a/public/editor-client/src/config.ts +++ b/public/editor-client/src/config.ts @@ -51,6 +51,7 @@ interface API { fileUrl: string; templates: DefaultTemplates; openAIUrl?: string; + ekklesiaApiUrl?: string; } export interface Config { hash: string; @@ -111,9 +112,8 @@ const apiReader = parseStrict({ mPipe(Obj.readKey("templates"), Obj.read, templatesReader), throwOnNullish("Invalid API: templates") ), - openAIUrl: optional(pipe( - mPipe(Obj.readKey("openAIUrl"), Str.read), - )) + openAIUrl: optional(pipe(mPipe(Obj.readKey("openAIUrl"), Str.read))), + ekklesiaApiUrl: optional(mPipe(Obj.readKey("ekklesiaApiUrl"), Str.read)) }); const actionsReader = parseStrict({ diff --git a/public/editor-client/src/ekklesia/index.ts b/public/editor-client/src/ekklesia/index.ts new file mode 100644 index 0000000000..07c70b1e9e --- /dev/null +++ b/public/editor-client/src/ekklesia/index.ts @@ -0,0 +1,84 @@ +import { Config } from "config"; +import { ChoicesAsync, ChoicesSync } from "types/Choices"; +import { + EkklesiaFieldMap, + EkklesiaFields, + EkklesiaKeys, + EkklesiaParams +} from "types/Ekklesia"; +import { Response } from "types/Response"; +import { t } from "utils/i18n"; +import { getFields } from "./utils"; + +export const getEkklesiaFields = (config: Config) => ({ + async handler( + res: Response, + rej: Response, + keys: EkklesiaParams + ): Promise { + const { ekklesiaApiUrl } = config.api; + if (!ekklesiaApiUrl) { + if (process.env.NODE_ENV === "development") { + console.error("Missing Ekklesia api url!"); + } + res([{ value: "", title: t("None") }]); + return; + } + try { + const fields = await getFields(ekklesiaApiUrl, keys); + res(fields); + } catch (error) { + if (process.env.NODE_ENV === "development") { + console.error("Failed to load ekklesia fields 2"); + } + rej(t("Failed to load ekklesia fields")); + } + } +}); + +export const updateEkklesiaFields = (config: Config) => ({ + async handler( + res: Response, + rej: Response, + keys: { + fields: Array; + } + ): Promise { + const { ekklesiaApiUrl } = config.api; + + if (!ekklesiaApiUrl) { + if (process.env.NODE_ENV === "development") { + console.error("Missing Ekklesia api url!"); + } + rej(t("Missing Ekklesia api url!")); + return; + } + + const dataToChange: EkklesiaKeys = {}; + try { + for (const field of keys.fields) { + const choiches = await getFields(ekklesiaApiUrl, field.module); + + if (!choiches.length) continue; + + const updatedField = Object.keys(field.value).reduce((acc, key) => { + const value = field.value[key]; + const currentField = choiches.find( + (choice) => choice.value === value + ); + + if (!currentField) { + acc[key] = ""; + } + + return acc; + }, {} as EkklesiaKeys); + + Object.assign(dataToChange, updatedField); + } + res(Object.keys(dataToChange).length ? dataToChange : undefined); + } catch (error) { + rej(t("Failed to load ekklesia fields")); + } + } +}); diff --git a/public/editor-client/src/ekklesia/utils.ts b/public/editor-client/src/ekklesia/utils.ts new file mode 100644 index 0000000000..88f59ff865 --- /dev/null +++ b/public/editor-client/src/ekklesia/utils.ts @@ -0,0 +1,64 @@ +import { request } from "api/index"; +import { makeUrl } from "api/utils"; +import { ChoicesSync } from "types/Choices"; +import { + EkklesiaChoiceParamsWithSubKey, + EkklesiaFields, + EkklesiaParams, + EkklesiaParentsChilds, + EkklesiaResponse +} from "types/Ekklesia"; +import { t } from "utils/i18n"; +import { isObject } from "utils/reader/object"; +import { read as readString } from "utils/reader/string"; +import { Literal } from "utils/types"; + +export const requestFields = (url: string): Promise => { + return request(url).then((res) => res.json()); +}; + +export const fieldHaveParentsChildsKeys = ( + keys: Record | EkklesiaParentsChilds +): keys is EkklesiaParentsChilds => "childs" in keys && "parents" in keys; + +export const keysHaveSubkey = ( + keys: EkklesiaParams +): keys is EkklesiaChoiceParamsWithSubKey => "subKey" in keys; + +export const getOption = ( + obj: Record | undefined +): ChoicesSync => + isObject(obj) + ? [ + { title: t("None"), value: "" }, + ...Object.entries(obj).map(([key, value]) => { + return { + title: readString(value) ?? "", + value: key + }; + }) + ] + : []; + +export const getFields = async < + T extends keyof EkklesiaFields = keyof EkklesiaFields +>( + _url: string, + keys: EkklesiaParams +): Promise => { + const { key } = keys; + + const url = makeUrl(_url, { module: key }); + + const { data = {} } = await requestFields(url); + const field = data[key]; + + if (field && fieldHaveParentsChildsKeys(field)) { + if (keysHaveSubkey(keys)) { + return getOption(field[keys.subKey]); + } + return [{ value: "", title: t("None") }]; + } else { + return getOption(field); + } +}; diff --git a/public/editor-client/src/index.ts b/public/editor-client/src/index.ts index 3cfbfe57a0..ba4ed9302f 100644 --- a/public/editor-client/src/index.ts +++ b/public/editor-client/src/index.ts @@ -1,3 +1,4 @@ +import { getEkklesiaFields, updateEkklesiaFields } from "ekklesia/index"; import set from "lodash/set"; import {doAiRequest} from "./aiText"; import {autoSave} from "./autoSave"; @@ -54,6 +55,12 @@ const api = { searchCollectionItems, getCollectionItemsIds }, + modules: { + ekklesia: { + getEkklesiaFields: getEkklesiaFields(config), + updateEkklesiaFields: updateEkklesiaFields(config) + } + }, collectionTypes: { loadCollectionTypes }, diff --git a/public/editor-client/src/types/Ekklesia.ts b/public/editor-client/src/types/Ekklesia.ts new file mode 100644 index 0000000000..c45a23f9ef --- /dev/null +++ b/public/editor-client/src/types/Ekklesia.ts @@ -0,0 +1,57 @@ +import { Literal } from "utils/types"; + +export interface EkklesiaResponse { + data: Partial; +} + +export interface EkklesiaFields { + groups: Record; + events: Record; + series: Record; + recentSermons: Record; + smallgroups: Record; + forms: Record; + sermon: Record; + event: Record; + smallgroup: Record; + eventsLvl: EkklesiaParentsChilds; + smallgroupsLvl: EkklesiaParentsChilds; +} + +export interface EkklesiaParentsChilds { + parents: Record; + childs: Record; +} + +export interface EkklesiaChoiceParams< + T extends keyof EkklesiaFields = keyof EkklesiaFields +> { + key: T; +} + +export interface EkklesiaChoiceParamsWithSubKey< + T extends keyof EkklesiaFields = keyof EkklesiaFields +> extends EkklesiaChoiceParams { + subKey: keyof EkklesiaFields[T]; +} + +export type EkklesiaParams< + T extends keyof EkklesiaFields = keyof EkklesiaFields +> = EkklesiaFields[T] extends EkklesiaParentsChilds + ? EkklesiaChoiceParamsWithSubKey + : EkklesiaChoiceParams; + +export interface EkklesiaKeys { + [key: string]: string; +} + +export type EkklesiaFieldMap = { + [K in keyof EkklesiaFields]: EkklesiaModuleFields; +}; + +export interface EkklesiaModuleFields< + T extends keyof EkklesiaFields = keyof EkklesiaFields +> { + value: Record; + module: EkklesiaParams; +}