diff --git a/payload.config.ts b/payload.config.ts index 799cd91..3822b06 100644 --- a/payload.config.ts +++ b/payload.config.ts @@ -35,6 +35,7 @@ import { TicketsPage } from './src/globals/TicketsPage' import { LocationsPage } from './src/globals/LocationsPage' import { BlogIndexPage } from './src/globals/BlogIndexPage' import { DinosaurPage } from './src/globals/DinosaurPage' +import { LegalPages } from './src/globals/LegalPages' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -90,6 +91,7 @@ export default buildConfig({ LocationsPage, BlogIndexPage, DinosaurPage, + LegalPages, ], plugins: [ diff --git a/src/app/(frontend)/data-processing/page.tsx b/src/app/(frontend)/data-processing/page.tsx new file mode 100644 index 0000000..425f38a --- /dev/null +++ b/src/app/(frontend)/data-processing/page.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next' +import { getPayload } from 'payload' +import configPromise from '@payload-config' +import { LegalPageLayout } from '../legal/LegalPage' +import { DATA_PROCESSING_DEFAULT } from '@/lib/legalDefaults' + +export const revalidate = 3600 +export const dynamicParams = true + +export const metadata: Metadata = { + title: 'Обробка персональних даних — Шуміленд', +} + +async function getData() { + try { + const payload = await getPayload({ config: configPromise }) + const data = await payload.findGlobal({ slug: 'legal-pages', depth: 0 }) + return data?.dataProcessing ?? null + } catch { + return null + } +} + +export default async function DataProcessingPage() { + const data = await getData() + return ( + + ) +} diff --git a/src/app/(frontend)/legal/LegalPage.tsx b/src/app/(frontend)/legal/LegalPage.tsx new file mode 100644 index 0000000..8aa7eb2 --- /dev/null +++ b/src/app/(frontend)/legal/LegalPage.tsx @@ -0,0 +1,28 @@ +const FONT = { fontFamily: 'var(--font-montserrat, Montserrat), sans-serif' } + +interface Props { + title: string + content: string +} + +export function LegalPageLayout({ title, content }: Props) { + return ( +
+
+
+

+ {title} +

+
+
+
+
+ {content} +
+
+
+ ) +} diff --git a/src/app/(frontend)/oferta/page.tsx b/src/app/(frontend)/oferta/page.tsx new file mode 100644 index 0000000..a31e344 --- /dev/null +++ b/src/app/(frontend)/oferta/page.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next' +import { getPayload } from 'payload' +import configPromise from '@payload-config' +import { LegalPageLayout } from '../legal/LegalPage' +import { OFFER_DEFAULT } from '@/lib/legalDefaults' + +export const revalidate = 3600 +export const dynamicParams = true + +export const metadata: Metadata = { + title: 'Публічна оферта — Шуміленд', +} + +async function getData() { + try { + const payload = await getPayload({ config: configPromise }) + const data = await payload.findGlobal({ slug: 'legal-pages', depth: 0 }) + return data?.offer ?? null + } catch { + return null + } +} + +export default async function OfertaPage() { + const data = await getData() + return ( + + ) +} diff --git a/src/app/(frontend)/privacy-policy/page.tsx b/src/app/(frontend)/privacy-policy/page.tsx new file mode 100644 index 0000000..705d759 --- /dev/null +++ b/src/app/(frontend)/privacy-policy/page.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next' +import { getPayload } from 'payload' +import configPromise from '@payload-config' +import { LegalPageLayout } from '../legal/LegalPage' +import { PRIVACY_DEFAULT } from '@/lib/legalDefaults' + +export const revalidate = 3600 +export const dynamicParams = true + +export const metadata: Metadata = { + title: 'Політика конфіденційності — Шуміленд', +} + +async function getData() { + try { + const payload = await getPayload({ config: configPromise }) + const data = await payload.findGlobal({ slug: 'legal-pages', depth: 0 }) + return data?.privacy ?? null + } catch { + return null + } +} + +export default async function PrivacyPage() { + const data = await getData() + return ( + + ) +} diff --git a/src/app/(frontend)/terms-of-use/page.tsx b/src/app/(frontend)/terms-of-use/page.tsx new file mode 100644 index 0000000..e91eec9 --- /dev/null +++ b/src/app/(frontend)/terms-of-use/page.tsx @@ -0,0 +1,32 @@ +import type { Metadata } from 'next' +import { getPayload } from 'payload' +import configPromise from '@payload-config' +import { LegalPageLayout } from '../legal/LegalPage' +import { TERMS_DEFAULT } from '@/lib/legalDefaults' + +export const revalidate = 3600 +export const dynamicParams = true + +export const metadata: Metadata = { + title: 'Умови використання — Шуміленд', +} + +async function getData() { + try { + const payload = await getPayload({ config: configPromise }) + const data = await payload.findGlobal({ slug: 'legal-pages', depth: 0 }) + return data?.terms ?? null + } catch { + return null + } +} + +export default async function TermsPage() { + const data = await getData() + return ( + + ) +} diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index c20f668..6c46f72 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -194,6 +194,27 @@ export async function Footer() { {/* Copyright */}
+ {/* Legal links */} +

{copyright}

diff --git a/src/globals/LegalPages.ts b/src/globals/LegalPages.ts new file mode 100644 index 0000000..cd7dc53 --- /dev/null +++ b/src/globals/LegalPages.ts @@ -0,0 +1,49 @@ +import type { GlobalConfig } from 'payload' +import { isAdminOrEditor } from '@/access/isAdminOrEditor' +import { revalidateGlobalAfterChange } from '@/hooks/revalidatePath' + +export const LegalPages: GlobalConfig = { + slug: 'legal-pages', + label: 'Юридичні сторінки', + admin: { group: 'Сторінки' }, + access: { read: () => true, update: isAdminOrEditor }, + hooks: { afterChange: [revalidateGlobalAfterChange] }, + fields: [ + { + name: 'privacy', + type: 'group', + label: 'Політика конфіденційності', + fields: [ + { name: 'title', type: 'text', defaultValue: 'Політика конфіденційності' }, + { name: 'content', type: 'textarea', label: 'Текст сторінки' }, + ], + }, + { + name: 'terms', + type: 'group', + label: 'Умови використання', + fields: [ + { name: 'title', type: 'text', defaultValue: 'Умови використання' }, + { name: 'content', type: 'textarea', label: 'Текст сторінки' }, + ], + }, + { + name: 'offer', + type: 'group', + label: 'Публічна оферта', + fields: [ + { name: 'title', type: 'text', defaultValue: 'Публічна оферта' }, + { name: 'content', type: 'textarea', label: 'Текст сторінки' }, + ], + }, + { + name: 'dataProcessing', + type: 'group', + label: 'Обробка персональних даних', + fields: [ + { name: 'title', type: 'text', defaultValue: 'Обробка персональних даних' }, + { name: 'content', type: 'textarea', label: 'Текст сторінки' }, + ], + }, + ], +} diff --git a/src/lib/legalDefaults.ts b/src/lib/legalDefaults.ts new file mode 100644 index 0000000..2af1033 --- /dev/null +++ b/src/lib/legalDefaults.ts @@ -0,0 +1,250 @@ +const COMPANY = 'ТОВ «ТЕХНОСМАРТ УКРАЇНА»' +const EDRPOU = '40166430' +const ADDRESS = 'Житомирська обл., м. Житомир, вул. Мала Бердичівська, буд. 16а, каб. 3' +const SITE = 'https://shumiland.com.ua' +const EMAIL = 'smart.office@proton.me' +const PHONE = '+380 67 144 3635' + +export const PRIVACY_DEFAULT = `Дата набрання чинності: 1 серпня 2025 р. + +1. ЗАГАЛЬНІ ПОЛОЖЕННЯ + +Цей документ є Політикою конфіденційності ${COMPANY} (далі — «Компанія», «ми»), що регулює порядок збору, обробки та захисту персональних даних користувачів вебсайту ${SITE} (далі — «Сайт») відповідно до Закону України «Про захист персональних даних» та Регламенту ЄС 2016/679 (GDPR). + +2. ХТО МИ + +Оператор персональних даних: +${COMPANY}, ЄДРПОУ ${EDRPOU} +Юридична адреса: ${ADDRESS} +Email: ${EMAIL} +Телефон: ${PHONE} + +3. ЯКІ ДАНІ МИ ЗБИРАЄМО + +При користуванні Сайтом ми можемо збирати: +— Контактні дані (ім'я, email, номер телефону) — при заповненні форм замовлення або зворотнього зв'язку; +— Платіжні дані — обробляються виключно платіжним провайдером (Monobank), ми не зберігаємо реквізити карток; +— Технічні дані (IP-адреса, cookie, дані браузера) — для аналітики та покращення роботи Сайту; +— Дані щодо замовлень (склад замовлення, дата, сума). + +4. МЕТА ОБРОБКИ ДАНИХ + +Ми обробляємо персональні дані з метою: +— Виконання договірних зобов'язань (продаж квитків, обробка замовлень); +— Надсилання підтверджень замовлень та квитків на email; +— Зв'язку з клієнтом у разі потреби; +— Покращення якості послуг та роботи Сайту; +— Дотримання вимог законодавства. + +5. ЗБЕРІГАННЯ ТА ЗАХИСТ ДАНИХ + +Персональні дані зберігаються на захищених серверах. Ми вживаємо технічних і організаційних заходів для захисту даних від несанкціонованого доступу. Дані зберігаються не довше, ніж це необхідно для зазначених цілей. + +6. ПЕРЕДАЧА ДАНИХ ТРЕТІМ ОСОБАМ + +Ми не продаємо та не передаємо персональні дані третім особам, крім: +— Платіжних сервісів (Monobank) для обробки платежів; +— Сервісів аналітики (Google Analytics) — знеособлені дані; +— Уповноважених державних органів на їхній законний запит. + +7. ПРАВА СУБ'ЄКТІВ ДАНИХ + +Ви маєте право: +— Отримати доступ до своїх персональних даних; +— Вимагати їх виправлення або видалення; +— Відкликати згоду на обробку в будь-який момент; +— Подати скаргу до Уповноваженого з прав людини. + +Для реалізації прав звертайтеся: ${EMAIL} + +8. COOKIE + +Сайт використовує cookie для аналітики та покращення роботи. Ви можете відключити cookie в налаштуваннях браузера. + +9. ЗМІНИ ДО ПОЛІТИКИ + +Ми можемо оновлювати цю Політику. Актуальна версія завжди доступна на Сайті. + +Контакти: ${EMAIL} | ${PHONE}` + +export const TERMS_DEFAULT = `Дата набрання чинності: 1 серпня 2025 р. + +1. ЗАГАЛЬНІ ПОЛОЖЕННЯ + +Ці Умови використання (далі — «Умови») регулюють відносини між ${COMPANY}, ЄДРПОУ ${EDRPOU} (далі — «Парк», «ми»), та користувачами вебсайту ${SITE} (далі — «Сайт», «Користувач»). + +Використання Сайту означає повне прийняття цих Умов. + +2. ПРЕДМЕТ + +Сайт надає інформацію про парк розваг «Шуміленд», а також забезпечує можливість онлайн-придбання квитків на атракції та послуги парку. + +3. ПРИДБАННЯ КВИТКІВ + +3.1. Квитки реалізуються через онлайн-форму на Сайті. +3.2. Оплата здійснюється через платіжний сервіс Monobank. +3.3. Підтвердження замовлення та квиток надсилаються на вказаний email протягом 15 хвилин після успішної оплати. +3.4. Квиток дійсний на дату та час, зазначені у замовленні. + +4. ПРАВИЛА ВІДВІДУВАННЯ + +4.1. Відвідувачі зобов'язані дотримуватись правил поведінки на території парку. +4.2. Адміністрація парку має право відмовити у вході або видалити відвідувача, що порушує правила. +4.3. Діти до 10 років допускаються лише у супроводі дорослих. +4.4. Забороняється вносити на територію парку алкогольні напої, наркотичні речовини, зброю. + +5. ПОВЕРНЕННЯ ТА ОБМІН КВИТКІВ + +5.1. Повернення коштів за придбані квитки можливе не пізніше ніж за 24 години до початку відвідування. +5.2. Для повернення звертайтеся на email: ${EMAIL} із зазначенням номера замовлення. +5.3. Кошти повертаються на картку, з якої здійснювалася оплата, протягом 5-7 банківських днів. + +6. ВІДПОВІДАЛЬНІСТЬ + +6.1. Парк не несе відповідальності за особисті речі відвідувачів. +6.2. Відвідування атракціонів здійснюється на власний ризик з урахуванням вікових та медичних обмежень. +6.3. Адміністрація парку не несе відповідальності за шкоду, спричинену порушенням правил відвідування. + +7. ІНТЕЛЕКТУАЛЬНА ВЛАСНІСТЬ + +Усі матеріали Сайту (тексти, зображення, логотипи) є власністю ${COMPANY}. Копіювання без письмового дозволу заборонено. + +8. ЗМІНИ УМОВ + +Ми залишаємо за собою право змінювати ці Умови. Нова редакція набирає чинності з моменту публікації на Сайті. + +Контакти: ${EMAIL} | ${PHONE}` + +export const OFFER_DEFAULT = `Дата набрання чинності: 1 серпня 2025 р. + +ПУБЛІЧНА ОФЕРТА +про надання послуг парку розваг «Шуміленд» + +${COMPANY}, ЄДРПОУ ${EDRPOU}, юридична адреса: ${ADDRESS} (далі — «Виконавець»), відповідно до ст. 633, 641 Цивільного кодексу України, публікує цю Публічну оферту (далі — «Оферта»), яка є офіційною пропозицією укласти Договір про надання послуг на нижчевикладених умовах. + +1. ТЕРМІНИ ТА ВИЗНАЧЕННЯ + +Оферта — ця публічна пропозиція Виконавця укласти Договір. +Акцепт — повна безумовна згода Замовника з умовами Оферти, що виражається в оплаті послуг. +Замовник — фізична або юридична особа, яка здійснила Акцепт. +Послуги — право відвідування парку розваг «Шуміленд» та користування атракціонами відповідно до придбаного квитка. + +2. ПРЕДМЕТ ДОГОВОРУ + +2.1. Виконавець зобов'язується надати Замовнику послуги з доступу до парку розваг «Шуміленд» (далі — «Парк») відповідно до придбаного квитка. +2.2. Замовник зобов'язується оплатити послуги в розмірі, визначеному на Сайті на момент замовлення. + +3. ПОРЯДОК УКЛАДЕННЯ ДОГОВОРУ + +3.1. Договір вважається укладеним з моменту повної оплати вартості квитка. +3.2. Акцептом є факт оплати замовлення через платіжну систему. +3.3. Підтвердженням укладення Договору є електронний квиток, надісланий на email Замовника. + +4. ВАРТІСТЬ ТА ПОРЯДОК ОПЛАТИ + +4.1. Вартість послуг визначається відповідно до діючого прайс-листа, опублікованого на Сайті. +4.2. Оплата здійснюється виключно в безготівковій формі через платіжний сервіс Monobank. +4.3. Ціни зазначені в гривнях (UAH), включаючи всі податки та збори. + +5. ПРАВА ТА ОБОВ'ЯЗКИ СТОРІН + +5.1. Виконавець зобов'язаний: +— забезпечити доступ до Парку згідно з придбаним квитком; +— підтримувати атракціони та зони в безпечному стані; +— надати необхідну інформацію про умови відвідування. + +5.2. Замовник зобов'язаний: +— пред'явити квиток при вході; +— дотримуватись правил відвідування Парку; +— нести відповідальність за поведінку неповнолітніх осіб, яких він супроводжує. + +6. ВІДПОВІДАЛЬНІСТЬ СТОРІН + +6.1. За невиконання або неналежне виконання умов Договору Сторони несуть відповідальність відповідно до чинного законодавства України. +6.2. Виконавець не несе відповідальності за неможливість надання послуг внаслідок обставин непереборної сили. + +7. ПОРЯДОК ПОВЕРНЕННЯ КОШТІВ + +7.1. Замовник має право відмовитися від послуг та отримати повне відшкодування коштів не пізніше ніж за 24 години до дати відвідування. +7.2. Заявка на повернення подається на email: ${EMAIL} +7.3. Кошти повертаються протягом 5-7 банківських днів на рахунок, з якого здійснювалася оплата. + +8. СТРОК ДІЇ ОФЕРТИ + +Оферта діє безстроково до її відкликання Виконавцем. + +9. РЕКВІЗИТИ ВИКОНАВЦЯ + +${COMPANY} +ЄДРПОУ: ${EDRPOU} +Адреса: ${ADDRESS} +Email: ${EMAIL} +Телефон: ${PHONE} +Сайт: ${SITE}` + +export const DATA_PROCESSING_DEFAULT = `Дата набрання чинності: 1 серпня 2025 р. + +ЗГОДА НА ОБРОБКУ ПЕРСОНАЛЬНИХ ДАНИХ + +${COMPANY}, ЄДРПОУ ${EDRPOU} (далі — «Оператор»), відповідно до Закону України «Про захист персональних даних» від 01.06.2010 № 2297-VI та Регламенту ЄС 2016/679 (GDPR), інформує про умови обробки персональних даних. + +1. ОПЕРАТОР ПЕРСОНАЛЬНИХ ДАНИХ + +Найменування: ${COMPANY} +ЄДРПОУ: ${EDRPOU} +Адреса: ${ADDRESS} +Email: ${EMAIL} +Телефон: ${PHONE} + +2. СКЛАД ПЕРСОНАЛЬНИХ ДАНИХ + +Оператор обробляє такі категорії персональних даних: +— Прізвище, ім'я (за наявності у замовленні); +— Адреса електронної пошти; +— Номер телефону; +— Інформація про замовлення та відвідування; +— Технічні дані (IP-адреса, дані cookie). + +3. МЕТА ТА ПРАВОВА ПІДСТАВА ОБРОБКИ + +3.1. Виконання договору (ст. 6(1)(b) GDPR) — обробка даних, необхідних для надання послуг, продажу квитків та підтвердження замовлень. + +3.2. Законний інтерес (ст. 6(1)(f) GDPR) — покращення якості послуг, аналітика, безпека Сайту. + +3.3. Дотримання юридичного зобов'язання (ст. 6(1)(c) GDPR) — виконання вимог законодавства. + +4. ПОРЯДОК ОБРОБКИ ДАНИХ + +4.1. Збір даних здійснюється при заповненні форм на Сайті або при покупці квитків. +4.2. Дані зберігаються на захищених серверах на території ЄС або в Україні. +4.3. Строк зберігання даних — 3 роки з моменту останньої взаємодії або до реалізації права на видалення. +4.4. Персональні дані не передаються третім особам, крім платіжних провайдерів та сервісів аналітики в знеособленому вигляді. + +5. ПРАВА СУБ'ЄКТІВ ПЕРСОНАЛЬНИХ ДАНИХ + +Відповідно до законодавства ви маєте право: +— Доступу до своїх персональних даних; +— Виправлення неточних або неповних даних; +— Видалення («право бути забутим»); +— Обмеження обробки; +— Портативності даних; +— Заперечення проти обробки; +— Відкликання згоди без шкоди для законності обробки до її відкликання. + +6. РЕАЛІЗАЦІЯ ПРАВ + +Для реалізації будь-якого з перелічених прав направте запит на email: ${EMAIL} +Строк розгляду запиту — 30 календарних днів з моменту отримання. + +7. ЗАХИСТ ДАНИХ + +7.1. Оператор вживає технічних та організаційних заходів безпеки відповідно до ст. 32 GDPR. +7.2. У разі витоку персональних даних Оператор повідомить суб'єктів протягом 72 годин. + +8. СКАРГИ + +У разі порушення ваших прав ви маєте право подати скаргу до: +— Уповноваженого Верховної Ради України з прав людини; +— Наглядового органу ЄС у сфері захисту даних (для громадян ЄС). + +Контакти Оператора: ${EMAIL} | ${PHONE}` diff --git a/src/payload-types.ts b/src/payload-types.ts index fb4bcc2..5d24331 100644 --- a/src/payload-types.ts +++ b/src/payload-types.ts @@ -82,6 +82,7 @@ export interface Config { 'locations-page': LocationsPage 'blog-index-page': BlogIndexPage 'dinosaur-page': DinosaurPage + 'legal-pages': LegalPage } globalsSelect: { 'home-page': HomePageSelect | HomePageSelect @@ -97,6 +98,7 @@ export interface Config { 'locations-page': LocationsPageSelect | LocationsPageSelect 'blog-index-page': BlogIndexPageSelect | BlogIndexPageSelect 'dinosaur-page': DinosaurPageSelect | DinosaurPageSelect + 'legal-pages': LegalPagesSelect | LegalPagesSelect } locale: null widgets: { @@ -2468,6 +2470,31 @@ export interface DinosaurPage { updatedAt?: string | null createdAt?: string | null } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "legal-pages". + */ +export interface LegalPage { + id: number + privacy?: { + title?: string | null + content?: string | null + } + terms?: { + title?: string | null + content?: string | null + } + offer?: { + title?: string | null + content?: string | null + } + dataProcessing?: { + title?: string | null + content?: string | null + } + updatedAt?: string | null + createdAt?: string | null +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "home-page_select". @@ -3068,6 +3095,39 @@ export interface DinosaurPageSelect { createdAt?: T globalType?: T } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "legal-pages_select". + */ +export interface LegalPagesSelect { + privacy?: + | T + | { + title?: T + content?: T + } + terms?: + | T + | { + title?: T + content?: T + } + offer?: + | T + | { + title?: T + content?: T + } + dataProcessing?: + | T + | { + title?: T + content?: T + } + updatedAt?: T + createdAt?: T + globalType?: T +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "collections_widget".