feat/huy-05022026-cms-add-footer-api-management

This commit is contained in:
2026-02-05 15:11:25 +07:00
parent b4891101e7
commit fb8676879d
11 changed files with 2673 additions and 1736 deletions

View File

@@ -1,234 +1,213 @@
const mongoose = require("mongoose");
// Schema cho menu links
const menuLinkSchema = new mongoose.Schema(
{
label: {
type: String,
required: true,
trim: true,
},
href: {
type: String,
required: true,
trim: true,
},
order: {
type: Number,
required: false,
default: 0,
},
},
{ _id: false },
);
// Schema cho social links
const socialLinkSchema = new mongoose.Schema(
{
platform: {
type: String,
required: true,
trim: true,
{
icon: {
type: String,
required: true,
trim: true,
},
href: {
type: String,
required: true,
trim: true,
},
},
url: {
type: String,
required: true,
trim: true,
},
icon: {
type: String,
required: true,
trim: true,
},
},
{ _id: false }
{ _id: false },
);
// Schema cho footer links
const footerLinkSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
// Schema cho phone
const phoneSchema = new mongoose.Schema(
{
display: {
type: String,
required: false,
trim: true,
default: "",
},
href: {
type: String,
required: false,
trim: true,
default: "",
},
},
url: {
type: String,
required: true,
trim: true,
},
},
{ _id: false }
);
// Schema cho footer columns
const footerColumnSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
},
links: {
type: [footerLinkSchema],
default: [],
},
},
{ _id: false }
{ _id: false },
);
// Schema cho logo
const logoSchema = new mongoose.Schema(
{
src: {
type: String,
required: true,
trim: true,
{
src: {
type: String,
required: false,
trim: true,
default: "",
},
alt: {
type: String,
required: false,
trim: true,
default: "",
},
href: {
type: String,
required: false,
trim: true,
default: "/",
},
},
alt: {
type: String,
required: true,
trim: true,
},
},
{ _id: false }
);
// Schema cho address
const addressSchema = new mongoose.Schema(
{
text: {
type: String,
required: true,
trim: true,
},
// Thêm address2 (địa chỉ dòng 2) không bắt buộc
address2: {
type: String,
trim: true,
default: "",
},
// Optional secondary link (e.g., a second map or external resource)
link2: {
type: String,
trim: true,
default: "",
},
mapUrl: {
type: String,
required: true,
trim: true,
},
},
{ _id: false }
);
// Schema cho contact info
const contactInfoSchema = new mongoose.Schema(
{
phone: {
type: String,
required: true,
trim: true,
},
hours: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
},
},
{ _id: false }
{ _id: false },
);
// Schema cho copyright
const copyrightSchema = new mongoose.Schema(
{
text: {
type: String,
required: true,
trim: true,
{
text: {
type: String,
required: false,
trim: true,
default: "Copyright©",
},
brand: {
type: String,
required: false,
trim: true,
default: "",
},
rights: {
type: String,
required: false,
trim: true,
default: "All Rights Reserved.",
},
},
},
{ _id: false }
{ _id: false },
);
// Schema cho about section (column đầu tiên)
const aboutSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
// Schema cho top section
const topSchema = new mongoose.Schema(
{
bgImage: {
type: String,
required: false,
trim: true,
default: "",
},
phone: {
type: phoneSchema,
default: () => ({ display: "", href: "" }),
},
address: {
type: String,
required: false,
trim: true,
default: "",
},
logo: {
type: logoSchema,
default: () => ({ src: "", alt: "", href: "/" }),
},
menuLinks: {
type: [menuLinkSchema],
default: [],
},
socialLinks: {
type: [socialLinkSchema],
default: [],
},
},
description: {
type: String,
required: true,
trim: true,
},
mapLink: {
text: {
type: String,
required: true,
trim: true,
},
url: {
type: String,
required: true,
trim: true,
},
},
},
{ _id: false }
{ _id: false },
);
// Main Footer Schema
// Schema cho bottom section
const bottomSchema = new mongoose.Schema(
{
copyright: {
type: copyrightSchema,
default: () => ({ text: "Copyright©", brand: "", rights: "All Rights Reserved." }),
},
menuLinks: {
type: [menuLinkSchema],
default: [],
},
},
{ _id: false },
);
// Main Footer Schema - khớp 100% với footer.json
const footerSchema = new mongoose.Schema(
{
name: {
type: String,
default: "default",
unique: true,
{
top: {
type: topSchema,
default: () => ({
bgImage: "",
phone: { display: "", href: "" },
address: "",
logo: { src: "", alt: "", href: "/" },
menuLinks: [],
socialLinks: [],
}),
},
bottom: {
type: bottomSchema,
default: () => ({
copyright: { text: "Copyright©", brand: "", rights: "All Rights Reserved." },
menuLinks: [],
}),
},
},
about: {
type: aboutSchema,
required: true,
{
timestamps: true,
},
address: {
type: addressSchema,
required: true,
},
contact: {
type: contactInfoSchema,
required: true,
},
columns: {
type: [footerColumnSchema],
default: [],
},
social: {
links: {
type: [socialLinkSchema],
default: [],
},
},
copyright: {
type: copyrightSchema,
required: true,
},
},
{
timestamps: true,
}
);
// Tạo migration script để import dữ liệu từ footer.json
footerSchema.statics.migrateFromJson = async function (jsonData) {
try {
// Kiểm tra xem đã có footer mặc định chưa
const existingFooter = await this.findOne({ name: "default" });
if (existingFooter) {
// Cập nhật footer hiện có
Object.assign(existingFooter, jsonData);
await existingFooter.save();
console.log("Footer data updated successfully");
return existingFooter;
} else {
// Tạo footer mới với dữ liệu từ JSON
const newFooter = await this.create({
name: "default",
...jsonData,
});
console.log("Footer data imported successfully");
return newFooter;
// Static method để lấy hoặc tạo footer duy nhất
footerSchema.statics.getSingle = async function () {
let footer = await this.findOne();
if (!footer) {
footer = await this.create({});
}
return footer;
};
// Migration method để import từ JSON hiện tại
footerSchema.statics.migrateFromJson = async function (jsonData) {
try {
// Xóa tất cả documents hiện có
await this.deleteMany({});
// Tạo document mới
const footer = await this.create(jsonData);
console.log("Footer data migrated successfully");
return footer;
} catch (error) {
console.error("Error migrating footer data:", error);
throw error;
}
} catch (error) {
console.error("Error migrating footer data:", error);
throw error;
}
};
module.exports = mongoose.model("Footer", footerSchema);