Files
cms.techvanguard.vn/utils/contentEditors/partnershipsConfig.js
T
Tống Thành Đạt 5d0fae6d51 feat(cms): enhance content editors and implement automatic ID generation
Improve the CMS administration interface across multiple pages (Accreditation, Admissions, History, Partnerships, and Policies) with a focus on usability and data integrity.
Key changes include:
- Implement `ensureUniqueIds` utility to automatically generate and maintain unique slugs for content items, removing the need for manual ID entry in the UI.
- Refactor the Admissions calculator to support detailed per-option editing via a new dedicated view and routes.
- Replace basic datalists with a custom, searchable icon combobox component for better visual selection.
- Update `_renderSingletonPageView` to handle active tab persistence via query parameters.
- Streamline editor configurations by removing redundant fields and improving help text.
- Enhance the Admissions "Key Dates" editor with a dynamic table interface for managing columns and rows.
- Normalize data payloads in controllers to ensure consistent API responses and internal linking.
2026-04-21 12:37:19 +07:00

148 lines
4.6 KiB
JavaScript

const {
text,
textarea,
image,
checkbox,
select,
combobox,
object,
stringList,
objectList,
} = require("./sharedFields");
const inquiryFieldOptions = [
{ value: "text", label: "Single line text" },
{ value: "textarea", label: "Paragraph" },
{ value: "select", label: "Dropdown" },
];
const widthOptions = [
{ value: "half", label: "Half width" },
{ value: "full", label: "Full width" },
];
module.exports = {
key: "partnerships",
title: "Partnerships Management",
subtitle: "Manage the content for the partnerships page",
routeBase: "/admin/partnerships",
apiPath: "/api/partnerships",
previewPath: "/about/partnerships",
dataFile: "partnerships",
imageType: "partnerships",
tabs: [
{
key: "hero",
label: "Hero",
icon: "fas fa-image",
schema: object("hero", "Hero", [
text("badge", "Eyebrow label", { maxLength: 40 }),
text("title", "Headline", { maxLength: 90 }),
textarea("description", "Supporting text", { maxLength: 220, rows: 4 }),
text("linkLabel", "Scroll link label", { maxLength: 40 }),
image("image", "Hero image", {
imageHint: "Recommended 720x630 px",
helpText: "Upload the image shown in the right hero panel.",
}),
text("imageAlt", "Hero image alt text", { maxLength: 120 }),
]),
},
{
key: "directory",
label: "Partner Directory",
icon: "fas fa-handshake",
schema: object("directory", "Partner directory", [
text("heading", "Section heading", { maxLength: 70 }),
textarea("description", "Section description", {
maxLength: 180,
rows: 3,
}),
stringList("tabs", "Category tabs", {
itemLabel: "Category tab",
maxLength: 30,
placeholder: "Industry",
sortable: true,
helpText: "Add and reorder the category tabs shown on the page.",
}),
objectList(
"partners",
"Partners",
[
text("name", "Partner name", { maxLength: 90 }),
combobox("category", "Category", {
maxLength: 30,
optionsPath: "directory.tabs",
}),
textarea("summary", "Card summary", {
maxLength: 130,
rows: 3,
helpText: "Keep this short. Around 130 characters works best in the card layout.",
}),
image("logo", "Partner logo", {
imageHint: "Recommended 105x80 px minimum visible ratio",
helpText: "Use a clean logo with transparent or simple background.",
}),
text("logoAlt", "Logo alt text", { maxLength: 120 }),
textarea("about", "About text", { maxLength: 600, rows: 5 }),
text("collabType", "Collaboration type", { maxLength: 40 }),
textarea("benefits", "Benefits", { maxLength: 240, rows: 4 }),
],
{
itemLabel: "Partner",
sortable: true,
itemTitleKey: "name",
itemSubtitleKey: "category",
emptyText: "No partners yet.",
},
),
]),
},
{
key: "cta",
label: "Call To Action",
icon: "fas fa-bullhorn",
schema: object("cta", "Call to action", [
text("heading", "Headline", { maxLength: 80 }),
textarea("description", "Supporting text", {
maxLength: 220,
rows: 4,
}),
text("buttonLabel", "Button label", { maxLength: 40 }),
]),
},
{
key: "inquiryForm",
label: "Inquiry Form",
icon: "fas fa-envelope",
schema: object("inquiryForm", "Inquiry form", [
text("title", "Modal title", { maxLength: 60 }),
objectList(
"fields",
"Form fields",
[
text("label", "Field label", { maxLength: 40 }),
text("placeholder", "Placeholder text", { maxLength: 80 }),
select("type", "Field type", inquiryFieldOptions),
select("width", "Field width", widthOptions),
stringList("options", "Dropdown options", {
itemLabel: "Option",
maxLength: 50,
sortable: true,
helpText: "Only used when the field type is Dropdown.",
visibleWhen: { path: "type", equals: "select" },
}),
checkbox("required", "Required field"),
],
{
itemLabel: "Field",
sortable: true,
itemTitleKey: "label",
itemSubtitleKey: "type",
emptyText: "No inquiry fields yet.",
},
),
]),
},
],
};