forked from UKSOURCE/cms.hailearning.edu.vn
first commit
This commit is contained in:
387
models/contact.js
Normal file
387
models/contact.js
Normal file
@@ -0,0 +1,387 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
// Schema cho hero section
|
||||
const heroSchema = new mongoose.Schema(
|
||||
{
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
backgroundImage: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
overlayColor: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "rgba(0, 0, 0, 0)",
|
||||
},
|
||||
sectionClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
titleClass: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
enableScrollspy: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
backgroundPosition: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "center",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho contact card
|
||||
const contactCardSchema = new mongoose.Schema(
|
||||
{
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
enum: [
|
||||
"phone",
|
||||
"email",
|
||||
"location",
|
||||
"hours",
|
||||
"website",
|
||||
"social",
|
||||
"custom",
|
||||
],
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
content: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
iconType: {
|
||||
type: String,
|
||||
required: false,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
iconSource: {
|
||||
type: String,
|
||||
required: false,
|
||||
trim: true,
|
||||
enum: ["fontawesome", "image"],
|
||||
default: "fontawesome",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho map coordinates
|
||||
const coordinatesSchema = new mongoose.Schema(
|
||||
{
|
||||
lat: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
lng: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho tile layer
|
||||
const tileLayerSchema = new mongoose.Schema(
|
||||
{
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
attribution: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
maxZoom: {
|
||||
type: Number,
|
||||
default: 18,
|
||||
},
|
||||
minZoom: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho map
|
||||
const mapSchema = new mongoose.Schema(
|
||||
{
|
||||
coordinates: {
|
||||
type: coordinatesSchema,
|
||||
required: true,
|
||||
},
|
||||
zoom: {
|
||||
type: Number,
|
||||
default: 15,
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
markerTitle: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
tileLayer: {
|
||||
type: tileLayerSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho form field
|
||||
const formFieldSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
enum: ["text", "email", "tel", "textarea", "programme"],
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
programmeName: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho submit button
|
||||
const submitButtonSchema = new mongoose.Schema(
|
||||
{
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Schema cho form
|
||||
const formSchema = new mongoose.Schema(
|
||||
{
|
||||
sectionLabel: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
heading: {
|
||||
type: String,
|
||||
trim: true,
|
||||
default: "",
|
||||
},
|
||||
fields: {
|
||||
type: [formFieldSchema],
|
||||
default: [],
|
||||
},
|
||||
submitButton: {
|
||||
type: submitButtonSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
// Main Contact Schema
|
||||
const contactSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
default: "default",
|
||||
unique: true,
|
||||
},
|
||||
hero: {
|
||||
type: heroSchema,
|
||||
required: true,
|
||||
},
|
||||
contactCards: {
|
||||
type: [contactCardSchema],
|
||||
default: [],
|
||||
},
|
||||
map: {
|
||||
type: mapSchema,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: formSchema,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Mapping iconType cũ sang Font Awesome icon mới
|
||||
const iconTypeMapping = {
|
||||
phone: "fas fa-phone",
|
||||
email: "fas fa-envelope",
|
||||
location: "fas fa-map-marker-alt",
|
||||
clock: "fas fa-clock",
|
||||
hours: "fas fa-clock",
|
||||
};
|
||||
|
||||
// Tạo migration script để import dữ liệu từ contact-data.json
|
||||
contactSchema.statics.migrateFromJson = async function (jsonData) {
|
||||
try {
|
||||
// Kiểm tra xem đã có contact mặc định chưa
|
||||
const existingContact = await this.findOne({ name: "default" });
|
||||
|
||||
// Xử lý và chuẩn hóa dữ liệu từ JSON
|
||||
const processedData = {
|
||||
hero: {
|
||||
title: jsonData.hero?.title || "Contact Us",
|
||||
backgroundImage: jsonData.hero?.backgroundImage || "",
|
||||
overlayColor: jsonData.hero?.overlayColor || "rgba(0, 0, 0, 0)",
|
||||
sectionClass: jsonData.hero?.sectionClass || "",
|
||||
titleClass: jsonData.hero?.titleClass || "",
|
||||
enableScrollspy: jsonData.hero?.enableScrollspy || false,
|
||||
backgroundPosition: jsonData.hero?.backgroundPosition || "center",
|
||||
},
|
||||
contactCards: (jsonData.contactCards || []).map((card) => {
|
||||
let iconType = card.iconType || "";
|
||||
let iconSource = card.iconSource;
|
||||
|
||||
// Nếu không có iconSource, tự động detect từ iconType
|
||||
if (!iconSource) {
|
||||
// Nếu iconType là image path (bắt đầu bằng /uploads/ hoặc http)
|
||||
if (
|
||||
iconType.startsWith("/uploads/") ||
|
||||
iconType.startsWith("http://") ||
|
||||
iconType.startsWith("https://")
|
||||
) {
|
||||
iconSource = "image";
|
||||
} else {
|
||||
// Nếu iconType là string cũ (phone, email, location, clock)
|
||||
iconSource = "fontawesome";
|
||||
// Map iconType cũ sang Font Awesome icon mới
|
||||
if (iconTypeMapping[iconType]) {
|
||||
iconType = iconTypeMapping[iconType];
|
||||
} else if (
|
||||
iconType &&
|
||||
!iconType.startsWith("fas ") &&
|
||||
!iconType.startsWith("fab ")
|
||||
) {
|
||||
// Nếu iconType không phải là Font Awesome class hợp lệ, thử map
|
||||
iconType = iconTypeMapping[iconType] || iconType;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Nếu đã có iconSource nhưng iconType là string cũ, map sang Font Awesome
|
||||
if (
|
||||
iconSource === "fontawesome" &&
|
||||
iconType &&
|
||||
!iconType.startsWith("fas ") &&
|
||||
!iconType.startsWith("fab ") &&
|
||||
iconTypeMapping[iconType]
|
||||
) {
|
||||
iconType = iconTypeMapping[iconType];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: card.type || "custom",
|
||||
title: card.title || "",
|
||||
content: Array.isArray(card.content) ? card.content : [],
|
||||
iconType: iconType,
|
||||
iconSource: iconSource || "fontawesome",
|
||||
};
|
||||
}),
|
||||
map: {
|
||||
coordinates: {
|
||||
lat: jsonData.map?.coordinates?.lat || 0,
|
||||
lng: jsonData.map?.coordinates?.lng || 0,
|
||||
},
|
||||
zoom: jsonData.map?.zoom || 15,
|
||||
location: jsonData.map?.location || "",
|
||||
markerTitle: jsonData.map?.markerTitle || "",
|
||||
tileLayer: {
|
||||
url:
|
||||
jsonData.map?.tileLayer?.url ||
|
||||
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
attribution: jsonData.map?.tileLayer?.attribution || "",
|
||||
maxZoom: jsonData.map?.tileLayer?.maxZoom || 18,
|
||||
minZoom: jsonData.map?.tileLayer?.minZoom || 0,
|
||||
},
|
||||
},
|
||||
form: {
|
||||
sectionLabel: jsonData.form?.sectionLabel || "",
|
||||
heading: jsonData.form?.heading || "",
|
||||
fields: (jsonData.form?.fields || []).map((field) => ({
|
||||
name: field.name || "",
|
||||
type: field.type || "text",
|
||||
placeholder: field.placeholder || "",
|
||||
required: field.required || false,
|
||||
programmeName: field.programmeName || "",
|
||||
})),
|
||||
submitButton: {
|
||||
text: jsonData.form?.submitButton?.text || "Send Message",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (existingContact) {
|
||||
// Cập nhật contact hiện có với dữ liệu đã xử lý
|
||||
existingContact.hero = processedData.hero;
|
||||
existingContact.contactCards = processedData.contactCards;
|
||||
existingContact.map = processedData.map;
|
||||
existingContact.form = processedData.form;
|
||||
await existingContact.save();
|
||||
console.log("Contact data updated successfully");
|
||||
return existingContact;
|
||||
} else {
|
||||
// Tạo contact mới với dữ liệu đã xử lý
|
||||
const newContact = await this.create({
|
||||
name: "default",
|
||||
...processedData,
|
||||
});
|
||||
console.log("Contact data imported successfully");
|
||||
return newContact;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error migrating contact data:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = mongoose.model("Contact", contactSchema);
|
||||
Reference in New Issue
Block a user