Skip to content

Commit

Permalink
replace fields based on tranlsations
Browse files Browse the repository at this point in the history
  • Loading branch information
SalvadorDalia committed Dec 11, 2024
1 parent 12fd4c2 commit 33e600a
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 37 deletions.
2 changes: 2 additions & 0 deletions i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ i18n.init({
en: {
translation: {
ContentType: "Content Type",
DefaultLanguage: "Domyślny język",
FieldRequired: "Field is required",
Fields: "Content type fields to translate",
Languages: "Available languages",
Expand All @@ -18,6 +19,7 @@ i18n.init({
pl: {
translation: {
ContentType: "Typ zawartości",
DefaultLanguage: "Default language",
FieldRequired: "Pole jest wymagane",
Fields: "Pola typu zawartości do przetłumaczenia",
Languages: "Dostępne języki",
Expand Down
97 changes: 97 additions & 0 deletions plugins/form-add/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
addElementToCache,
getCachedElement,
} from "../../common/plugin-element-cache";
import pluginInfo from "../../plugin-manifest.json";

const selectedClass = "plugin-multilangual-tab__item--selected";

export const formLng = {
current: null,
};

const addToTranslations = (contentTypeSettings, formik, lngIndex) => {
const defaultObject = contentTypeSettings.fields.reduce(
(fields, currentFieldKey) => {
console.log(currentFieldKey, formik.values[currentFieldKey]);
fields[currentFieldKey] = formik.values[currentFieldKey];
return fields;
},
{},
);

formik.setFieldValue(`__translations.[${lngIndex}]`, {
...defaultObject,
__language: formLng.current,
});
};

export const handleFormFieldAdd = (
{ contentType, formik },
getPluginSettings,
) => {
const pluginSettings = getPluginSettings();
const parsedSettings = JSON.parse(pluginSettings || "{}");

const contentTypeSettings = parsedSettings?.config?.find(
({ content_type }) => content_type === contentType?.name,
);

if (!contentTypeSettings) return;

const dropdownCacheKey = `${pluginInfo.id}-language-tabs`;
let tabsContainer = getCachedElement(dropdownCacheKey)?.element;
let tabsData = getCachedElement(dropdownCacheKey)?.data || {};

tabsData.formik = formik;

if (!tabsContainer) {
tabsContainer = document.createElement("div");
tabsContainer.className = "plugin-multilangual-tabs";

const defaultLng = contentTypeSettings.default_language;
formLng.current = defaultLng;

for (const lng of contentTypeSettings.languages) {
const lngItemButton = document.createElement("button");
lngItemButton.className = "plugin-multilangual-tab__item";
lngItemButton.innerText = lng;
lngItemButton.type = "button";

if (lng === defaultLng) {
lngItemButton.classList.toggle(selectedClass);
}

lngItemButton.onclick = async (event) => {
formLng.current = lng;

if (formLng.current !== defaultLng) {
const indexInTranlsations = Object.values(
tabsData.formik.values.__translations,
).findIndex(({ __language }) => __language === formLng.current);

if (indexInTranlsations < 0) {
addToTranslations(
contentTypeSettings,
tabsData.formik,
tabsData.formik.values.__translations.length,
);
}
}

tabsData.formik.setFieldTouched(`__translations`, true);

const slectedTab = document.querySelector(`.${selectedClass}`);
if (slectedTab) slectedTab.classList.toggle(selectedClass);

event.target.classList.toggle(selectedClass);
};

tabsContainer.appendChild(lngItemButton);
}
}

addElementToCache(tabsContainer, dropdownCacheKey, tabsData);

return tabsContainer;
};
65 changes: 61 additions & 4 deletions plugins/form-config/co-form/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,61 @@
export const handleCoFormConfig = (
{ contentType, name, config, formik },
settings,
) => {};
import { formLng } from "../../form-add";

let fieldDictionary = null;

export const handleCoFormConfig = async (
{ name, config, formik },
contentTypeSettings,
) => {
config.key = `${formLng.current}-${name}`;

if (
!formLng.current ||
formLng.current === contentTypeSettings.default_language
) {
return;
}

if (!fieldDictionary) {
fieldDictionary = contentTypeSettings.fields.reduce((acc, field) => {
acc[field] = true;
return acc;
}, {});
}

const isInTranlsations = fieldDictionary[name];

if (!isInTranlsations) {
const { listName } = name.match(/(?<listName>\w+)\[(\d+)\]/)?.groups || {};

if (listName) {
const listInTranlsation = fieldDictionary[listName];
if (listInTranlsation) return;
}

config.disabled = true;
return;
}

const translationIndex = Object.values(
formik.values.__translations,
).findIndex(({ __language }) => __language === formLng.current);

const lngIndex =
translationIndex > -1
? translationIndex
: formik.values.__translations.length;

const fieldName = `__translations.[${lngIndex}].${name}`;

if (fieldName !== config.name) {
config.name = fieldName;

const value = formik.values.__translations?.[lngIndex]?.[name];

if ("checked" in config) {
config.checked = value;
} else {
config.value = value;
}
}
};
4 changes: 2 additions & 2 deletions plugins/form-config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export const handleFormFieldConfig = (data, getPluginSettings) => {
const pluginSettings = getPluginSettings();
const parsedSettings = JSON.parse(pluginSettings || "{}");

const contentTypeSettings = parsedSettings?.buttons?.filter(
const contentTypeSettings = parsedSettings?.config?.find(
({ content_type }) => content_type === data?.contentType?.name,
);

if (!contentTypeSettings?.length) return;
if (!contentTypeSettings) return;

handleCoFormConfig(data, contentTypeSettings);
};
7 changes: 6 additions & 1 deletion plugins/form-config/plugin-form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ export const handlePluginFormConfig = ({ name, config, formik }) => {

formik.setFieldValue(`config[${index}].fields`, "");
};
} else {
} else if (type === "fields") {
const fieldOptions =
getCachedElement(validFieldsCacheKey)?.element?.fieldOptions;

const ctd = formik.values.config[index].content_type;

config.options = fieldOptions?.[ctd] || [];
config.additionalHelpTextClasses = "break-normal";
} else if (type === "default_language") {
config.options = formik.values.config[index].languages.map((lng) => ({
value: lng,
label: lng,
}));
}
};
5 changes: 5 additions & 0 deletions plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import pluginInfo from "../plugin-manifest.json";
import cssString from "inline:./styles/style.css";
import { handleManageSchema } from "./manage";
import { handleFormFieldConfig } from "./form-config";
import { handleFormFieldAdd } from "./form-add";

registerFn(pluginInfo, (handler, client, { toast, getPluginSettings }) => {
/**
Expand All @@ -19,6 +20,10 @@ registerFn(pluginInfo, (handler, client, { toast, getPluginSettings }) => {
handleFormFieldConfig(data, getPluginSettings),
);

handler.on("flotiq.form::add", (data) =>
handleFormFieldAdd(data, getPluginSettings),
);

handler.on("flotiq.plugins.manage::form-schema", (data) =>
handleManageSchema(data, client, toast),
);
Expand Down
92 changes: 62 additions & 30 deletions plugins/manage/form-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ export const getSchema = (contentTypes) => ({
type: "array",
items: {
type: "object",
required: ["languages", "fields", "content_type"],
required: [
"languages",
"fields",
"content_type",
"default_language",
],
properties: {
fields: {
type: "array",
Expand All @@ -41,6 +46,10 @@ export const getSchema = (contentTypes) => ({
type: "string",
minLength: 1,
},
default_language: {
type: "string",
minLength: 1,
},
},
},
},
Expand All @@ -55,7 +64,7 @@ export const getSchema = (contentTypes) => ({
propertiesConfig: {
config: {
items: {
order: ["content_type", "fields", "languages"],
order: ["content_type", "fields", "languages", "default_language"],
propertiesConfig: {
fields: {
label: i18n.t("Fields"),
Expand All @@ -81,6 +90,14 @@ export const getSchema = (contentTypes) => ({
optionsWithLabels: contentTypes,
useOptionsWithLabels: true,
},
default_language: {
label: i18n.t("DefaultLanguage"),
unique: false,
helpText: "",
isMultiple: false,
inputType: "select",
options: [],
},
},
},
label: "config",
Expand All @@ -102,24 +119,26 @@ export const getValidator = (fieldKeys) => {
const onValidate = (values) => {
const errors = {};

values.config?.forEach(({ content_type, languages, fields }, index) => {
if (!content_type) {
addToErrors(errors, index, "content_type", i18n.t("FieldRequired"));
}
values.config?.forEach((ctdConfig, index) => {
const requiredFields = [
"content_type",
"default_language",
"languages",
"fields",
];

if (!languages?.length) {
addToErrors(errors, index, "languages", i18n.t("FieldRequired"));
for (const field of requiredFields) {
const value = ctdConfig[field];
if (!value || (Array.isArray(value) && !value.length)) {
addToErrors(errors, index, "field", i18n.t("FieldRequired"));
}
}

if (!fields?.length) {
addToErrors(errors, index, "fields", i18n.t("FieldRequired"));
} else {
fields.map((field) => {
if (!(fieldKeys[content_type] || []).includes(field)) {
addToErrors(errors, index, "fields", i18n.t("WrongField"));
}
});
}
(ctdConfig.fields || []).map((field) => {
if (!(fieldKeys[ctdConfig.content_type] || []).includes(field)) {
addToErrors(errors, index, "fields", i18n.t("WrongField"));
}
});
});

return errors;
Expand All @@ -128,7 +147,12 @@ export const getValidator = (fieldKeys) => {
return onValidate;
};

const updateContentTypeSchema = async (contentType, fieldKeys, languages) => {
const updateContentTypeSchema = async (
contentType,
fieldKeys,
languages,
defaultLanguage,
) => {
const translationPropertiesConfig = fieldKeys.reduce((config, key) => {
config[key] = contentType.metaDefinition.propertiesConfig[key];
return config;
Expand All @@ -151,7 +175,7 @@ const updateContentTypeSchema = async (contentType, fieldKeys, languages) => {
__language: {
label: "Language",
unique: false,
options: languages,
options: languages.filter((lng) => lng !== defaultLanguage),
helpText: "",
inputType: "select",
useOptionsWithLabels: false,
Expand Down Expand Up @@ -194,20 +218,28 @@ export const getSubmitHandler =
(contentTypes, client, reload, modalInstance, toast) => async (values) => {
try {
await Promise.all(
values.config.map(async ({ content_type, fields, languages }) => {
const ctd = contentTypes.find(({ name }) => name === content_type);
const ctdClone = JSON.parse(JSON.stringify(ctd));
values.config.map(
async ({ content_type, fields, languages, default_language }) => {
const ctd = contentTypes.find(({ name }) => name === content_type);
const ctdClone = JSON.parse(JSON.stringify(ctd));

updateContentTypeSchema(ctdClone, fields, languages);
updateContentTypeSchema(
ctdClone,
fields,
languages,
default_language,
);

const isSame = deepEqual(ctd, ctdClone);
if (isSame) return;
const isSame = deepEqual(ctd, ctdClone);
if (isSame) return;

const { body, ok } = await client[ctd.name].putContentType(ctdClone);
if (!ok) {
toast.error(`Cannot update ${ctd.name}, ${body.message}`);
}
}),
const { body, ok } =
await client[ctd.name].putContentType(ctdClone);
if (!ok) {
toast.error(`Cannot update ${ctd.name}, ${body.message}`);
}
},
),
);
const { body, ok } = await client["_plugin_settings"].patch(
pluginInfo.id,
Expand Down
Loading

0 comments on commit 33e600a

Please sign in to comment.