diff --git a/proto/scripts/migrate-content-to-payload.ts b/proto/scripts/migrate-content-to-payload.ts new file mode 100644 index 0000000..5c2bdab --- /dev/null +++ b/proto/scripts/migrate-content-to-payload.ts @@ -0,0 +1,104 @@ +/** + * MITHOME-87: egyszeri migrációs script — a proto/src/content/pages/*.json + * + common.json tartalmát átemeli a Payload Globals-ekbe (Home, About, + * Services, Contact, Common) a Local API-n keresztül. + * + * Futtatás (proto/ mappából, futó MongoDB-vel és beállított env-ekkel): + * node --env-file=.env.local --import tsx scripts/migrate-content-to-payload.ts + * + * Idempotens: updateGlobal-t hív, tetszőlegesen többször futtatható — + * mindig a JSON az aktuális "forrás igazság", felülírja a Payload-ban + * lévő korábbi állapotot. NEM törli/nem érinti a JSON fájlokat. + */ +import { getPayload } from 'payload' +import config from '../src/payload.config' + +import homeJson from '../src/content/pages/home.json' +import aboutJson from '../src/content/pages/about.json' +import servicesJson from '../src/content/pages/services.json' +import contactJson from '../src/content/pages/contact.json' +import commonJson from '../src/content/common.json' + +/** string[] -> [{ value: string }] — lásd src/globals/fields/stringArray.ts */ +function toStringArray(items: readonly string[]): { value: string }[] { + return items.map((value) => ({ value })) +} + +function buildHomeData(json: typeof homeJson) { + const { hero, about, services, cta, serviceFeatures } = json + return { + hero: { + ...hero, + trustBullets: toStringArray(hero.trustBullets), + }, + about, + services: { + ...services, + items: services.items.map((item) => ({ + ...item, + features: toStringArray(item.features), + })), + }, + cta, + serviceFeatures, + } +} + +function buildAboutData(json: typeof aboutJson) { + const { meta, hero, story, mission, team, cta } = json + return { + meta, + hero, + story: { ...story, paragraphs: toStringArray(story.paragraphs) }, + mission, + team: { ...team, paragraphs: toStringArray(team.paragraphs) }, + cta, + } +} + +function buildServicesData(json: typeof servicesJson) { + const { meta, hero, details, support, cta } = json + return { + meta, + hero, + details: { + ...details, + services: details.services.map((service) => ({ + ...service, + specs: { + ...service.specs, + items: toStringArray(service.specs.items), + }, + })), + }, + support, + cta, + } +} + +async function run() { + const payload = await getPayload({ config }) + + await payload.updateGlobal({ slug: 'home', data: buildHomeData(homeJson) }) + payload.logger.info('Home global migrálva') + + await payload.updateGlobal({ slug: 'about', data: buildAboutData(aboutJson) }) + payload.logger.info('About global migrálva') + + await payload.updateGlobal({ slug: 'services', data: buildServicesData(servicesJson) }) + payload.logger.info('Services global migrálva') + + await payload.updateGlobal({ slug: 'contact', data: contactJson }) + payload.logger.info('Contact global migrálva') + + await payload.updateGlobal({ slug: 'common', data: commonJson }) + payload.logger.info('Common global migrálva') + + payload.logger.info('MITHOME-87 migráció kész.') + process.exit(0) +} + +run().catch((error) => { + console.error('Migráció sikertelen:', error) + process.exit(1) +}) diff --git a/proto/src/app/(frontend)/layout.tsx b/proto/src/app/(frontend)/layout.tsx index fc621b5..e0096da 100755 --- a/proto/src/app/(frontend)/layout.tsx +++ b/proto/src/app/(frontend)/layout.tsx @@ -2,11 +2,11 @@ import type { Metadata, Viewport } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; -import Header from "../components/Header"; -import Footer from "../components/Footer"; -import { ThemeProvider } from "../components/ThemeProvider"; -import { siteConfig } from "../config/site"; -import { common } from "../content"; +import Header from "../../components/Header"; +import Footer from "../../components/Footer"; +import { ThemeProvider } from "../../components/ThemeProvider"; +import { siteConfig } from "../../config/site"; +import { common } from "../../content"; const geistSans = Geist({ variable: "--font-geist-sans", diff --git a/proto/src/app/(payload)/admin/importMap.js b/proto/src/app/(payload)/admin/importMap.js index 3ed9bc6..af86423 100644 --- a/proto/src/app/(payload)/admin/importMap.js +++ b/proto/src/app/(payload)/admin/importMap.js @@ -1,4 +1,6 @@ -// Auto-generated by Payload (`npx payload generate:importmap`). -// Kept empty until a collection/global config references a custom admin -// component — regenerate with the CLI command whenever one does. -export const importMap = {} +import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc' + +/** @type import('payload').ImportMap */ +export const importMap = { + "@payloadcms/next/rsc#CollectionCards": CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 +} diff --git a/proto/src/globals/About.ts b/proto/src/globals/About.ts new file mode 100644 index 0000000..eaa8ceb --- /dev/null +++ b/proto/src/globals/About.ts @@ -0,0 +1,73 @@ +import type { GlobalConfig } from 'payload' + +import { stringArrayField } from './fields/stringArray' + +/** Mirrors AboutPageContent (proto/src/content/types.ts) — MITHOME-87. */ +export const About: GlobalConfig = { + slug: 'about', + admin: { + group: 'Oldalak', + }, + fields: [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { name: 'ogDescription', type: 'textarea', required: true }, + ], + }, + { + name: 'hero', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + ], + }, + { + name: 'story', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + stringArrayField('paragraphs', 'Paragraphs'), + ], + }, + { + name: 'mission', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + { + name: 'values', + type: 'array', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { name: 'icon', type: 'text', required: true }, + ], + }, + ], + }, + { + name: 'team', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + stringArrayField('paragraphs', 'Paragraphs'), + ], + }, + { + name: 'cta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'textarea', required: true }, + { name: 'button', type: 'text', required: true }, + ], + }, + ], +} diff --git a/proto/src/globals/Common.ts b/proto/src/globals/Common.ts new file mode 100644 index 0000000..93b0674 --- /dev/null +++ b/proto/src/globals/Common.ts @@ -0,0 +1,73 @@ +import type { GlobalConfig } from 'payload' + +/** Mirrors CommonContent (proto/src/content/types.ts) — MITHOME-87. */ +export const Common: GlobalConfig = { + slug: 'common', + admin: { + group: 'Oldalak', + }, + fields: [ + { + name: 'buttons', + type: 'group', + fields: [ + { name: 'contact', type: 'text', required: true }, + { name: 'learnMore', type: 'text', required: true }, + { name: 'webmail', type: 'text', required: true }, + { name: 'sendMessage', type: 'text', required: true }, + ], + }, + { + name: 'labels', + type: 'group', + fields: [ + { name: 'required', type: 'text', required: true }, + { name: 'features', type: 'text', required: true }, + ], + }, + { + name: 'validation', + type: 'group', + fields: [ + { name: 'required', type: 'text', required: true }, + { name: 'invalidEmail', type: 'text', required: true }, + { + name: 'minLength', + type: 'text', + required: true, + admin: { + description: 'A {min} placeholder futásidőben cserélődik ki.', + }, + }, + ], + }, + { + name: 'staging', + type: 'group', + fields: [{ name: 'banner', type: 'text', required: true }], + }, + { + name: 'footer', + type: 'group', + fields: [ + { + name: 'copyright', + type: 'text', + required: true, + admin: { + description: 'A {year} placeholder futásidőben cserélődik ki.', + }, + }, + { name: 'address', type: 'text', required: true }, + ], + }, + { + name: 'a11y', + type: 'group', + fields: [ + { name: 'openMenu', type: 'text', required: true }, + { name: 'closeMenu', type: 'text', required: true }, + ], + }, + ], +} diff --git a/proto/src/globals/Contact.ts b/proto/src/globals/Contact.ts new file mode 100644 index 0000000..7ae951d --- /dev/null +++ b/proto/src/globals/Contact.ts @@ -0,0 +1,142 @@ +import type { GlobalConfig } from 'payload' + +/** + * Mirrors ContactPageContent (proto/src/content/types.ts) — MITHOME-87. + * + * WHY `gdpr.label` textarea és nem richText: a JSON forrás egy kézzel + * beírt taget tartalmazó HTML string (lásd contact.json). A lexical + * richText mező más (JSON node-fa) szerializációt használna, ami extra + * migrációs/render logikát igényelne — ezt itt, bootstrap szinten nem + * bontjuk ki, marad egyszerű (HTML-t tartalmazó) szöveg mező. + */ +export const Contact: GlobalConfig = { + slug: 'contact', + admin: { + group: 'Oldalak', + }, + fields: [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + ], + }, + { + name: 'hero', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + ], + }, + { + name: 'form', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'successMessage', type: 'text', required: true }, + { name: 'errorMessage', type: 'text', required: true }, + { + name: 'fields', + type: 'group', + fields: [ + { + name: 'name', + type: 'group', + fields: [ + { name: 'label', type: 'text', required: true }, + { name: 'placeholder', type: 'text', required: true }, + { name: 'error', type: 'text', required: true }, + ], + }, + { + name: 'email', + type: 'group', + fields: [ + { name: 'label', type: 'text', required: true }, + { name: 'placeholder', type: 'text', required: true }, + { name: 'errorRequired', type: 'text', required: true }, + { name: 'errorInvalid', type: 'text', required: true }, + ], + }, + { + name: 'subject', + type: 'group', + fields: [ + { name: 'label', type: 'text', required: true }, + { name: 'placeholder', type: 'text', required: true }, + { name: 'error', type: 'text', required: true }, + ], + }, + { + name: 'message', + type: 'group', + fields: [ + { name: 'label', type: 'text', required: true }, + { name: 'placeholder', type: 'text', required: true }, + { name: 'errorRequired', type: 'text', required: true }, + { name: 'errorMinLength', type: 'text', required: true }, + ], + }, + { + name: 'gdpr', + type: 'group', + fields: [ + { name: 'label', type: 'textarea', required: true }, + { name: 'error', type: 'text', required: true }, + ], + }, + ], + }, + { name: 'submitButton', type: 'text', required: true }, + { name: 'submittingButton', type: 'text', required: true }, + ], + }, + { + name: 'info', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { + name: 'email', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'responseTime', type: 'text', required: true }, + ], + }, + { + name: 'company', + type: 'group', + fields: [{ name: 'title', type: 'text', required: true }], + }, + { + name: 'webmail', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'linkText', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + ], + }, + ], + }, + { + name: 'faq', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { + name: 'items', + type: 'array', + fields: [ + { name: 'question', type: 'text', required: true }, + { name: 'answer', type: 'textarea', required: true }, + ], + }, + ], + }, + ], +} diff --git a/proto/src/globals/Home.ts b/proto/src/globals/Home.ts new file mode 100644 index 0000000..05cffb1 --- /dev/null +++ b/proto/src/globals/Home.ts @@ -0,0 +1,105 @@ +import type { GlobalConfig } from 'payload' + +import { stringArrayField } from './fields/stringArray' + +/** + * Mirrors HomePageContent (proto/src/content/types.ts) — MITHOME-87. + * + * WHY nincs `partners` mező: a home.partners.items a JSON-ban ma egy + * beágyazott lista, de a Payload oldalon önálló `Partners` collection lesz + * (logó = Media upload reference) — lásd MITHOME-89. Itt szándékosan + * kihagyjuk, nehogy két, egymásnak ellentmondó forrás legyen. + */ +export const Home: GlobalConfig = { + slug: 'home', + admin: { + group: 'Oldalak', + }, + fields: [ + { + name: 'hero', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + stringArrayField('trustBullets', 'Trust bullets'), + { + name: 'cta', + type: 'group', + fields: [ + { + name: 'primary', + type: 'group', + fields: [ + { name: 'text', type: 'text', required: true }, + { name: 'href', type: 'text', required: true }, + { name: 'external', type: 'checkbox', defaultValue: false }, + ], + }, + { + name: 'secondary', + type: 'group', + fields: [ + { name: 'text', type: 'text', required: true }, + { name: 'href', type: 'text', required: true }, + { name: 'external', type: 'checkbox', defaultValue: false }, + ], + }, + ], + }, + ], + }, + { + name: 'about', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { + name: 'usps', + type: 'array', + fields: [ + { name: 'id', type: 'text', required: true }, + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { name: 'icon', type: 'text', required: true }, + ], + }, + ], + }, + { + name: 'services', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + { + name: 'items', + type: 'array', + fields: [ + { name: 'id', type: 'text', required: true }, + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { name: 'icon', type: 'text', required: true }, + stringArrayField('features', 'Features'), + { name: 'ctaText', type: 'text', required: true }, + ], + }, + ], + }, + { + name: 'cta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'textarea', required: true }, + { name: 'button', type: 'text', required: true }, + ], + }, + { + name: 'serviceFeatures', + type: 'group', + fields: [{ name: 'title', type: 'text', required: true }], + }, + ], +} diff --git a/proto/src/globals/Services.ts b/proto/src/globals/Services.ts new file mode 100644 index 0000000..3fccecd --- /dev/null +++ b/proto/src/globals/Services.ts @@ -0,0 +1,82 @@ +import type { GlobalConfig } from 'payload' + +import { stringArrayField } from './fields/stringArray' + +/** Mirrors ServicesPageContent (proto/src/content/types.ts) — MITHOME-87. */ +export const Services: GlobalConfig = { + slug: 'services', + admin: { + group: 'Oldalak', + }, + fields: [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { name: 'ogDescription', type: 'textarea', required: true }, + ], + }, + { + name: 'hero', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + ], + }, + { + name: 'details', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + { + name: 'services', + type: 'array', + fields: [ + { name: 'icon', type: 'text', required: true }, + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'textarea', required: true }, + { + name: 'specs', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + stringArrayField('items', 'Items'), + ], + }, + ], + }, + ], + }, + { + name: 'support', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'text', required: true }, + { + name: 'channels', + type: 'array', + fields: [ + { name: 'icon', type: 'text', required: true }, + { name: 'title', type: 'text', required: true }, + { name: 'description', type: 'text', required: true }, + ], + }, + ], + }, + { + name: 'cta', + type: 'group', + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'subtitle', type: 'textarea', required: true }, + { name: 'primaryButton', type: 'text', required: true }, + { name: 'secondaryButton', type: 'text', required: true }, + ], + }, + ], +} diff --git a/proto/src/globals/fields/stringArray.ts b/proto/src/globals/fields/stringArray.ts new file mode 100644 index 0000000..a2f57a3 --- /dev/null +++ b/proto/src/globals/fields/stringArray.ts @@ -0,0 +1,24 @@ +import type { ArrayField } from 'payload' + +/** + * Payload has no native "array of plain strings" field — the closest + * built-in shape is an array of one-field objects. Used for every + * string[] in the old content/types.ts (trustBullets, paragraphs, + * features, spec items, …) so the JSON -> Payload migration script has a + * single, consistent shape to transform into. + */ +export function stringArrayField(name: string, label?: string, required = false): ArrayField { + return { + name, + type: 'array', + label, + fields: [ + { + name: 'value', + type: 'text', + required: true, + }, + ], + required, + } +} diff --git a/proto/src/payload.config.ts b/proto/src/payload.config.ts index c92a231..60d4517 100644 --- a/proto/src/payload.config.ts +++ b/proto/src/payload.config.ts @@ -5,11 +5,9 @@ * (proto/src/lib/mongodb.ts) — Payload a `mongooseAdapter`-en keresztül * ugyanabba az adatbázisba ír, nincs szükség külön DB-re/szerverre. * - * Ez a fájl jelenleg csak a bootstrap-hez szükséges minimumot tartalmazza - * (Users collection az admin bejelentkezéshez — Payload nem tud admin - * felületet renderelni auth collection nélkül). A tényleges tartalom- - * collectionök/globalok (Home, About, Services, Contact, Common, LegalPages, - * Partners, Media) a MITHOME-87..90 ticketekben kerülnek be. + * MITHOME-87: Home/About/Services/Contact/Common Globals hozzáadva — ezek + * tükrözik a proto/src/content/pages/*.json + common.json struktúráját. + * A LegalPages/Partners/Media collectionök a MITHOME-88..89-ben kerülnek be. */ import path from 'path' import { fileURLToPath } from 'url' @@ -19,6 +17,11 @@ import { lexicalEditor } from '@payloadcms/richtext-lexical' import sharp from 'sharp' import { Users } from './collections/Users' +import { Home } from './globals/Home' +import { About } from './globals/About' +import { Services } from './globals/Services' +import { Contact } from './globals/Contact' +import { Common } from './globals/Common' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -34,6 +37,8 @@ export default buildConfig({ collections: [Users], + globals: [Home, About, Services, Contact, Common], + secret: process.env.PAYLOAD_SECRET || '', typescript: {