fix(frontend): render locations shortDesc via RichText, regenerate payload types/schema
Some checks are pending
CI / Type Check (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Unit Tests (push) Waiting to run
Deploy / Build & Push Image (push) Waiting to run
Deploy / Deploy to VPS (push) Blocked by required conditions

shortDesc is richText since 0021 but /lokatsii and the home Locations section
still rendered it as a string (object-as-React-child crash once data exists).
payload-types.ts and payload-generated-schema.ts were stale since the
conversion commits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-06-12 10:21:55 +01:00
parent bc3eb90fb9
commit dc5cebdc74
6 changed files with 807 additions and 529 deletions

View file

@ -1,5 +1,6 @@
import type { Metadata } from 'next'
import Link from 'next/link'
import { RichText } from '@payloadcms/richtext-lexical/react'
import { getPayload } from 'payload'
import configPromise from '@payload-config'
import { PageHero } from '@/components/ui/PageHero'
@ -9,6 +10,8 @@ import type { LocationCMS, Media } from '@/types/globals'
export const revalidate = 60
type RichTextData = Parameters<typeof RichText>[0]['data']
async function getPageData() {
try {
const payload = await getPayload({ config: configPromise })
@ -147,12 +150,14 @@ export default async function LocationsPage() {
>
{loc.name}
</h2>
<p
className="text-[16px] leading-relaxed text-white/80"
style={{ fontFamily: 'var(--font-montserrat, Montserrat), sans-serif' }}
>
{loc.shortDesc}
</p>
{loc.shortDesc ? (
<div
className="text-[16px] leading-relaxed text-white/80"
style={{ fontFamily: 'var(--font-montserrat, Montserrat), sans-serif' }}
>
<RichText data={loc.shortDesc as RichTextData} />
</div>
) : null}
<div className="mt-2 flex flex-wrap gap-3">
{detailHref && (
<Link

View file

@ -1,7 +1,10 @@
import { RichText } from '@payloadcms/richtext-lexical/react'
import { LocationsCardStack } from './LocationsCardStack'
import type { LocationData } from './LocationsSlider'
import type { LocationCMS, Media } from '@/types/globals'
type RichTextData = Parameters<typeof RichText>[0]['data']
function getMediaUrl(img: Media | string | null | undefined): string | null {
if (!img) return null
if (typeof img === 'string') return img
@ -79,7 +82,7 @@ export function Locations({ data, title }: LocationsProps) {
name: loc.name,
slug: loc.slug,
tagline: loc.tagline ?? '',
description: loc.shortDesc ?? '',
description: loc.shortDesc ? <RichText data={loc.shortDesc as RichTextData} /> : '',
image:
getMediaUrl(loc.image) ??
FALLBACK_IMAGES[loc.slug] ??

View file

@ -1,4 +1,5 @@
/* eslint-disable @next/next/no-img-element */
import type { ReactNode } from 'react'
import Link from 'next/link'
import { BtnGradient } from '@/components/ui/BtnGradient'
@ -6,7 +7,7 @@ export interface LocationData {
name: string
slug: string
tagline: string
description: string
description: ReactNode
image: string
href: string
}

File diff suppressed because it is too large Load diff

View file

@ -553,7 +553,21 @@ export interface Location {
name: string
slug: string
tagline?: string | null
shortDesc?: string | null
shortDesc?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
description?: {
root: {
type: string
@ -611,7 +625,21 @@ export interface Location {
whyVisitItems?:
| {
title: string
description: string
description: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
id?: string | null
}[]
| null
@ -1712,7 +1740,21 @@ export interface HomePage {
backgroundImageUrl?: string | null
type?: ('brand' | 'location') | null
title: string
subtitle?: string | null
subtitle?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
ctaLabel?: string | null
ctaHref?: string | null
id?: string | null
@ -1720,7 +1762,21 @@ export interface HomePage {
| null
hero?: {
title?: string | null
subtitle?: string | null
subtitle?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
ctaLabel?: string | null
ctaHref?: string | null
backgroundVideo?: string | null
@ -1775,7 +1831,21 @@ export interface HomePage {
items?:
| {
title?: string | null
description?: string | null
description?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
id?: string | null
}[]
| null
@ -1803,7 +1873,21 @@ export interface HomePage {
src?: string | null
}
birthdayIntro?: {
text?: string | null
text?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
/**
* Фоновий паттерн для не-featured карток (зелений фон).
*/
@ -1818,7 +1902,21 @@ export interface HomePage {
/**
* Підзаголовок секції новин на головній.
*/
subtitle?: string | null
subtitle?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
limit?: number | null
}
faq?: {
@ -1826,7 +1924,21 @@ export interface HomePage {
items?:
| {
question: string
answer: string
answer: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
id?: string | null
}[]
| null
@ -2015,6 +2127,7 @@ export interface Footer {
*/
export interface SiteSetting {
id: number
gtmId?: string | null
ga4Id?: string | null
binotelId?: string | null
telegramChatId?: string | null
@ -2050,9 +2163,46 @@ export interface GroupVisitsPage {
heroImage?: (number | null) | Media
heroTitle?: string | null
heroSubtitle?: string | null
heroDescription?: string | null
/**
* Порожнє стандарт 56px. Мобільний масштабується автоматично.
*/
heroTitleSize?: number | null
/**
* Порожнє стандарт 24px.
*/
heroSubtitleSize?: number | null
heroFont?: ('montserrat' | 'poppins' | 'inter') | null
heroDescription?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
heroCta?: string | null
featureText?: string | null
featureText?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
/**
* Завантажте 2 фото відображаються перекошено side by side
*/
@ -2082,8 +2232,36 @@ export interface GroupVisitsPage {
priceNote?: string | null
priceMinPeople?: string | null
priceCta?: string | null
priceDescription?: string | null
bottomText?: string | null
priceDescription?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
bottomText?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
bottomImages?:
| {
image: number | Media
@ -2120,7 +2298,21 @@ export interface BirthdayPage {
packageItems?:
| {
title: string
description: string
description: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
/**
* Фото для картки
*/
@ -2137,7 +2329,21 @@ export interface BirthdayPage {
whyItems?:
| {
title: string
description: string
description: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
id?: string | null
}[]
| null
@ -2188,7 +2394,21 @@ export interface TicketsPage {
* Напр. «600 »
*/
price: string
description?: string | null
description?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
featured?: boolean | null
/**
* Напр. «Найпопулярніший»
@ -2225,7 +2445,21 @@ export interface TicketsPage {
id?: string | null
}[]
| null
benefitsFootnote?: string | null
benefitsFootnote?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
meta?: {
title?: string | null
description?: string | null
@ -2282,7 +2516,21 @@ export interface BlogIndexPage {
export interface DinosaurPage {
id: number
heroTitle?: string | null
heroDescription?: string | null
heroDescription?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
/**
* Число у круглому бейджі (наприклад "26")
*/
@ -2340,7 +2588,21 @@ export interface DinosaurPage {
}[]
| null
activitiesTitle?: string | null
activitiesDescription?: string | null
activitiesDescription?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
activities?:
| {
name: string
@ -2348,7 +2610,21 @@ export interface DinosaurPage {
* Наприклад: 150 грн
*/
price?: string | null
description?: string | null
description?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
image?: (number | null) | Media
href?: string | null
id?: string | null
@ -2358,7 +2634,21 @@ export interface DinosaurPage {
whyVisitItems?:
| {
title: string
description: string
description: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
}
id?: string | null
}[]
| null
@ -2397,19 +2687,75 @@ export interface LegalPage {
id: number
privacy?: {
title?: string | null
content?: string | null
content?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
}
terms?: {
title?: string | null
content?: string | null
content?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
}
offer?: {
title?: string | null
content?: string | null
content?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
}
dataProcessing?: {
title?: string | null
content?: string | null
content?: {
root: {
type: string
children: {
type: any
version: number
[k: string]: unknown
}[]
direction: ('ltr' | 'rtl') | null
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
indent: number
version: number
}
[k: string]: unknown
} | null
}
updatedAt?: string | null
createdAt?: string | null
@ -2651,6 +2997,7 @@ export interface FooterSelect<T extends boolean = true> {
* via the `definition` "site-settings_select".
*/
export interface SiteSettingsSelect<T extends boolean = true> {
gtmId?: T
ga4Id?: T
binotelId?: T
telegramChatId?: T
@ -2677,6 +3024,9 @@ export interface GroupVisitsPageSelect<T extends boolean = true> {
heroImage?: T
heroTitle?: T
heroSubtitle?: T
heroTitleSize?: T
heroSubtitleSize?: T
heroFont?: T
heroDescription?: T
heroCta?: T
featureText?: T

View file

@ -168,7 +168,7 @@ export interface LocationCMS {
name: string
slug: string
tagline?: string | null
shortDesc?: string | null
shortDesc?: unknown
description?: unknown
image?: Media | string | null
gallery?: { image?: Media | string | null }[] | null