- beforeChange hook: when ezy_id changes, fetch tariff from ezy API,
populate last_synced_name/price/at; throw if ezy_id not found
- POST /api/tariffs/[id]/sync-ezy: re-sync a specific tariff on demand
- SyncEzyButton: custom Payload UI field component with loading/ok/error states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Field was readOnly in UI but protected by access control already.
Removing readOnly lets admins clear ezy_id when a tariff isn't in ezy yet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
buildComboCards now uses ezy tariffs as primary source when available.
Static cards are only used for descriptions and as fallback when ezy is down.
This removes test/placeholder cards and fixes mismatched prices from CMS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
At Docker build time Next.js renders /kvytky statically before the server
starts, so getTariffs() gets empty array. KvytkyTicketsClient now fetches
/api/tickets/tariffs on mount when serverTariffs is empty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- revalidatePath + kvytky page: use http://localhost:3000 for server-to-self
fetches (was using NEXT_PUBLIC_SITE_URL with self-signed HTTPS → Node rejected cert)
- Footer: strip hostname from Payload media URL (same fix as Header)
- DyvoLisTickets: show zone ticket named 'Диво' for individual dyvolis tickets
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Header: strip hostname from Payload media URL in resolveLogoUrl (was showing IP)
- DyvoLisTickets: prefer 'dyvolis' category over 'dyno' for single tickets
- DyvoLisWhyVisit: narrow accordion (628→480px), remove video max-w cap
- migration 0017: seed 3 extra birthday package items (rows 4-6) so CMS block is editable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add googleReviewUrl text field to HomePage.sectionTitles group so editors
can update the Google review link without a deploy. Falls back to the
hardcoded URL when the field is empty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Copy original lossless PNG to public/images/locations/ as hero bg fallback
(bypasses Payload WebP compression entirely when CMS has no image)
- Fallback heroBgUrl to static PNG so the banner always renders
- Raise Media collection WebP quality: 82→88 (mobile/tablet), 85→92 (original+desktop)
Future re-uploads will have noticeably better quality
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded video-only VideoSlider with SideSlider that accepts
any images array. If CMS sideGallery images exist, show them without
the play button; otherwise fall back to static video thumbnail with
play button as before.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allow editors to upload custom background pattern images for the birthday
section cards (green cards and featured orange card) from the CMS admin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
extraItems was simplified to always use FALLBACK_EXTRA_ITEMS in the
previous refactor, breaking CMS editability for Костюмованих ведучих,
Аквагрим, Затишну альтанку. Restore CMS-first logic: use
cmsPackageItems[3+] when available, fallback otherwise.
Replace wrong gallery-shumi-6.webp (DyvoLis topiary arch) with null
so the placeholder SVG shows until a real photo is uploaded via CMS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
heroBgUrl was never populated — page.tsx queried only the dinosaur-page
global and didn't read the Location's heroBackground upload field.
Now fetches the locations collection in parallel and passes heroBgUrl to
DinoPageContent, which already handles the conditional hero-bg render.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove 10 CMS global fields that had data+fallbacks but were never rendered:
workingHours, pricingPackages, entrancePrices, freeInclusions, entertainmentPackages
plus heroCta, packageSectionSubtitle, and their title fields.
In page.tsx: remove TicketCard component, TicketCardData interface, and all
corresponding variable declarations (~80 lines). Simplify extraItems to always
use FALLBACK_EXTRA_ITEMS (removes fragile cmsHasPhotos && length>3 condition).
Fix typo in packageItems defaultValue: 'ДинопаркArk' → 'ДиноПарк'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DinoPageContent: add isolation:isolate to .hero so z-index:-1 hero-bg
is visible (was painted behind the page background color)
- Gallery: pad CMS images with static fallbacks when fewer than 9 entries,
so the slider always shows a full set even if CMS only has 2 photos
- Birthday page: replace null altanka image with gallery-shumi-6.webp placeholder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Payload 3 + PostgreSQL rejects string IDs for upload field relationships;
helpers were returning String(doc.id) which caused ValidationError on
every location/post create that referenced an already-existing media record.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On video upload, fires FFmpeg in the background to re-encode to
H.264/AAC with CRF 28 (50-80% size reduction vs phone recordings).
Adds FFmpeg to runner Docker image. Original file is replaced
in-place so URL never changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace text src/poster in whyVideos with media upload pickers so
admins can upload video files directly from the CMS instead of
entering raw URLs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
extraItems now uses slice(3) without end limit — items 4-N all appear
in the "Також можна додатково замовити" grid instead of being silently dropped.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Admins can now upload custom pattern images for green and orange
pricing cards via Home Page → День народження → Паттерн зелених/оранжевої карток.
Falls back to static /images/figma/card-pattern-*.png if not set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove DyvoLisPage global from Payload config (was not connected to website,
website reads from locations collection instead)
- Fix docker-compose.prod.yml migrate service volume path:
/app/migrations -> /migrations to match Dockerfile.migrator WORKDIR
- Wrap seed route in try/catch to return proper error instead of silent 500
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add FAQ accordion section (FAQ.tsx) after Reviews on home page
- Add faq group field to HomePage global (title + items array)
- Add HomePageFaq types to types/globals.ts
- Seed whyParents.items with 6 items from static fallback texts
- Seed faq with 6 Q&A items about the park
- Migration 0012: create home_page_faq_items table for Payload array field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CookieBanner: bottom-fixed, stores consent in localStorage,
links to privacy policy, green brand colors
- Privacy policy + Data processing: replace GDPR as primary
reference with ЗУ «Про захист персональних даних» № 2297-VI,
correct article references (ст. 6, 8, 16, 24 Закону),
supervisory authority: Уповноважений ВРУ з прав людини
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CheckoutPage: pass instructions and terms from CMS global to frontend;
instructions shown above form, terms below button
- ThankYouPage: fetch title/message/contactPhone/contactEmail from CMS;
contact info shown if set, falls back to hardcoded defaults
- Hero: use backgroundImageUrl text field as fallback for media upload
- Add lexicalToText util for plain-text extraction from Payload Lexical JSON
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add heroSlides array to HomePage global (title, subtitle, type,
backgroundImage, ctaLabel, ctaHref per slide)
- Hero.tsx fetches slides from CMS, passes as props to HeroSlider
- HeroSlider accepts optional slides prop, falls back to static default
- No visible change until slides are added in admin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4-layer box-shadow: 40→100→180→280px blur with decreasing opacity
creates smooth fade from video edge into the green background.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>