Files
Tống Thành Đạt a39c336dd4 feat(cms): enhance content editors with dynamic UI configs and validation
Implement a more flexible, configuration-driven approach for CMS editors across accreditation, admissions, and partnerships modules.
- Move UI labels, help texts, and field limits from hardcoded views to `editorUi` configurations in config files.
- Add server-side and client-side validation to prevent duplicate category tabs in accreditation and partnerships editors.
- Refactor partnership and admission views to dynamically render tabs and fields based on the provided configuration.
- Update field length constraints and default values across multiple content editors to better align with frontend requirements.
- Improve the admissions calculator editor with dynamic field configurations and default value fallbacks.
2026-04-22 18:06:03 +07:00

194 lines
3.4 KiB
JavaScript

const ICON_OPTIONS = [
"fa-scale-balanced",
"fa-shield-check",
"fa-magnifying-glass",
"fa-graduation-cap",
"fa-check-double",
"fa-building-columns",
"fa-award",
"fa-trophy",
"fa-arrow-down",
"fa-arrow-right",
"fa-check-circle",
"fa-exchange-alt",
"fa-bolt",
"fa-book-open",
"fa-credit-card",
"fa-calendar-days",
"fa-envelope",
"fa-file-lines",
"fa-globe",
"fa-briefcase",
"fa-handshake",
"fa-circle-info",
"fa-star",
"fa-list-check",
];
const text = (key, label, options = {}) => ({
key,
label,
type: "text",
...options,
});
const date = (key, label, options = {}) => ({
key,
label,
type: "date",
...options,
});
const hidden = (key, options = {}) => ({
key,
type: "hidden",
...options,
});
const textarea = (key, label, options = {}) => ({
key,
label,
type: "textarea",
rows: options.rows || 4,
...options,
});
const image = (key, label, options = {}) => ({
key,
label,
type: "image",
...options,
});
const icon = (key, label, options = {}) => ({
key,
label,
type: "icon",
options: options.options || ICON_OPTIONS,
...options,
});
const checkbox = (key, label, options = {}) => ({
key,
label,
type: "checkbox",
...options,
});
const url = (key, label, options = {}) => ({
key,
label,
type: "url",
...options,
});
const select = (key, label, options = [], extra = {}) => ({
key,
label,
type: "select",
options,
...extra,
});
const combobox = (key, label, options = {}) => ({
key,
label,
type: "combobox",
...options,
});
const object = (key, label, fields, options = {}) => ({
key,
label,
type: "object",
fields,
...options,
});
const stringList = (key, label, options = {}) => ({
key,
label,
type: "array",
itemLabel: options.itemLabel || "Item",
sortable: options.sortable,
addLabel: options.addLabel,
helpText: options.helpText,
emptyText: options.emptyText,
itemSchema: {
type: "primitive",
fieldType: options.fieldType || "text",
label: options.itemLabel || "Item",
maxLength: options.maxLength,
min: options.min,
max: options.max,
step: options.step,
placeholder: options.placeholder,
helpText: options.itemHelpText,
},
...options,
});
const objectList = (key, label, fields, options = {}) => ({
key,
label,
type: "array",
itemLabel: options.itemLabel || "Item",
sortable: options.sortable,
addLabel: options.addLabel,
helpText: options.helpText,
emptyText: options.emptyText,
itemTitleKey: options.itemTitleKey,
itemSubtitleKey: options.itemSubtitleKey,
itemActions: options.itemActions,
itemSchema: {
type: "object",
fields,
},
...options,
});
const variantList = (key, label, variants, options = {}) => ({
key,
label,
type: "array",
itemLabel: options.itemLabel || "Item",
sortable: options.sortable,
addLabel: options.addLabel,
helpText: options.helpText,
emptyText: options.emptyText,
itemSchema: {
type: "variant",
discriminator: "type",
options: Object.keys(variants).map((value) => ({
value,
label: variants[value].label,
})),
variants,
},
...options,
});
const linkFields = (prefix = "Link") => [
text("label", `${prefix} label`, { maxLength: 40 }),
url("href", `${prefix} URL`, { maxLength: 255 }),
];
module.exports = {
ICON_OPTIONS,
text,
date,
hidden,
textarea,
image,
icon,
checkbox,
url,
select,
combobox,
object,
stringList,
objectList,
variantList,
linkFields,
};