- Birthday: new pricing structure (component breakdown instead of packages), packageItems with image upload per card, why/accordion CMS fields - GroupVisits: all text/prices/images CMS-editable (heroDescription, amenities, featureImages, workingHours, price, bottomImages, etc.) - DyvoLis: fixed 404 (seed location record), combo tickets now show (600/1500/1800/2000) - ThankYou: DyvoLis topiary background, 'Купити квиток' button text - Tariffs: updated to match Figma (300/150/300/50 dyno + 4 combo variants) - Seed: add DyvoLis location, correct hero text and section titles for home Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
334 lines
12 KiB
TypeScript
334 lines
12 KiB
TypeScript
import 'dotenv/config'
|
||
import { getPayload } from 'payload'
|
||
import config from '../payload.config.js'
|
||
|
||
async function seed(): Promise<void> {
|
||
const payload = await getPayload({ config })
|
||
|
||
// Admin user
|
||
const { totalDocs } = await payload.find({
|
||
collection: 'users',
|
||
limit: 1,
|
||
overrideAccess: true,
|
||
})
|
||
|
||
if (totalDocs === 0) {
|
||
await payload.create({
|
||
collection: 'users',
|
||
data: {
|
||
email: 'admin@shumiland.ua',
|
||
password: 'changeMe123!',
|
||
name: 'Admin',
|
||
role: 'admin',
|
||
},
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Created admin user: admin@shumiland.ua / changeMe123!')
|
||
} else {
|
||
console.log('Users already exist, skipping user seed.')
|
||
}
|
||
|
||
// Home page global with real content
|
||
await payload.updateGlobal({
|
||
slug: 'home-page',
|
||
data: {
|
||
hero: {
|
||
title: 'Започаткуйте традицію:',
|
||
subtitle: 'щороку фотографуйтесь біля улюбленого динозавра',
|
||
ctaLabel: 'Купити квиток',
|
||
ctaHref: '/kvytky',
|
||
},
|
||
sectionTitles: {
|
||
locations: 'ЛАСКАВО ПРОСИМО ДО ШУМІЛЕНДУ',
|
||
whyParents: 'ЧОМУ БАТЬКИ ОБИРАЮТЬ ШУМІЛЕНД',
|
||
birthday: 'ДЕНЬ НАРОДЖЕННЯ В ШУМІЛЕНДІ',
|
||
gallery: 'ФОТОГАЛЕРЕЯ',
|
||
reviews: 'ВІДГУКИ',
|
||
news: 'НОВИНИ',
|
||
},
|
||
locations: [
|
||
{
|
||
name: 'ДиноПарк',
|
||
shortDesc: 'Прогуляйтесь серед реалістичних динозаврів у повний зріст',
|
||
href: '/lokatsii',
|
||
},
|
||
{
|
||
name: 'Диво Ліс',
|
||
shortDesc: 'Чарівний ліс з інтерактивними атракціонами та мотузковими парками',
|
||
href: '/lokatsii',
|
||
},
|
||
{
|
||
name: 'Дзеркальний Лабіринт',
|
||
shortDesc: 'Захоплюючий лабіринт з дзеркалами та оптичними ілюзіями',
|
||
href: '/lokatsii',
|
||
},
|
||
],
|
||
features: [
|
||
{
|
||
icon: '🦕',
|
||
title: 'Безпека',
|
||
description: 'Атракціони сертифіковані, майданчик під постійним наглядом',
|
||
},
|
||
{ icon: '🌲', title: 'Природа', description: 'Парк розташований серед живої природи' },
|
||
{
|
||
icon: '🎉',
|
||
title: 'Свята',
|
||
description: 'Дні народження, корпоративи та шкільні екскурсії',
|
||
},
|
||
{
|
||
icon: '🎟️',
|
||
title: 'Квитки онлайн',
|
||
description: 'Купуйте квитки онлайн без черги на касі',
|
||
},
|
||
{
|
||
icon: '🍕',
|
||
title: 'Кафе та їжа',
|
||
description: 'Власне кафе з дитячим меню та легкими закусками',
|
||
},
|
||
{ icon: '🅿️', title: 'Парковка', description: 'Безкоштовна парковка для відвідувачів' },
|
||
],
|
||
news: { title: 'Новини', limit: 3 },
|
||
} as never,
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Seeded home-page global')
|
||
|
||
// Header global
|
||
await payload.updateGlobal({
|
||
slug: 'header',
|
||
data: {
|
||
navLinks: [
|
||
{ label: 'Головна', href: '/' },
|
||
{ label: 'Локації', href: '/lokatsii' },
|
||
{ label: 'Блог', href: '/blog' },
|
||
{ label: 'Дні народження', href: '/dni-narodzhennia' },
|
||
{ label: 'Групові відвідування', href: '/grupovi-vidviduvannia' },
|
||
],
|
||
ctaLabel: 'Купити квиток',
|
||
ctaHref: '/kvytky',
|
||
} as never,
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Seeded header global')
|
||
|
||
// Footer global
|
||
await payload.updateGlobal({
|
||
slug: 'footer',
|
||
data: { copyrightText: `© Шуміленд ${new Date().getFullYear()}` } as never,
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Seeded footer global')
|
||
|
||
// Site settings
|
||
await payload.updateGlobal({
|
||
slug: 'site-settings',
|
||
data: {
|
||
siteName: 'Шуміленд',
|
||
siteURL: process.env['NEXT_PUBLIC_SITE_URL'] ?? 'https://shumiland.ua',
|
||
} as never,
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Seeded site-settings global')
|
||
|
||
// Remaining globals — initialize empty
|
||
for (const slug of ['checkout-page', 'thank-you-page'] as const) {
|
||
try {
|
||
await payload.updateGlobal({ slug, data: {} as never, overrideAccess: true })
|
||
console.log(`Initialized global: ${slug}`)
|
||
} catch (err) {
|
||
console.warn(`Could not initialize global ${slug}:`, err)
|
||
}
|
||
}
|
||
|
||
// Blog posts
|
||
const { totalDocs: postCount } = await payload.find({
|
||
collection: 'blog-posts',
|
||
limit: 1,
|
||
overrideAccess: true,
|
||
})
|
||
if (postCount === 0) {
|
||
const posts = [
|
||
{
|
||
title: 'Сезон динозаврів відкрито!',
|
||
slug: 'sezon-dynozavriv-vidkryto',
|
||
excerpt: 'Шуміленд вітає нових мешканців ДиноПарку — зустрічайте 12 нових динозаврів!',
|
||
status: 'published' as const,
|
||
publishedAt: new Date('2025-04-01').toISOString(),
|
||
},
|
||
{
|
||
title: 'Весняні канікули в Шуміленді',
|
||
slug: 'vesniani-kanikuly-v-shumilenди',
|
||
excerpt:
|
||
'Проведіть весняні канікули незабутньо! Спеціальні активності щодня з 28 березня по 6 квітня.',
|
||
status: 'published' as const,
|
||
publishedAt: new Date('2025-03-20').toISOString(),
|
||
},
|
||
{
|
||
title: 'Нова локація: Тир з призами',
|
||
slug: 'nova-lokatsiya-tyr-z-pryzamy',
|
||
excerpt:
|
||
'Відтепер у Шуміленді є новий Тир з призами — точний постріл приносить реальний виграш!',
|
||
status: 'published' as const,
|
||
publishedAt: new Date('2025-03-10').toISOString(),
|
||
},
|
||
]
|
||
for (const post of posts) {
|
||
await payload.create({ collection: 'blog-posts', data: post as never, overrideAccess: true })
|
||
}
|
||
console.log('Seeded blog posts')
|
||
} else {
|
||
console.log('Blog posts already exist, skipping.')
|
||
}
|
||
|
||
// Tariffs — update to match Figma designs
|
||
{
|
||
// Delete old tariffs and re-seed with correct data
|
||
const existing = await payload.find({ collection: 'tariffs', limit: 100, overrideAccess: true })
|
||
for (const t of existing.docs) {
|
||
await payload.delete({ collection: 'tariffs', id: t.id, overrideAccess: true })
|
||
}
|
||
|
||
const tariffs = [
|
||
// Individual dino-park tickets (shown on both Dino and DyvoLis pages)
|
||
{
|
||
ezy_id: 1001,
|
||
last_synced_name: 'Вхід до Динопарку',
|
||
display_name: 'Вхід до Динопарку',
|
||
last_synced_price: 300,
|
||
category_tag: 'dyno',
|
||
sort: 1,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 1002,
|
||
last_synced_name: 'Звичайна екскурсія',
|
||
display_name: 'Звичайна екскурсія',
|
||
last_synced_price: 150,
|
||
category_tag: 'dyno',
|
||
sort: 2,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 1003,
|
||
last_synced_name: 'Палеонтологічна екскурсія',
|
||
display_name: 'Палеонтологічна екскурсія',
|
||
last_synced_price: 300,
|
||
category_tag: 'dyno',
|
||
sort: 3,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 1004,
|
||
last_synced_name: 'ДиноРодо',
|
||
display_name: 'ДиноРодо',
|
||
last_synced_price: 50,
|
||
category_tag: 'dyno',
|
||
sort: 4,
|
||
visible: true,
|
||
},
|
||
// Combo tickets
|
||
{
|
||
ezy_id: 3001,
|
||
last_synced_name: 'Комбо на 1 людину',
|
||
display_name: 'Комбо на 1 людину',
|
||
last_synced_price: 600,
|
||
category_tag: 'combo',
|
||
sort: 1,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 3002,
|
||
last_synced_name: 'Комбо на 3 людини',
|
||
display_name: 'Комбо на 3 людини',
|
||
last_synced_price: 1500,
|
||
category_tag: 'combo',
|
||
sort: 2,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 3003,
|
||
last_synced_name: 'Комбо на 4 людини',
|
||
display_name: 'Комбо на 4 людини',
|
||
last_synced_price: 1800,
|
||
category_tag: 'combo',
|
||
sort: 3,
|
||
visible: true,
|
||
},
|
||
{
|
||
ezy_id: 3004,
|
||
last_synced_name: 'Комбо на 5 людин',
|
||
display_name: 'Комбо на 5 людин',
|
||
last_synced_price: 2000,
|
||
category_tag: 'combo',
|
||
sort: 4,
|
||
visible: true,
|
||
},
|
||
]
|
||
for (const t of tariffs) {
|
||
await payload.create({ collection: 'tariffs', data: t as never, overrideAccess: true })
|
||
}
|
||
console.log('Seeded tariffs (updated to match Figma)')
|
||
}
|
||
|
||
// Locations
|
||
const { totalDocs: locCount } = await payload.find({
|
||
collection: 'locations',
|
||
limit: 1,
|
||
overrideAccess: true,
|
||
})
|
||
if (locCount === 0) {
|
||
await payload.create({
|
||
collection: 'locations',
|
||
data: {
|
||
name: 'Диво Ліс',
|
||
slug: 'dyvolis',
|
||
tagline: 'Казковий світ топіарних фігур',
|
||
shortDesc: 'Топіарні фігури з живих рослин — 60+ персонажів улюблених казок у живому лісі.',
|
||
showInMenu: true,
|
||
showOnHome: true,
|
||
showDetailPage: true,
|
||
sort: 2,
|
||
heroStat: '60+',
|
||
heroStatLabel: 'експонатів з безпечних для дітей матеріалів',
|
||
heroTips: [
|
||
{ text: 'Унікальна ландшафтна композиція з місцями для відпочинку' },
|
||
{ text: 'Повна свобода переміщення — без заборон' },
|
||
],
|
||
galleryQuote:
|
||
'Це місце — де малеча зустрічає героїв улюблених казок. Простір справжнього дитинства.',
|
||
whyVisitTitle: 'Чому варто відвідати ДивоЛіс',
|
||
whyVisitItems: [
|
||
{
|
||
title: 'Простір для спільної фантазії',
|
||
description:
|
||
'Вигадуйте казки та пригоди разом із дітьми — кожна топіарна фігурка стає новою сторінкою вашої власної чарівної історії.',
|
||
},
|
||
{
|
||
title: 'Казковий ліс у справжньому лісі',
|
||
description:
|
||
'Ми створили локацію, в якій гармонійно поєднуються казкові фігури та жива природа. Прогулянка лісом ще не була такою захопливою.',
|
||
},
|
||
{
|
||
title: 'Магічні кадри для сімейного альбому',
|
||
description:
|
||
'Унікальні топіарні декорації та яскраві персонажі — ідеальний фон для незабутніх сімейних фотографій.',
|
||
},
|
||
],
|
||
workingHours: 'щодня з 11:00 до 20:00',
|
||
comboDescription:
|
||
'Динопарк + Диволіс із казковими топіарними фігурами + Дзеркальний лабіринт',
|
||
} as never,
|
||
overrideAccess: true,
|
||
})
|
||
console.log('Created DyvoLis location')
|
||
} else {
|
||
console.log('Locations already exist, skipping.')
|
||
}
|
||
|
||
process.exit(0)
|
||
}
|
||
|
||
seed().catch((err) => {
|
||
console.error('Seed failed:', err)
|
||
process.exit(1)
|
||
})
|