Files
sst_site/.history/models/Banner_20251022195905.js
2025-10-22 21:22:44 +09:00

195 lines
4.0 KiB
JavaScript

const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/database');
const Banner = sequelize.define('Banner', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
title: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true,
len: [1, 200]
}
},
subtitle: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: [0, 300]
}
},
description: {
type: DataTypes.TEXT,
allowNull: true
},
buttonText: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: [0, 50]
}
},
buttonUrl: {
type: DataTypes.STRING,
allowNull: true,
validate: {
isUrl: true
}
},
image: {
type: DataTypes.STRING,
allowNull: true,
comment: 'Banner background image URL'
},
mobileImage: {
type: DataTypes.STRING,
allowNull: true,
comment: 'Mobile-optimized banner image URL'
},
position: {
type: DataTypes.ENUM('hero', 'secondary', 'footer'),
defaultValue: 'hero',
allowNull: false
},
order: {
type: DataTypes.INTEGER,
defaultValue: 0,
allowNull: false,
comment: 'Display order (lower numbers appear first)'
},
isActive: {
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: false
},
startDate: {
type: DataTypes.DATE,
allowNull: true,
comment: 'Banner start display date'
},
endDate: {
type: DataTypes.DATE,
allowNull: true,
comment: 'Banner end display date'
},
clickCount: {
type: DataTypes.INTEGER,
defaultValue: 0,
allowNull: false
},
impressions: {
type: DataTypes.INTEGER,
defaultValue: 0,
allowNull: false
},
targetAudience: {
type: DataTypes.ENUM('all', 'mobile', 'desktop'),
defaultValue: 'all',
allowNull: false
},
backgroundColor: {
type: DataTypes.STRING,
allowNull: true,
validate: {
is: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
},
comment: 'Hex color code for banner background'
},
textColor: {
type: DataTypes.STRING,
allowNull: true,
validate: {
is: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
},
comment: 'Hex color code for banner text'
},
animation: {
type: DataTypes.ENUM('none', 'fade', 'slide', 'zoom'),
defaultValue: 'none',
allowNull: false
},
metadata: {
type: DataTypes.JSONB,
allowNull: true,
defaultValue: {},
comment: 'Additional banner metadata and settings'
}
}, {
tableName: 'banners',
timestamps: true,
paranoid: true,
indexes: [
{
fields: ['isActive']
},
{
fields: ['position']
},
{
fields: ['order']
},
{
fields: ['startDate', 'endDate']
}
]
});
// Virtual field for checking if banner is currently active
Banner.prototype.isCurrentlyActive = function() {
if (!this.isActive) return false;
const now = new Date();
if (this.startDate && now < this.startDate) return false;
if (this.endDate && now > this.endDate) return false;
return true;
};
// Method to increment click count
Banner.prototype.recordClick = async function() {
this.clickCount += 1;
await this.save();
return this;
};
// Method to increment impressions
Banner.prototype.recordImpression = async function() {
this.impressions += 1;
await this.save();
return this;
};
// Static method to get active banners
Banner.getActiveBanners = async function(position = null) {
const whereClause = {
isActive: true
};
if (position) {
whereClause.position = position;
}
const now = new Date();
return await this.findAll({
where: {
...whereClause,
[require('sequelize').Op.or]: [
{ startDate: null },
{ startDate: { [require('sequelize').Op.lte]: now } }
],
[require('sequelize').Op.or]: [
{ endDate: null },
{ endDate: { [require('sequelize').Op.gte]: now } }
]
},
order: [['order', 'ASC'], ['createdAt', 'DESC']]
});
};
module.exports = Banner;