Shumiland/src/seed.ts
Vadym Samoilenko 6863f5022d feat(pages): redesign all 6 pages to match Figma designs with full CMS coverage
- 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>
2026-05-28 16:27:24 +01:00

334 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
})