- Change heroDescription, featureText, bottomText fields from textarea to richText (Lexical)
in GroupVisitsPage global so admins can format paragraphs and bold text in admin UI
- Render rich text fields with <RichText> component on the frontend
- Migration: ALTER varchar → jsonb for the three fields; UPDATE header cta_href and
birthday_page_pricing_packages cta_href from /kvytky to /payments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously filtered only categoryTag==='dyno'; EZY returns 'zone'
for Динопарк. Mirrors the same pattern already used in DyvoLisTickets.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /payments now serves the main ticket catalog (was /kvytky)
- /checkout serves the legacy single-tariff checkout form
- All /kvytky references updated across components, layout, lib, seed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hide img overlay on .playing so video is visible when playing
- Add controls on play click
- When no poster: show video directly with preload=metadata (native first frame)
- why-grid left col 704px → minmax(0,500px) so video column gets more space
- video-card: flex fills available width, absolute positioning for img/video stack
- aspect-ratio 9:16 for portrait video
- Strip absolute origin from video/poster src (fixes cert error from shumi.ai-impress.com)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Background-image on the element is always behind content — no overlay div
needed. card-pattern-arcs.svg (360×360 arc circles, #70b030 strokes)
is visible on dark green without opacity tricks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PageHero: swap opaque green fill for subtle black gradient so hero photo shows through
- Locations cards: add card-wave-green.svg pattern on top of solid green bg
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On mobile (< 768px) the stacked cards had rotated/offset transforms
that were clipped by the overflow-hidden container. Now mid/back cards
are hidden (opacity 0) and the front card renders flat — no clipping.
Desktop stack layout is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move hero title plate to the bottom of the photo so faces stay visible
- Admin can now set hero title/subtitle size (px) and font
(Montserrat/Poppins/Inter); mobile scales via clamp()
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PNG sources re-encoded losslessly, oversized JPGs at q92:
22 files, 13.6MB -> 4.5MB. JPGs that would grow after
re-encoding are kept as-is. References updated; originals
kept on disk since CMS rows may still point at them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On narrow screens the cover-cropped hero photo lands under the
heading text, making it unreadable. Add a light gradient overlay
behind the text at <=640px.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Container now full-width with overflow-hidden on mobile; cards fill container.
Fixed w-[520px] was overflowing 360px viewport by 160px.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add checkbox field to control whether a location card appears on /lokatsii.
Default true so existing entries remain visible. Filter added to getLocations query.
Migration 20260610_140000 adds show_on_lokatsii boolean column with DEFAULT true.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
ALTER TABLE home_page + _home_page_v to add the new varchar column
for the Google review URL field added to sectionTitles group.
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>
Terminates HTTPS on port 443 with self-signed cert, redirects :80 to HTTPS.
Required for Payload admin CSRF (browsers only send Sec-Fetch-Site in secure context).
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>
Switch prod setup from traefik (external network) to self-contained
Caddy container that terminates HTTPS at the IP. Self-signed cert is
needed so browsers send Sec-Fetch-Site (only in secure contexts) and
Payload admin cookie auth works over http-by-IP won't.
- Add caddy:2-alpine service with ports 80/443 and Caddyfile mount
- Mount ./certs volume to app (NODE_EXTRA_CA_CERTS) so next/image can
optimise absolute https://IP media URLs without cert rejection
- Remove traefik-public external network + labels
- Update build arg NEXT_PUBLIC_SITE_URL to https://147.135.209.100
- Add postgres-data/backups/certs to .dockerignore
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 media served from the deployment host (e.g. http://147.135.209.100)
was blocked by Next.js image optimiser with 400 because the host was absent
from remotePatterns. Now parsed at build time from NEXT_PUBLIC_SITE_URL so
it works for any environment (localhost, IP, or domain) without hardcoding.
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>