/** * Seed curated homepage images into website slots for mana-collection. * Creates missing cells and fills empty imageUrl with storefront defaults. * Never overwrites an existing uploaded imageUrl. * * Usage: npm run seed:website-slots */ import { PrismaClient } from '@prisma/client'; import { WEBSITE_SLOT_DEFS } from '../src/website-slots/website-slot.catalog'; const prisma = new PrismaClient(); type DefaultRow = { slotKey: string; sortOrder: number; nameFa: string; nameEn: string; subtext: string; link: string; imageUrl: string; }; function collectDefaults(): DefaultRow[] { const rows: DefaultRow[] = []; for (const def of WEBSITE_SLOT_DEFS) { if (def.kind === 'fixed' && def.defaultImage) { rows.push({ slotKey: def.slug, sortOrder: 0, nameFa: def.defaultNameFa || def.labelFa, nameEn: def.defaultNameEn || def.labelEn, subtext: def.defaultSubtext || '', link: def.defaultLink || '', imageUrl: def.defaultImage, }); continue; } if (def.kind === 'fixed-set' && def.cellLabels?.length) { def.cellLabels.forEach((cell, index) => { if (!cell.defaultImage) return; rows.push({ slotKey: def.slug, sortOrder: index, nameFa: cell.defaultNameFa || cell.labelFa, nameEn: cell.defaultNameEn || cell.labelEn, subtext: cell.defaultSubtext || '', link: cell.defaultLink || '', imageUrl: cell.defaultImage, }); }); } } return rows; } async function main() { const store = await prisma.store.findFirst({ where: { slug: 'mana-collection' }, select: { id: true, slug: true }, }); if (!store) { throw new Error('Store mana-collection not found. Run seed:mana-store first.'); } const defaults = collectDefaults(); let created = 0; let filled = 0; let skipped = 0; for (const row of defaults) { const existing = await prisma.websiteSlotItem.findFirst({ where: { storeId: store.id, slotKey: row.slotKey, sortOrder: row.sortOrder, }, }); if (!existing) { await prisma.websiteSlotItem.create({ data: { storeId: store.id, slotKey: row.slotKey, sortOrder: row.sortOrder, nameFa: row.nameFa, nameEn: row.nameEn, subtext: row.subtext, linkText: '', link: row.link, imageUrl: row.imageUrl, }, }); created += 1; continue; } const shouldReplaceImage = !existing.imageUrl || // Replace legacy CDN category icons with curated transparent assets. (row.slotKey === 'category-strip' && !existing.imageUrl.includes('/images/transparent/')) || ((row.slotKey === 'opening-frame' || row.slotKey === 'sticky-story') && !existing.imageUrl.includes('/images/landscapes/')); if (shouldReplaceImage) { await prisma.websiteSlotItem.update({ where: { id: existing.id }, data: { imageUrl: row.imageUrl, nameFa: existing.nameFa || row.nameFa, nameEn: existing.nameEn || row.nameEn, subtext: existing.subtext || row.subtext, link: existing.link || row.link, }, }); filled += 1; continue; } skipped += 1; } console.log('Seeded website slot defaults:', { store: store.slug, created, filledEmptyImages: filled, alreadyHadImages: skipped, totalDefaults: defaults.length, }); } main() .catch((err) => { console.error(err); process.exitCode = 1; }) .finally(async () => { await prisma.$disconnect(); });