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;