fix: resolve contact form placeholders, restore process block layout, and fix testimonials carousel scroll logic

This commit is contained in:
MichalC
2026-09-17 22:25:25 +02:00
parent 7cc68b9f36
commit ab4c5c83dd
91 changed files with 4790 additions and 319 deletions
+117
View File
@@ -0,0 +1,117 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import fs from 'fs'
const ALLOWED_DUPLICATES = [
"b.b.h. Lohnsteuerhilfeverein e.V.",
"§4 Nr. 11 StBerG",
"Finanz- & Lohnbuchhaltung",
"Dipl.-Ing. Janusz Kędzierski",
"JK"
]
function isAllowedDuplicate(val: string): boolean {
if (!val || typeof val !== 'string') return true;
const trimmed = val.trim();
if (ALLOWED_DUPLICATES.includes(trimmed)) return true;
if (trimmed.startsWith('http') || trimmed.startsWith('/') || trimmed.startsWith('tel:') || trimmed.startsWith('mailto:')) return true;
// phone numbers, pure digits
if (/^[\d\s\+\-\(\)]+$/.test(trimmed)) return true;
// emails
if (trimmed.includes('@') && !trimmed.includes(' ')) return true;
return false;
}
function extractText(val: any): string {
if (typeof val === 'string') return val;
if (val && typeof val === 'object' && val.root && val.root.children) {
// Basic rich text extractor
let text = '';
const traverse = (node: any) => {
if (node.text) text += node.text;
if (node.children) node.children.forEach(traverse);
};
traverse(val.root);
return text.trim();
}
return JSON.stringify(val);
}
function compareObjects(objPL: any, objDE: any, path: string, results: string[]) {
if (!objPL || !objDE) return;
if (typeof objPL !== 'object' || typeof objDE !== 'object') return;
// If array
if (Array.isArray(objPL)) {
for (let i = 0; i < objPL.length; i++) {
compareObjects(objPL[i], objDE[i], `${path}[${i}]`, results);
}
return;
}
// Iterate keys
for (const key of Object.keys(objPL)) {
if ([
'id', 'createdAt', 'updatedAt', 'blockType', 'blockName',
'slug', 'value', 'name', 'icon', 'globalType', 'confirmationType',
'type', 'url', 'siteName', 'titleOrder', 'titleSeparator',
'defaultTheme', 'relationTo', 'status'
].includes(key)) continue;
const valPL = objPL[key];
const valDE = objDE[key];
if (typeof valPL === 'string' || (valPL && valPL.root)) {
const textPL = extractText(valPL);
const textDE = extractText(valDE);
if (textPL && textPL === textDE) {
if (!isAllowedDuplicate(textPL)) {
results.push(`[PODEJRZANY DUPLIKAT] ${path}.${key} | PL: "${textPL.substring(0, 50).replace(/\n/g, ' ')}" | DE: "${textDE.substring(0, 50).replace(/\n/g, ' ')}"`);
}
}
} else if (typeof valPL === 'object') {
compareObjects(valPL, valDE, `${path}.${key}`, results);
}
}
}
async function run() {
const payload = await getPayload({ config: configPromise })
const results: string[] = [];
console.log('Fetching pages...');
const pagesPL = await payload.find({ collection: 'pages', depth: 2, locale: 'pl', limit: 100 })
const pagesDE = await payload.find({ collection: 'pages', depth: 2, locale: 'de', limit: 100 })
for (const pagePL of pagesPL.docs) {
const pageDE = pagesDE.docs.find(p => p.id === pagePL.id)
if (pageDE) {
compareObjects(pagePL, pageDE, `Page(${pagePL.slug})`, results);
}
}
const globals = ['header', 'footer', 'company', 'site-settings']
for (const slug of globals) {
console.log(`Fetching global ${slug}...`);
const globalPL = await payload.findGlobal({ slug: slug as any, depth: 2, locale: 'pl' })
const globalDE = await payload.findGlobal({ slug: slug as any, depth: 2, locale: 'de' })
compareObjects(globalPL, globalDE, `Global(${slug})`, results);
}
console.log('Fetching forms...');
const formsPL = await payload.find({ collection: 'forms', depth: 2, locale: 'pl', limit: 100 })
const formsDE = await payload.find({ collection: 'forms', depth: 2, locale: 'de', limit: 100 })
for (const formPL of formsPL.docs) {
const formDE = formsDE.docs.find(f => f.id === formPL.id)
if (formDE) {
compareObjects(formPL, formDE, `Form(${formPL.title})`, results);
}
}
fs.writeFileSync('audit_results.txt', results.join('\n'));
console.log(`Audit complete. Found ${results.length} suspicious fields.`);
process.exit(0)
}
run()
+37
View File
@@ -0,0 +1,37 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const locales = ['pl', 'de']
let foundEmpty = false
for (const locale of locales) {
const pages = await payload.find({ collection: 'pages', locale: locale as 'pl'|'de', limit: 100 })
for (const page of pages.docs) {
const layout = page.layout || []
for (const block of layout) {
// Iterate over keys of the block to find arrays
for (const key of Object.keys(block)) {
const value = block[key]
if (Array.isArray(value) && value.length === 0) {
// Some arrays might naturally be empty if they are optional, but most of these are required
// Let's flag any empty array in these block fields
if (['steps', 'questions', 'services', 'members', 'stats', 'points', 'testimonials', 'logos', 'bullets', 'checkmarks'].includes(key)) {
console.log(`[UWAGA] Pusta tablica '${key}' znaleziona w bloku '${block.blockType}' na stronie '${page.slug}' (locale: ${locale})`)
foundEmpty = true
}
}
}
}
}
}
if (!foundEmpty) {
console.log("Wszystkie tablice w blokach na stronach (PL i DE) są pełne. Stan: OK.")
}
process.exit(0)
}
run().catch(console.error)
+12
View File
@@ -0,0 +1,12 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const forms = await payload.find({ collection: 'forms', locale: 'all' });
console.log('Available forms:', forms.docs.map(f => ({ id: f.id, title: f.title })));
process.exit(0);
}
run().catch(console.error);
+24
View File
@@ -0,0 +1,24 @@
import http from 'http';
function fetchHTML(path) {
return new Promise((resolve, reject) => {
http.get(`http://localhost:3000${path}`, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
}
async function run() {
for (const locale of ['pl', 'de']) {
const html = await fetchHTML(`/${locale}/kontakt`);
console.log(`\n=== OPTIONS FOR /${locale}/kontakt ===`);
const regex = /<option[^>]*>([^<]*)<\/option>/g;
let match;
while ((match = regex.exec(html)) !== null) {
console.log(`[OPTION] ${match[1]}`);
}
}
}
run();
+47
View File
@@ -0,0 +1,47 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
for (const locale of ['pl', 'de']) {
const pages = await payload.find({
collection: 'pages',
locale: locale as 'pl' | 'de',
where: { slug: { equals: 'kontakt' } }
})
if (pages.docs.length > 0) {
const page = pages.docs[0];
const formBlock = page.layout?.find(b => b.blockType === 'contactSection');
if (formBlock && formBlock.form) {
// Fetch the form
const formId = typeof formBlock.form === 'object' ? formBlock.form.id : formBlock.form;
console.log(`\n=== FORMULARZ PODPIĘTY POD /${locale}/kontakt (ID: ${formId}) ===`);
const form = await payload.findByID({
collection: 'forms',
id: formId as number,
locale: locale as 'pl' | 'de',
});
const serviceField = form.fields?.find(f => f.name === 'service' && f.blockType === 'select');
console.log(`POLE SERVICE OPTIONS (LOCALE: ${locale}):`);
console.log(JSON.stringify(serviceField?.options, null, 2));
// Let's also check placeholders and other texts for step 5
console.log(`\nPOZOSTAŁE POLA (LOCALE: ${locale}):`);
form.fields?.forEach(f => {
if (f.blockType !== 'select') {
const placeholderValue = f.defaultValue || (f.name === 'email' ? (f.label === 'Adres e-mail' ? '[email protected]' : '[email protected]') : '');
console.log(`- ${f.name} (${f.blockType}): label="${f.label}", placeholder="${placeholderValue}"`);
}
});
}
}
}
process.exit(0);
}
run().catch(console.error);
+31
View File
@@ -0,0 +1,31 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const resPl = await payload.find({
collection: 'pages',
where: { slug: { equals: 'jak-sie-umowic' } },
locale: 'pl',
depth: 1
})
const resDe = await payload.find({
collection: 'pages',
where: { slug: { equals: 'jak-sie-umowic' } },
locale: 'de',
depth: 1
})
console.log("=== PL ===")
const processPl = resPl.docs[0]?.layout?.find(b => b.blockType === 'process')
console.log(JSON.stringify(processPl, null, 2))
console.log("\\n=== DE ===")
const processDe = resDe.docs[0]?.layout?.find(b => b.blockType === 'process')
console.log(JSON.stringify(processDe, null, 2))
process.exit(0)
}
run().catch(console.error)
+20
View File
@@ -0,0 +1,20 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const resDe = await payload.find({
collection: 'pages',
where: { slug: { equals: 'terminvereinbarung' } },
locale: 'de',
depth: 1
})
console.log("\\n=== DE (terminvereinbarung) ===")
const processDe = resDe.docs[0]?.layout?.find(b => b.blockType === 'process')
console.log(JSON.stringify(processDe, null, 2))
process.exit(0)
}
run().catch(console.error)
+43
View File
@@ -0,0 +1,43 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
console.log('--- KOTWICE USŁUG (HOME -> USLUGI) ---')
for (const locale of ['pl', 'de'] as const) {
const pages = await payload.find({ collection: 'pages', locale, where: { slug: { equals: 'home' } } })
if (pages.docs.length > 0) {
console.log(`\nStrona ${locale.toUpperCase()} (Home):`)
pages.docs[0].layout?.forEach((b:any) => {
if (b.blockType === 'servicesList' && b.services) {
b.services.forEach((s:any) => console.log(` - ${s.title} -> ${s.linkUrl}`))
}
})
}
}
console.log('\n--- FORMULARZ KONTAKTOWY (PL vs DE) ---')
const forms = await payload.find({ collection: 'forms', locale: 'all', limit: 1 })
if (forms.docs.length > 0) {
const form = forms.docs[0] as any
console.log(`\nFormularz ID: ${form.id}`)
console.log(`Tytuł: PL="${form.title.pl}", DE="${form.title.de}"`)
console.log(`Wiadomość z podziękowaniem (PL): ${form.confirmationMessage.pl.root.children[0].children[0].text}`)
console.log(`Wiadomość z podziękowaniem (DE): ${form.confirmationMessage.de.root.children[0].children[0].text}`)
console.log(`Temat email (PL): ${form.emails[0].subject.pl}`)
console.log(`Temat email (DE): ${form.emails[0].subject.de}`)
console.log('\nPola formularza:')
form.fields?.forEach((f:any) => {
console.log(` - Pole ${f.blockType}: ${f.name} (Etykieta PL: "${f.label.pl}", DE: "${f.label.de}")`)
if (f.blockType === 'select' && f.options) {
f.options.forEach((o:any) => {
console.log(` * [${o.value}] PL: "${o.label.pl}", DE: "${o.label.de}"`)
})
}
})
}
process.exit(0)
}
run()
+61
View File
@@ -0,0 +1,61 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
console.log('Rozpoczynam naprawę tłumaczenia bloku Team dla DE...')
const payload = await getPayload({ config: configPromise })
const pages = await payload.find({
collection: 'pages',
locale: 'de',
limit: 100
})
let updated = false
for (const page of pages.docs) {
if (!page.layout) continue
let changed = false
const newLayout = page.layout.map((block: any) => {
if (block.blockType === 'team') {
if (block.title === 'Nasz zespół' || block.title === 'Unser Team') {
console.log(`[DE] Wartość przed: title="${block.title}", subtitle="${block.subtitle}"`)
block.title = 'Unser Team'
block.subtitle = 'Lernen Sie die Experten kennen, die sich mit Engagement um Ihre Finanzen kümmern. Jeder von uns bringt langjährige Erfahrung mit, um Ihnen Sicherheit und Ruhe zu garantieren.'
console.log(`[DE] Wartość po: title="${block.title}", subtitle="${block.subtitle}"`)
if (block.members && block.members.length > 0) {
// Przetłumacz na sztywno Janusza jeśli jest w bazie, żeby rola/opis też miały sens
if (block.members[0].name.includes('Janusz')) {
block.members[0].role = 'Inhaber / Beratungsstellenleiter'
block.members[0].description = 'Langjähriger Steuerrechtspraktiker mit Spezialisierung auf die Beratung polnischer Arbeitnehmer in Deutschland.'
// keep URL as is
}
}
changed = true
}
}
return block
})
if (changed) {
console.log(`Aktualizacja strony DE: ${page.title} (ID: ${page.id})`)
await payload.update({
collection: 'pages',
id: page.id,
locale: 'de',
data: { layout: newLayout }
})
updated = true
}
}
if (updated) {
console.log('Zaktualizowano pomyślnie.')
} else {
console.log('Nie znaleziono bloku Team do aktualizacji na DE.')
}
process.exit(0)
}
run()
+114
View File
@@ -0,0 +1,114 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const addressDE = "Vom Kunden zu bestätigen";
const hoursDE = "Mo-Fr: 9:00 - 17:00\nNach vorheriger Terminvereinbarung";
// 1. Kontakt Page (ID: 5, slug: 'kontakt')
console.log('Fetching Kontakt DE...');
const kontaktDE = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'kontakt' } } });
if (kontaktDE.docs.length > 0) {
const doc = kontaktDE.docs[0];
let changed = false;
const newLayout = doc.layout?.map((block: any) => {
if (block.blockType === 'pageHeader') {
if (block.subtitle === 'Masz pytania dotyczące rozliczenia podatkowego w N' || block.subtitle === 'Masz pytania dotyczące rozliczenia podatkowego w Niemczech? Skontaktuj się z nami — chętnie pomożemy.') {
block.subtitle = 'Haben Sie Fragen zu Ihrer Steuererklärung in Deutschland? Kontaktieren Sie uns — wir helfen Ihnen gerne.';
changed = true;
}
}
if (block.blockType === 'contactSection') {
if (block.address === 'DO POTWIERDZENIA PRZEZ KLIENTA') {
block.address = addressDE;
changed = true;
}
if (block.hours === 'Pon-Pt: 9:00 - 17:00\nPo wcześniejszym umówieniu') {
block.hours = hoursDE;
changed = true;
}
}
if (changed) delete block.id;
return block;
});
if (changed) {
await payload.update({
collection: 'pages',
id: doc.id,
locale: 'de',
data: { layout: newLayout }
});
console.log('Updated Kontakt DE');
}
}
// 2. Jak się umówić Page (slug: 'jak-sie-umowic')
console.log('Fetching Jak się umówić DE...');
const jsuDE = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'terminvereinbarung' } } });
if (jsuDE.docs.length === 0) {
const jsuDE_plSlug = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'jak-sie-umowic' } } });
if (jsuDE_plSlug.docs.length > 0) {
jsuDE.docs = jsuDE_plSlug.docs;
}
}
if (jsuDE.docs.length > 0) {
const doc = jsuDE.docs[0];
let changed = false;
const newLayout = doc.layout?.map((block: any) => {
if (block.blockType === 'contactSection') {
if (block.address === 'DO POTWIERDZENIA PRZEZ KLIENTA') {
block.address = addressDE;
changed = true;
}
if (block.hours === 'Pon-Pt: 9:00 - 17:00\nPo wcześniejszym umówieniu') {
block.hours = hoursDE;
changed = true;
}
}
if (changed) delete block.id;
return block;
});
if (changed) {
await payload.update({
collection: 'pages',
id: doc.id,
locale: 'de',
data: { layout: newLayout }
});
console.log('Updated Jak się umówić DE');
}
}
// 3. Company Global
console.log('Fetching Company DE...');
const companyDE = await payload.findGlobal({ slug: 'company', locale: 'de' });
if (companyDE) {
let changed = false;
const updateData: any = {};
if (companyDE.address === 'DO POTWIERDZENIA PRZEZ KLIENTA') {
updateData.address = addressDE;
changed = true;
}
if (companyDE.hours === 'Pon-Pt: 9:00 - 17:00\nPo wcześniejszym umówieniu') {
updateData.hours = hoursDE;
changed = true;
}
if (changed) {
await payload.updateGlobal({
slug: 'company',
locale: 'de',
data: updateData
});
console.log('Updated Company DE');
}
}
console.log('Migration complete');
process.exit(0);
}
run()
+61
View File
@@ -0,0 +1,61 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
for (const locale of ['pl', 'de']) {
const pages = await payload.find({
collection: 'pages',
locale: locale as 'pl' | 'de',
where: {
slug: { equals: 'kontakt' }
}
})
if (pages.docs.length === 0) continue;
const page = pages.docs[0];
let updated = false;
// We do point updates on the layout array
const newLayout = page.layout?.map((block: any) => {
// If we find contactInfo, upgrade it to contactSection
if (block.blockType === 'contactInfo') {
updated = true;
return {
...block,
blockType: 'contactSection',
form: 1 // Add the form relation
}
}
// If we already have contactSection but missing form, just add it (just in case)
if (block.blockType === 'contactSection' && !block.form) {
updated = true;
return {
...block,
form: 1
}
}
return block;
});
if (updated) {
await payload.update({
collection: 'pages',
id: page.id,
locale: locale as 'pl' | 'de',
data: {
layout: newLayout
}
});
console.log(`Updated layout for ${locale.toUpperCase()}`);
} else {
console.log(`No contactInfo block found to upgrade for ${locale.toUpperCase()}`);
}
}
process.exit(0);
}
run().catch(console.error);
+31
View File
@@ -0,0 +1,31 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const addressDE = "Vom Kunden zu bestätigen";
const hoursDE = "Mo-Fr: 9:00 - 17:00\nNach vorheriger Terminvereinbarung";
for (const slug of ['kontakt', 'terminvereinbarung']) {
const pages = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: slug } } });
if (pages.docs.length > 0) {
const doc = pages.docs[0];
const newLayout = doc.layout?.map((b: any) => {
if (b.blockType === 'contactInfo' || b.blockType === 'contactSection') {
b.address = addressDE;
b.hours = hoursDE;
}
return b;
});
await payload.update({
collection: 'pages',
id: doc.id,
locale: 'de',
data: { layout: newLayout }
});
console.log('Updated ' + slug);
}
}
process.exit(0);
}
run()
+92
View File
@@ -0,0 +1,92 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
function deepStripIds(obj: any): any {
if (Array.isArray(obj)) return obj.map(deepStripIds);
if (obj !== null && typeof obj === 'object') {
const newObj = { ...obj };
delete newObj.id;
for (const key of Object.keys(newObj)) {
newObj[key] = deepStripIds(newObj[key]);
}
return newObj;
}
return obj;
}
async function run() {
const payload = await getPayload({ config: configPromise })
const addressDE = "Vom Kunden zu bestätigen";
const hoursDE = "Mo-Fr: 9:00 - 17:00\nNach vorheriger Terminvereinbarung";
// Kontakt
const kontaktPL = await payload.find({ collection: 'pages', locale: 'pl', where: { slug: { equals: 'kontakt' } } });
if (kontaktPL.docs.length > 0) {
let changed = false;
const layoutDE = deepStripIds(kontaktPL.docs[0].layout).map((b: any) => {
const newB = { ...b };
if (newB.blockType === 'pageHeader') {
newB.subtitle = 'Haben Sie Fragen zu Ihrer Steuererklärung in Deutschland? Kontaktieren Sie uns — wir helfen Ihnen gerne.';
changed = true;
}
if (newB.blockType === 'contactSection') {
newB.address = addressDE;
newB.hours = hoursDE;
changed = true;
}
return newB;
});
if (changed) {
await payload.update({
collection: 'pages',
id: kontaktPL.docs[0].id,
locale: 'de',
data: { layout: layoutDE }
});
console.log('Updated Kontakt DE');
}
}
// Jak sie umowic
const jsuPL = await payload.find({ collection: 'pages', locale: 'pl', where: { slug: { equals: 'jak-sie-umowic' } } });
if (jsuPL.docs.length > 0) {
let changed = false;
const layoutDE = deepStripIds(jsuPL.docs[0].layout).map((b: any) => {
const newB = { ...b };
if (newB.blockType === 'contactSection') {
newB.address = addressDE;
newB.hours = hoursDE;
changed = true;
}
return newB;
});
if (changed) {
await payload.update({
collection: 'pages',
id: jsuPL.docs[0].id,
locale: 'de',
data: { layout: layoutDE }
});
console.log('Updated Jak Sie Umowic DE');
}
}
// Company Global
const companyDE = await payload.findGlobal({ slug: 'company', locale: 'de' });
if (companyDE) {
await payload.updateGlobal({
slug: 'company',
locale: 'de',
data: {
address: addressDE,
hours: hoursDE
}
});
console.log('Updated Company DE');
}
process.exit(0);
}
run()
+88
View File
@@ -0,0 +1,88 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[15:52:56] INFO: [ipal] Plugin initialized.
=== FORMULARZ PODPIĘTY POD /pl/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: pl):
[
{
"id": "6aab9bd69f369ef03e6bf859",
"value": "erstellung-der-einkommensteuererklarung"
},
{
"id": "6aab9bd69f369ef03e6bf85a",
"value": "steuervorausberechnung"
},
{
"id": "6aab9bd69f369ef03e6bf85b",
"value": "prufung-des-steuerbescheids"
},
{
"id": "6aab9bd69f369ef03e6bf85c",
"value": "einspruchsverfahren"
},
{
"id": "6aab9bd69f369ef03e6bf85d",
"value": "ganzjahrige-steuerliche-betreuung"
},
{
"id": "6aab9bd69f369ef03e6bf85e",
"value": "wahl-der-optimalen-steuerklasse"
},
{
"id": "6aab9bd69f369ef03e6bf85f",
"value": "freibetrage-kindergeld-and-fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: pl):
- name (text): label="Imię i nazwisko", placeholder=""
- email (email): label="Adres e-mail", placeholder=""
- message (textarea): label="Wiadomość", placeholder=""
- consent (checkbox): label="Wyrażam zgodę na przetwarzanie danych", placeholder=""
=== FORMULARZ PODPIĘTY POD /de/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: de):
[
{
"id": "6aab9bd69f369ef03e6bf859",
"value": "erstellung-der-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aab9bd69f369ef03e6bf85a",
"value": "steuervorausberechnung",
"label": "Steuervorausberechnung"
},
{
"id": "6aab9bd69f369ef03e6bf85b",
"value": "prufung-des-steuerbescheids",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aab9bd69f369ef03e6bf85c",
"value": "einspruchsverfahren",
"label": "Einspruchsverfahren"
},
{
"id": "6aab9bd69f369ef03e6bf85d",
"value": "ganzjahrige-steuerliche-betreuung",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aab9bd69f369ef03e6bf85e",
"value": "wahl-der-optimalen-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aab9bd69f369ef03e6bf85f",
"value": "freibetrage-kindergeld-and-fahrtkosten",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: de):
- name (text): label="Vor- und Nachname", placeholder=""
- email (email): label="E-Mail Adresse", placeholder=""
- message (textarea): label="Nachricht", placeholder=""
- consent (checkbox): label="Ich stimme der Datenverarbeitung zu", placeholder=""
+95
View File
@@ -0,0 +1,95 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[16:03:33] INFO: [ipal] Plugin initialized.
=== FORMULARZ PODPIĘTY POD /pl/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: pl):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Sporządzenie deklaracji podatkowej (Einkommensteuererklärung)"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Wstępne obliczenie przewidywanego zwrotu"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Kontrola decyzji podatkowej (Steuerbescheid)"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Składanie odwołań (Einspruch)"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Całoroczne doradztwo podatkowe"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Doradztwo przy wyborze klasy podatkowej (Steuerklasse)"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Ulgi, dopłaty i odliczenia (Kindergeld, dojazdy, podwójne gospodarstwo)"
}
]
POZOSTAŁE POLA (LOCALE: pl):
- name (text): label="Imię i nazwisko", placeholder="Jan Kowalski"
- email (email): label="Adres e-mail", placeholder="[email protected]"
- message (textarea): label="Wiadomość", placeholder="Opisz krótko swoją sytuację..."
- consent (checkbox): label="Wyrażam zgodę na przetwarzanie danych", placeholder=""
=== FORMULARZ PODPIĘTY POD /de/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: de):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Steuervorausberechnung"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Einspruchsverfahren"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: de):
- name (text): label="Vor- und Nachname", placeholder="Max Mustermann"
- email (email): label="E-Mail Adresse", placeholder="[email protected]"
- message (textarea): label="Nachricht", placeholder="Beschreiben Sie kurz Ihre Situation..."
- consent (checkbox): label="Ich stimme der Datenverarbeitung zu", placeholder=""
+88
View File
@@ -0,0 +1,88 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[15:54:43] INFO: [ipal] Plugin initialized.
=== FORMULARZ PODPIĘTY POD /pl/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: pl):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo"
}
]
POZOSTAŁE POLA (LOCALE: pl):
- name (text): label="Imię i nazwisko", placeholder=""
- email (email): label="Adres e-mail", placeholder=""
- message (textarea): label="Wiadomość", placeholder=""
- consent (checkbox): label="Wyrażam zgodę na przetwarzanie danych", placeholder=""
=== FORMULARZ PODPIĘTY POD /de/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: de):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Steuervorausberechnung"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Einspruchsverfahren"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: de):
- name (text): label="Vor- und Nachname", placeholder=""
- email (email): label="E-Mail Adresse", placeholder=""
- message (textarea): label="Nachricht", placeholder=""
- consent (checkbox): label="Ich stimme der Datenverarbeitung zu", placeholder=""
+95
View File
@@ -0,0 +1,95 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[16:00:33] INFO: [ipal] Plugin initialized.
=== FORMULARZ PODPIĘTY POD /pl/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: pl):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Sporządzenie deklaracji podatkowej (Einkommensteuererklärung)"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Wstępne obliczenie przewidywanego zwrotu"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Kontrola decyzji podatkowej (Steuerbescheid)"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Składanie odwołań (Einspruch)"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Całoroczne doradztwo podatkowe"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Doradztwo przy wyborze klasy podatkowej (Steuerklasse)"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Ulgi, dopłaty i odliczenia (Kindergeld, dojazdy, podwójne gospodarstwo)"
}
]
POZOSTAŁE POLA (LOCALE: pl):
- name (text): label="Imię i nazwisko", placeholder=""
- email (email): label="Adres e-mail", placeholder=""
- message (textarea): label="Wiadomość", placeholder=""
- consent (checkbox): label="Wyrażam zgodę na przetwarzanie danych", placeholder=""
=== FORMULARZ PODPIĘTY POD /de/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: de):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Steuervorausberechnung"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Einspruchsverfahren"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: de):
- name (text): label="Vor- und Nachname", placeholder=""
- email (email): label="E-Mail Adresse", placeholder=""
- message (textarea): label="Nachricht", placeholder=""
- consent (checkbox): label="Ich stimme der Datenverarbeitung zu", placeholder=""
+95
View File
@@ -0,0 +1,95 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[16:02:47] INFO: [ipal] Plugin initialized.
=== FORMULARZ PODPIĘTY POD /pl/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: pl):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Sporządzenie deklaracji podatkowej (Einkommensteuererklärung)"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Wstępne obliczenie przewidywanego zwrotu"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Kontrola decyzji podatkowej (Steuerbescheid)"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Składanie odwołań (Einspruch)"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Całoroczne doradztwo podatkowe"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Doradztwo przy wyborze klasy podatkowej (Steuerklasse)"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Ulgi, dopłaty i odliczenia (Kindergeld, dojazdy, podwójne gospodarstwo)"
}
]
POZOSTAŁE POLA (LOCALE: pl):
- name (text): label="Imię i nazwisko", placeholder="Jan Kowalski"
- email (email): label="Adres e-mail", placeholder=""
- message (textarea): label="Wiadomość", placeholder="Opisz krótko swoją sytuację..."
- consent (checkbox): label="Wyrażam zgodę na przetwarzanie danych", placeholder=""
=== FORMULARZ PODPIĘTY POD /de/kontakt (ID: 1) ===
POLE SERVICE OPTIONS (LOCALE: de):
[
{
"id": "6aabf118b9380a1f9b3da1a6",
"value": "sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aabf118b9380a1f9b3da1a7",
"value": "wstepne-obliczenie-przewidywanego-zwrotu",
"label": "Steuervorausberechnung"
},
{
"id": "6aabf118b9380a1f9b3da1a8",
"value": "kontrola-decyzji-podatkowej-steuerbescheid",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aabf118b9380a1f9b3da1a9",
"value": "skladanie-odwolan-einspruch",
"label": "Einspruchsverfahren"
},
{
"id": "6aabf118b9380a1f9b3da1aa",
"value": "caloroczne-doradztwo-podatkowe",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aabf118b9380a1f9b3da1ab",
"value": "doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aabf118b9380a1f9b3da1ac",
"value": "ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
]
POZOSTAŁE POLA (LOCALE: de):
- name (text): label="Vor- und Nachname", placeholder="Max Mustermann"
- email (email): label="E-Mail Adresse", placeholder=""
- message (textarea): label="Nachricht", placeholder="Beschreiben Sie kurz Ihre Situation..."
- consent (checkbox): label="Ich stimme der Datenverarbeitung zu", placeholder=""
+57
View File
@@ -0,0 +1,57 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const pages = await payload.find({
collection: 'pages',
where: {
slug: {
equals: 'kontakt'
}
},
locale: 'pl',
});
if (pages.docs.length === 0) {
console.log("No Kontakt page found");
process.exit(0);
}
const page = pages.docs[0];
console.log("=== LAYOUT PL ===");
if (page.layout) {
page.layout.forEach((block: any, idx: number) => {
console.log(`[${idx}] ${block.blockType}`);
});
} else {
console.log("No layout for PL");
}
console.log("\n=== LAYOUT DE ===");
const pageDe = await payload.findByID({
collection: 'pages',
id: page.id,
locale: 'de',
});
if (pageDe.layout) {
pageDe.layout.forEach((block: any, idx: number) => {
console.log(`[${idx}] ${block.blockType}`);
});
} else {
console.log("No layout for DE");
}
console.log("\n=== FULL DUMP DE ===");
console.log(JSON.stringify(pageDe.layout, null, 2));
console.log("\n=== FULL DUMP PL ===");
console.log(JSON.stringify(page.layout, null, 2));
process.exit(0);
}
run().catch(console.error);
+15
View File
@@ -0,0 +1,15 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const forms = await payload.find({ collection: 'forms', depth: 0 })
console.log('Forms:', forms.docs.map(f => ({ id: f.id, title: f.title })))
const pages = await payload.find({ collection: 'pages', depth: 0 })
console.log('Pages:', pages.docs.map(p => ({ id: p.id, slug: p.slug })))
process.exit(0)
}
run()
+12
View File
@@ -0,0 +1,12 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const pages = await payload.find({ collection: 'pages', depth: 0, locale: 'de' })
console.log('DE Pages:', pages.docs.map(p => ({ id: p.id, slug: p.slug })))
process.exit(0)
}
run()
View File
+369
View File
@@ -0,0 +1,369 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[15:46:43] INFO: [ipal] Plugin initialized.
=== LAYOUT PL ===
[0] pageHeader
[1] contactSection
=== LAYOUT DE ===
[0] pageHeader
[1] contactSection
=== FULL DUMP DE ===
[
{
"id": "6aab9fe4fae4c5f3750e199d",
"title": "Kontakt",
"subtitle": "Haben Sie Fragen zu Ihrer Steuererklärung in Deutschland? Kontaktieren Sie uns — wir helfen Ihnen gerne.",
"image": null,
"blockName": null,
"blockType": "pageHeader"
},
{
"id": "6aab9fe4fae4c5f3750e199e",
"address": "Vom Kunden zu bestätigen",
"phone": "+49 123 456 789",
"email": "[email protected]",
"hours": "Mo-Fr: 9:00 - 17:00\nNach vorheriger Terminvereinbarung",
"form": {
"id": 1,
"title": "Kontaktformular",
"fields": [
{
"id": "6aab2fdb7d8e4b60abd49527",
"name": "name",
"width": null,
"required": true,
"blockName": null,
"blockType": "text",
"label": "Vor- und Nachname",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd49528",
"name": "email",
"width": null,
"required": true,
"blockName": null,
"blockType": "email",
"label": "E-Mail Adresse"
},
{
"id": "6aab2fdb7d8e4b60abd4952a",
"name": "service",
"width": null,
"placeholder": null,
"required": null,
"blockName": null,
"options": [
{
"id": "6aab9bd69f369ef03e6bf859",
"value": "erstellung-der-einkommensteuererklarung",
"label": "Erstellung der Einkommensteuererklärung"
},
{
"id": "6aab9bd69f369ef03e6bf85a",
"value": "steuervorausberechnung",
"label": "Steuervorausberechnung"
},
{
"id": "6aab9bd69f369ef03e6bf85b",
"value": "prufung-des-steuerbescheids",
"label": "Prüfung des Steuerbescheids"
},
{
"id": "6aab9bd69f369ef03e6bf85c",
"value": "einspruchsverfahren",
"label": "Einspruchsverfahren"
},
{
"id": "6aab9bd69f369ef03e6bf85d",
"value": "ganzjahrige-steuerliche-betreuung",
"label": "Ganzjährige steuerliche Betreuung"
},
{
"id": "6aab9bd69f369ef03e6bf85e",
"value": "wahl-der-optimalen-steuerklasse",
"label": "Wahl der optimalen Steuerklasse"
},
{
"id": "6aab9bd69f369ef03e6bf85f",
"value": "freibetrage-kindergeld-and-fahrtkosten",
"label": "Freibeträge, Kindergeld & Fahrtkosten"
}
],
"blockType": "select",
"label": "Dienstleistung",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd4952b",
"name": "message",
"width": null,
"required": true,
"blockName": null,
"blockType": "textarea",
"label": "Nachricht",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd4952c",
"name": "consent",
"width": null,
"required": true,
"defaultValue": null,
"blockName": null,
"blockType": "checkbox",
"label": "Ich stimme der Datenverarbeitung zu"
}
],
"submitButtonLabel": null,
"confirmationType": "message",
"confirmationMessage": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"text": "Vielen Dank für Ihre Nachricht!",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
},
"redirect": {
"type": "reference",
"url": null
},
"emails": [
{
"id": "6aab8cd6f63e48e4b270376c",
"emailTo": "[email protected]",
"cc": null,
"bcc": null,
"replyTo": null,
"emailFrom": "[email protected]",
"subject": "Neue Anfrage über die Website",
"message": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"text": "Jemand hat eine Anfrage über die Website gesendet.",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
}
}
],
"updatedAt": "2026-09-17T07:50:46.201Z",
"createdAt": "2026-09-17T00:10:03.982Z"
},
"blockName": null,
"blockType": "contactSection"
}
]
=== FULL DUMP PL ===
[
{
"id": "6aab9f5e52cb70f317bb9a7b",
"title": "Kontakt",
"subtitle": "Masz pytania dotyczące rozliczenia podatkowego w Niemczech? Skontaktuj się z nami — chętnie pomożemy.",
"image": null,
"blockName": null,
"blockType": "pageHeader"
},
{
"id": "6aab9f5e52cb70f317bb9a7c",
"address": "DO POTWIERDZENIA PRZEZ KLIENTA",
"phone": "+49 123 456 789",
"email": "[email protected]",
"hours": "Pon-Pt: 9:00 - 17:00\nPo wcześniejszym umówieniu",
"form": {
"id": 1,
"title": "Kontaktformular",
"fields": [
{
"id": "6aab2fdb7d8e4b60abd49527",
"name": "name",
"width": null,
"required": true,
"blockName": null,
"blockType": "text",
"label": "Imię i nazwisko",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd49528",
"name": "email",
"width": null,
"required": true,
"blockName": null,
"blockType": "email",
"label": "Adres e-mail"
},
{
"id": "6aab2fdb7d8e4b60abd4952a",
"name": "service",
"width": null,
"placeholder": null,
"required": null,
"blockName": null,
"options": [
{
"id": "6aab9bd69f369ef03e6bf859",
"value": "erstellung-der-einkommensteuererklarung"
},
{
"id": "6aab9bd69f369ef03e6bf85a",
"value": "steuervorausberechnung"
},
{
"id": "6aab9bd69f369ef03e6bf85b",
"value": "prufung-des-steuerbescheids"
},
{
"id": "6aab9bd69f369ef03e6bf85c",
"value": "einspruchsverfahren"
},
{
"id": "6aab9bd69f369ef03e6bf85d",
"value": "ganzjahrige-steuerliche-betreuung"
},
{
"id": "6aab9bd69f369ef03e6bf85e",
"value": "wahl-der-optimalen-steuerklasse"
},
{
"id": "6aab9bd69f369ef03e6bf85f",
"value": "freibetrage-kindergeld-and-fahrtkosten"
}
],
"blockType": "select",
"label": "Usługa",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd4952b",
"name": "message",
"width": null,
"required": true,
"blockName": null,
"blockType": "textarea",
"label": "Wiadomość",
"defaultValue": null
},
{
"id": "6aab2fdb7d8e4b60abd4952c",
"name": "consent",
"width": null,
"required": true,
"defaultValue": null,
"blockName": null,
"blockType": "checkbox",
"label": "Wyrażam zgodę na przetwarzanie danych"
}
],
"submitButtonLabel": null,
"confirmationType": "message",
"confirmationMessage": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"text": "Dziękujemy za wiadomość!",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
},
"redirect": {
"type": "reference",
"url": null
},
"emails": [
{
"id": "6aab8cd6f63e48e4b270376c",
"emailTo": "[email protected]",
"cc": null,
"bcc": null,
"replyTo": null,
"emailFrom": "[email protected]",
"subject": "Nowe zapytanie ze strony",
"message": {
"root": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"text": "Ktoś wysłał zapytanie ze strony.",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"version": 1
}
}
}
],
"updatedAt": "2026-09-17T07:50:46.201Z",
"createdAt": "2026-09-17T00:10:03.982Z"
},
"blockName": null,
"blockType": "contactSection"
}
]
+111
View File
@@ -0,0 +1,111 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import { toSlug } from '@intecion/ipal-kit'
async function run() {
console.log('Rozpoczynam migrację kotwic usług...')
const payload = await getPayload({ config: configPromise })
const locales = ['pl', 'de'] as const
const urls: Record<string, string> = {
pl: '/uslugi',
de: '/leistungen'
}
let updatedPagesCount = 0
for (const locale of locales) {
const pages = await payload.find({
collection: 'pages',
locale,
limit: 100
})
for (const page of pages.docs) {
if (!page.layout) continue
let changed = false
const titleToAnchor: Record<string, string> = {}
// Pass 1: Generate anchors for servicesDetailed
const newLayout = page.layout.map((block: any) => {
if (block.blockType === 'servicesDetailed') {
if (block.services && Array.isArray(block.services)) {
block.services = block.services.map((service: any) => {
if (!service.anchor) {
service.anchor = toSlug(service.title)
changed = true
}
titleToAnchor[service.title] = service.anchor
return service
})
}
}
return block
})
// We need to fetch the ServicesDetailed from the services page if we are on the homepage
// Actually, it's easier to just assume they have similar titles, or we can just fetch the anchors from the services page
// Let's first fetch the services page to build a global map for this locale
const servicesPage = pages.docs.find(p => p.slug === 'uslugi' || p.slug === 'leistungen')
let globalTitleToAnchor: Record<string, string> = {}
if (servicesPage && servicesPage.layout) {
servicesPage.layout.forEach((b: any) => {
if (b.blockType === 'servicesDetailed' && b.services) {
b.services.forEach((s: any) => {
const anchor = s.anchor || toSlug(s.title)
globalTitleToAnchor[s.title] = anchor
// Also map some generic prefixes if needed, but exact match is best
})
}
})
}
// Pass 2: Update servicesList on any page
const finalLayout = newLayout.map((block: any) => {
if (block.blockType === 'servicesList') {
if (block.services && Array.isArray(block.services)) {
block.services = block.services.map((service: any) => {
// Try to find matching anchor
let anchor = globalTitleToAnchor[service.title]
if (!anchor) {
// Fuzzy match
const foundKey = Object.keys(globalTitleToAnchor).find(k =>
k.toLowerCase().includes(service.title.toLowerCase()) ||
service.title.toLowerCase().includes(k.toLowerCase())
)
if (foundKey) anchor = globalTitleToAnchor[foundKey]
}
const newUrl = anchor ? `${urls[locale]}#${anchor}` : urls[locale]
if (service.linkUrl !== newUrl) {
service.linkUrl = newUrl
changed = true
}
return service
})
}
}
return block
})
if (changed) {
console.log(`Aktualizacja strony ${locale.toUpperCase()}: ${page.title} (ID: ${page.id})`)
await payload.update({
collection: 'pages',
id: page.id,
locale,
data: { layout: finalLayout }
})
updatedPagesCount++
}
}
}
console.log(`Zaktualizowano ${updatedPagesCount} stron.`)
process.exit(0)
}
run()
+93
View File
@@ -0,0 +1,93 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import fs from 'fs'
import path from 'path'
async function run() {
const payload = await getPayload({ config: configPromise })
const stepsPL = [
{
title: "Napisz na WhatsApp",
description: "Skontaktuj się z nami bezpośrednio przez WhatsApp lub formularz poniżej, aby rozpocząć i ustalić szczegóły Twojej sytuacji podatkowej."
},
{
title: "Przekaż dokumenty",
description: "Prześlij zaświadczenia o dochodach (Lohnsteuerbescheinigung, EU/EWR), podatkowy numer identyfikacyjny (IdNr) lub PESEL oraz ewentualne potwierdzenia kosztów."
},
{
title: "Odbierz gotowe rozliczenie do podpisu",
description: "Przygotowujemy kompletną deklarację, wyliczamy przewidywany zwrot z urzędu skarbowego i przesyłamy gotowy dokument do Twojej akceptacji i podpisu."
}
];
const finalStepsDE = [
{
title: "WhatsApp kontaktieren",
description: "Schreiben Sie uns direkt über WhatsApp oder das untenstehende Formular, um Ihre Anfrage und steuerliche Situation zu besprechen."
},
{
title: "Unterlagen einreichen",
description: "Übermitteln Sie Ihre Lohnsteuerbescheinigung, Steuer-Identifikationsnummer sowie relevante Belege für Werbungskosten und Freibeträge."
},
{
title: "Fertige Erklärung zur Unterschrift",
description: "Wir erstellen Ihre vollständige Erklärung, berechnen die voraussichtliche Erstattung und übermitteln Ihnen die Unterlagen zur Freigabe."
}
];
// 1. Update PL
const jsuPL = await payload.find({ collection: 'pages', locale: 'pl', where: { slug: { equals: 'jak-sie-umowic' } } })
if (jsuPL.docs.length > 0) {
const doc = jsuPL.docs[0]
const layout = doc.layout || []
let updated = false
for (let i = 0; i < layout.length; i++) {
if (layout[i].blockType === 'process') {
layout[i].steps = stepsPL.map((s: any) => ({
title: s.title,
description: s.description
}))
updated = true
}
}
if (updated) {
await payload.update({
collection: 'pages',
id: doc.id,
locale: 'pl',
data: { layout }
})
console.log("Zaktualizowano kroki dla PL")
}
}
// 2. Update DE
const jsuDE = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'terminvereinbarung' } } })
if (jsuDE.docs.length > 0) {
const doc = jsuDE.docs[0]
const layout = doc.layout || []
let updated = false
for (let i = 0; i < layout.length; i++) {
if (layout[i].blockType === 'process') {
layout[i].steps = finalStepsDE.map((s: any) => ({
title: s.title,
description: s.description
}))
updated = true
}
}
if (updated) {
await payload.update({
collection: 'pages',
id: doc.id,
locale: 'de',
data: { layout }
})
console.log("Zaktualizowano kroki dla DE")
}
}
process.exit(0)
}
run().catch(console.error)
-86
View File
@@ -1,86 +0,0 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import type { Page } from '../src/payload-types'
type PageHeaderBlock = Extract<NonNullable<Page['layout']>[0], { blockType: 'pageHeader' }>
type ContactInfoBlock = Extract<NonNullable<Page['layout']>[0], { blockType: 'contactInfo' }>
const plHeader: PageHeaderBlock = {
blockType: 'pageHeader',
title: 'Kontakt',
subtitle: 'Masz pytania dotyczące rozliczenia podatkowego w Niemczech? Skontaktuj się ze mną — chętnie pomogę.',
}
const deHeader: PageHeaderBlock = {
blockType: 'pageHeader',
title: 'Kontakt',
subtitle: 'Haben Sie Fragen zu Ihrer Steuererklärung in Deutschland? Kontaktieren Sie mich — ich helfe Ihnen gerne.',
}
const plContact: ContactInfoBlock = {
blockType: 'contactInfo',
address: 'DO POTWIERDZENIA PRZEZ KLIENTA',
phone: '+49 123 456 789',
email: '[email protected]',
hours: 'Pon-Pt: 9:00 - 17:00\nPo wcześniejszym umówieniu',
}
const deContact: ContactInfoBlock = {
blockType: 'contactInfo',
address: 'DO POTWIERDZENIA PRZEZ KLIENTA',
phone: '+49 123 456 789',
email: '[email protected]',
hours: 'Mo-Fr: 9:00 - 17:00\nNach vorheriger Terminvereinbarung',
}
async function run() {
console.log('Rozpoczynam odzyskiwanie strony Kontakt (ID 5)...')
const payload = await getPayload({ config: configPromise })
for (const locale of ['pl', 'de'] as const) {
try {
const page = await payload.findByID({
collection: 'pages',
id: 5,
locale: locale
})
const hasPageHeader = page.layout?.some(block => block.blockType === 'pageHeader')
const hasContactInfo = page.layout?.some(block => block.blockType === 'contactInfo')
if (hasPageHeader && hasContactInfo) {
console.log(`[${locale}] Strona Kontakt posiada już bloki pageHeader i contactInfo. Pomijam.`)
continue;
}
console.log(`[${locale}] Przywracam utracone bloki...`)
// Jeśli strona miała jakieś bloki, zachowaj je (z wyjątkiem ewentualnych starych/uszkodzonych wersji tych dwóch)
let newLayout = (page.layout ? page.layout.filter(b => b.blockType !== 'pageHeader' && b.blockType !== 'contactInfo') : []) as NonNullable<Page['layout']>;
// Dodaj nagłówek i info kontaktowe na górę
newLayout.unshift(
(locale === 'de' ? deHeader : plHeader) as unknown as NonNullable<Page['layout']>[0],
(locale === 'de' ? deContact : plContact) as unknown as NonNullable<Page['layout']>[0]
);
await payload.update({
collection: 'pages',
id: 5,
locale: locale,
data: {
layout: newLayout
}
})
console.log(`[${locale}] Zaktualizowano pomyślnie.`)
} catch (error) {
console.error(`[${locale}] Błąd podczas aktualizacji:`, error)
}
}
console.log('Zakończono.')
process.exit(0)
}
run()
+59
View File
@@ -0,0 +1,59 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import fs from 'fs'
import path from 'path'
async function run() {
const payload = await getPayload({ config: configPromise })
const snapshotRaw = fs.readFileSync(path.join(process.cwd(), 'scripts', 'content-snapshot.json'), 'utf8')
const snapshot = JSON.parse(snapshotRaw)
for (const pageSnap of snapshot.pages) {
for (const locale of ['pl', 'de']) {
const pageData = pageSnap[locale]
if (!pageData) continue
// Fetch current page from DB
const pagesInDb = await payload.find({
collection: 'pages',
locale: locale as 'pl' | 'de',
where: { slug: { equals: pageData.slug } }
})
if (pagesInDb.docs.length > 0) {
const dbPage = pagesInDb.docs[0]
let layoutChanged = false
const newLayout = dbPage.layout?.map((dbBlock: any) => {
if (dbBlock.blockType === 'servicesDetailed') {
const snapBlock = pageData.layout.find((b: any) => b.blockType === 'servicesDetailed')
if (snapBlock && snapBlock.services) {
dbBlock.services = snapBlock.services.map((s:any) => {
return {
title: s.title,
description: s.description,
icon: s.icon
}
})
layoutChanged = true
}
}
return dbBlock
})
if (layoutChanged) {
await payload.update({
collection: 'pages',
id: dbPage.id,
locale: locale as 'pl' | 'de',
data: { layout: newLayout }
})
console.log(`Restored servicesDetailed for ${pageData.slug} (${locale})`)
}
}
}
}
process.exit(0)
}
run()
+92
View File
@@ -0,0 +1,92 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const translations = {
pl: {
title: 'Formularz kontaktowy',
confirmationMessage: 'Dziękujemy za wiadomość!',
emailSubject: 'Nowe zapytanie ze strony',
emailMessage: 'Ktoś wysłał zapytanie ze strony.',
fields: [
{ name: 'name', label: 'Imię i nazwisko' },
{ name: 'email', label: 'Adres e-mail' },
{ name: 'service', label: 'Usługa', options: [{ value: 'konsultacje', label: 'Konsultacje' }] },
{ name: 'message', label: 'Wiadomość' },
{ name: 'consent', label: 'Wyrażam zgodę na przetwarzanie danych' }
]
},
de: {
title: 'Kontaktformular',
confirmationMessage: 'Vielen Dank für Ihre Nachricht!',
emailSubject: 'Neue Anfrage über die Website',
emailMessage: 'Jemand hat eine Anfrage über die Website gesendet.',
fields: [
{ name: 'name', label: 'Vor- und Nachname' },
{ name: 'email', label: 'E-Mail Adresse' },
{ name: 'service', label: 'Dienstleistung', options: [{ value: 'konsultacje', label: 'Beratung' }] },
{ name: 'message', label: 'Nachricht' },
{ name: 'consent', label: 'Ich stimme der Datenverarbeitung zu' }
]
}
}
for (const locale of ['pl', 'de'] as const) {
const t = translations[locale]
// First, fetch the form in this locale to get its fields layout
const forms = await payload.find({ collection: 'forms', locale, limit: 1 })
if (forms.docs.length > 0) {
const form = forms.docs[0]
const updatedFields = form.fields?.map((f:any) => {
const tf = t.fields.find(tf => tf.name === f.name)
if (tf) {
f.label = tf.label
if (f.blockType === 'select' && f.options) {
f.options = f.options.map((o:any) => {
const to = tf.options?.find(to => to.value === o.value)
if (to) o.label = to.label
return o
})
}
}
return f
})
const updatedEmails = form.emails?.map((e:any) => {
e.subject = t.emailSubject
e.message = {
root: {
type: 'root',
children: [{ type: 'paragraph', children: [{ type: 'text', text: t.emailMessage, version: 1 }], direction: 'ltr', format: '', indent: 0, version: 1 }],
direction: 'ltr', format: '', indent: 0, version: 1
}
}
return e
})
await payload.update({
collection: 'forms',
id: form.id,
locale,
data: {
title: t.title,
fields: updatedFields,
emails: updatedEmails,
confirmationMessage: {
root: {
type: 'root',
children: [{ type: 'paragraph', children: [{ type: 'text', text: t.confirmationMessage, version: 1 }], direction: 'ltr', format: '', indent: 0, version: 1 }],
direction: 'ltr', format: '', indent: 0, version: 1
}
}
}
})
console.log(`Updated form translations for locale: ${locale}`)
}
}
process.exit(0)
}
run()
+16
View File
@@ -0,0 +1,16 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const forms = await payload.find({ collection: 'forms', locale: 'all' })
for (const form of forms.docs) {
console.log(`Form ID: ${form.id}`)
console.log(`Emails length: ${form.emails?.length || 0}`)
if (form.emails) {
form.emails.forEach(e => console.log(e))
}
}
process.exit(0)
}
run()
+70
View File
@@ -0,0 +1,70 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const mappings: Record<string, Record<string, string>> = {
pl: {
'Deklaracje podatkowe': 'sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung',
'Kontrola decyzji': 'kontrola-decyzji-podatkowej-steuerbescheid',
'Ulgi i dopłaty': 'ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo'
},
de: {
'Steuererklärungen': 'erstellung-der-einkommensteuererklarung',
'Steuerbescheidprüfung': 'prufung-des-steuerbescheids',
'Vergünstigungen und Zuschüsse': 'freibetrage-kindergeld-and-fahrtkosten'
}
}
const urls: Record<string, string> = {
pl: '/uslugi',
de: '/leistungen'
}
for (const locale of ['pl', 'de'] as const) {
const pages = await payload.find({
collection: 'pages',
locale,
where: { slug: { equals: 'home' } }
})
if (pages.docs.length > 0) {
const homePage = pages.docs[0]
if (homePage.layout) {
let changed = false
const newLayout = homePage.layout.map((block: any) => {
if (block.blockType === 'servicesList' && block.services) {
block.services = block.services.map((service: any) => {
const anchor = mappings[locale][service.title]
const newUrl = anchor ? `${urls[locale]}#${anchor}` : urls[locale]
if (service.linkUrl !== newUrl) {
service.linkUrl = newUrl
changed = true
}
return service
})
}
return block
})
if (changed) {
await payload.update({
collection: 'pages',
id: homePage.id,
locale,
data: { layout: newLayout }
})
}
console.log(`\nStrona ${locale.toUpperCase()} (Home) zaktualizowane linki:`)
newLayout.find((b:any) => b.blockType === 'servicesList')?.services?.forEach((s:any) => {
console.log(` - ${s.title} -> ${s.linkUrl}`)
})
}
}
}
process.exit(0)
}
run()
+31
View File
@@ -0,0 +1,31 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
console.log("Submitting form with empty data using payload.create...")
try {
const result = await payload.create({
collection: 'form-submissions',
data: {
form: 1,
submissionData: [
{ field: 'name', value: '' },
{ field: 'email', value: '' },
{ field: 'message', value: '' },
{ field: 'consent', value: 'true' }
]
}
})
console.log("Submit form result ID:", result.id)
console.log("Submission data:", JSON.stringify(result.submissionData, null, 2))
} catch (err) {
console.error("Error submitting form:", err)
}
process.exit(0)
}
run().catch(console.error)
+9
View File
@@ -0,0 +1,9 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const pages = await payload.find({ collection: 'pages', locale: 'all', limit: 100 })
pages.docs.forEach(p => console.log(p.slug))
process.exit(0)
}
run()
+38
View File
@@ -0,0 +1,38 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
import { submitForm } from '@intecion/ipal-kit/server'
async function run() {
const payload = await getPayload({ config: configPromise })
console.log("Submitting form with empty data using submitForm action...")
try {
const result = await submitForm({
payload,
formId: "1",
data: {
name: "",
email: "",
message: "",
consent: true
}
})
console.log("Submit form result:", result)
// Now fetch the latest submission to see what was saved
const submissions = await payload.find({
collection: 'form-submissions',
sort: '-createdAt',
limit: 1
})
console.log("Latest submission data:", JSON.stringify(submissions.docs[0].submissionData, null, 2))
} catch (err) {
console.error("Error submitting form:", err)
}
process.exit(0)
}
run().catch(console.error)
+41
View File
@@ -0,0 +1,41 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
await payload.update({
collection: 'forms',
id: 1,
data: {
emails: [
{
emailTo: '[email protected]',
emailFrom: '[email protected]',
subject: 'Nowe zapytanie ze strony',
message: {
root: {
type: 'root',
children: [
{
type: 'paragraph',
children: [{ type: 'text', text: 'Ktoś wysłał zapytanie ze strony.', version: 1 }],
direction: 'ltr',
format: '',
indent: 0,
version: 1
}
],
direction: 'ltr',
format: '',
indent: 0,
version: 1
}
}
}
]
}
})
process.exit(0)
}
run()
+22
View File
@@ -0,0 +1,22 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
for (const locale of ['pl', 'de']) {
const slug = locale === 'pl' ? 'uslugi' : 'leistungen'
const pages = await payload.find({ collection: 'pages', locale: locale as any, where: { slug: { equals: slug } } })
if (pages.docs.length > 0) {
const page = pages.docs[0]
page.layout?.forEach((b:any) => {
if (b.blockType === 'servicesDetailed' && b.services) {
b.services.forEach((s:any) => console.log(`${locale.toUpperCase()}: "${s.title}" -> ${s.anchor}`))
}
})
}
}
process.exit(0)
}
run()
+26
View File
@@ -0,0 +1,26 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
for (const locale of ['pl', 'de']) {
const slug = locale === 'pl' ? 'uslugi' : 'leistungen'
const pages = await payload.find({ collection: 'pages', locale: locale as any, where: { slug: { equals: slug } } })
if (pages.docs.length > 0) {
const page = pages.docs[0]
console.log(`\n=== INTEGRALNOŚĆ STRONY: ${slug} (${locale}) ===`)
page.layout?.forEach((b:any) => {
console.log(`Block: ${b.blockType}`)
if (b.blockType === 'pageHeader') console.log(` - title: ${b.title}`)
if (b.blockType === 'eligibility') console.log(` - eligibleTitle: ${b.eligibleTitle}`)
if (b.blockType === 'finalCta') console.log(` - title: ${b.title}`)
})
} else {
console.log(`Nie znaleziono strony ${slug} w języku ${locale}`)
}
}
process.exit(0)
}
run()
+61
View File
@@ -0,0 +1,61 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
console.log("Symulacja odebrania FormData(puste pola) na backendzie (zgodnie z logiką validateSubmission)...")
const incomingData: Record<string, any> = {
name: "",
email: "",
message: "",
consent: true // Pomijamy consent
}
console.log("Dane wejściowe (z FormData):", incomingData)
const form: any = await payload.findByID({ id: 1, collection: 'forms', depth: 0 })
const fields = form.fields || []
let validationResult: any = { ok: true, cleaned: {} }
for (const field of fields) {
if (field.blockType === 'message') continue;
const value = incomingData[field.name]
const isBlank = value == null || (typeof value === 'string' && value.trim() === '') || value === false
if (field.required && isBlank) {
validationResult = { field: field.name, kind: 'required', ok: false, reason: 'invalid' }
break;
}
if (value !== undefined) {
validationResult.cleaned[field.name] = value
}
}
console.log("\\n=== Wynik validateSubmission ===")
console.log(JSON.stringify(validationResult, null, 2))
if (validationResult.ok) {
console.log("\\nTworzenie wpisu w bazie przez payload.create (symulacja zapisu)...")
const submission = await payload.create({
collection: 'form-submissions',
data: {
form: 1,
submissionData: Object.entries(validationResult.cleaned).map(([field, value]) => ({
field,
value: value == null ? '' : String(value),
})) as any,
}
})
console.log("\\nZapisano w bazie:", JSON.stringify(submission.submissionData, null, 2))
} else {
console.log("\\nFormularz odrzucony na poziomie API backendowego (validateSubmission) - rekord NIE trafił do bazy, użytkownik dostaje błąd o braku pola.")
}
process.exit(0)
}
run().catch(console.error)
+124
View File
@@ -0,0 +1,124 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const servicesData: Record<string, { label: string, value: string }[]> = { pl: [], de: [] }
for (const locale of ['pl', 'de']) {
const pages = await payload.find({
collection: 'pages',
locale: locale as 'pl' | 'de',
where: { slug: { equals: locale === 'de' ? 'leistungen' : 'uslugi' } }
})
if (pages.docs.length > 0) {
const dbPage = pages.docs[0]
const servicesBlock = dbPage.layout?.find((b: any) => b.blockType === 'servicesDetailed') as any
if (servicesBlock && servicesBlock.services) {
servicesData[locale] = servicesBlock.services.map((s: any) => ({
label: s.title,
value: s.anchor || s.title.toLowerCase().replace(/[^a-z0-9]+/g, '-')
}))
}
}
}
const baseValues = servicesData['pl'].map(s => s.value);
// First pass: PL. This will create the options (or update them).
let form = await payload.findByID({
collection: 'forms',
id: 1,
locale: 'pl',
})
let updatedFieldsPL = form.fields?.map((f: any) => {
if (f.name === 'name') {
f.defaultValue = 'Jan Kowalski'
f.label = 'Imię i nazwisko'
}
if (f.name === 'email') {
f.defaultValue = '[email protected]'
f.label = 'Adres e-mail'
}
if (f.name === 'message') {
f.defaultValue = 'Opisz krótko swoją sytuację...'
f.label = 'Wiadomość'
}
if (f.name === 'consent') {
f.label = 'Wyrażam zgodę na przetwarzanie danych'
}
if (f.name === 'service' && f.blockType === 'select') {
f.label = 'Usługa'
f.options = servicesData['pl'].map((s: any, idx: number) => {
// preserve existing id if we have the exact same amount of options
const existingOption = f.options?.[idx];
return {
id: existingOption ? existingOption.id : undefined,
label: s.label,
value: baseValues[idx]
}
})
}
return f
})
await payload.update({
collection: 'forms',
id: 1,
locale: 'pl',
data: { fields: updatedFieldsPL }
})
console.log(`Updated form 1 for locale pl`)
// Refetch the form to get the assigned IDs of the options!
form = await payload.findByID({
collection: 'forms',
id: 1,
locale: 'all', // Get all locales to see the IDs
})
let updatedFieldsDE = form.fields?.map((f: any) => {
if (f.name === 'name') {
f.defaultValue = 'Max Mustermann'
f.label = 'Vor- und Nachname'
}
if (f.name === 'email') {
f.defaultValue = '[email protected]'
f.label = 'E-Mail Adresse'
}
if (f.name === 'message') {
f.defaultValue = 'Beschreiben Sie kurz Ihre Situation...'
f.label = 'Nachricht'
}
if (f.name === 'consent') {
f.label = 'Ich stimme der Datenverarbeitung zu'
}
if (f.name === 'service' && f.blockType === 'select') {
f.label = 'Dienstleistung'
f.options = servicesData['de'].map((s: any, idx: number) => {
// VERY IMPORTANT: Use the ID assigned during the PL update
const optionId = f.options?.[idx]?.id;
return {
id: optionId,
label: s.label,
value: baseValues[idx]
}
})
}
return f
})
await payload.update({
collection: 'forms',
id: 1,
locale: 'de',
data: { fields: updatedFieldsDE }
})
console.log(`Updated form 1 for locale de`)
process.exit(0)
}
run().catch(console.error)
+64
View File
@@ -0,0 +1,64 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[15:53:24] INFO: [ipal] Plugin initialized.
Services: {
pl: [
{
label: 'Sporządzenie deklaracji podatkowej (Einkommensteuererklärung)',
value: 'sporzadzenie-deklaracji-podatkowej-einkommensteuererklarung'
},
{
label: 'Wstępne obliczenie przewidywanego zwrotu',
value: 'wstepne-obliczenie-przewidywanego-zwrotu'
},
{
label: 'Kontrola decyzji podatkowej (Steuerbescheid)',
value: 'kontrola-decyzji-podatkowej-steuerbescheid'
},
{
label: 'Składanie odwołań (Einspruch)',
value: 'skladanie-odwolan-einspruch'
},
{
label: 'Całoroczne doradztwo podatkowe',
value: 'caloroczne-doradztwo-podatkowe'
},
{
label: 'Doradztwo przy wyborze klasy podatkowej (Steuerklasse)',
value: 'doradztwo-przy-wyborze-klasy-podatkowej-steuerklasse'
},
{
label: 'Ulgi, dopłaty i odliczenia (Kindergeld, dojazdy, podwójne gospodarstwo)',
value: 'ulgi-doplaty-i-odliczenia-kindergeld-dojazdy-podwojne-gospodarstwo'
}
],
de: [
{
label: 'Erstellung der Einkommensteuererklärung',
value: 'erstellung-der-einkommensteuererklarung'
},
{
label: 'Steuervorausberechnung',
value: 'steuervorausberechnung'
},
{
label: 'Prüfung des Steuerbescheids',
value: 'prufung-des-steuerbescheids'
},
{ label: 'Einspruchsverfahren', value: 'einspruchsverfahren' },
{
label: 'Ganzjährige steuerliche Betreuung',
value: 'ganzjahrige-steuerliche-betreuung'
},
{
label: 'Wahl der optimalen Steuerklasse',
value: 'wahl-der-optimalen-steuerklasse'
},
{
label: 'Freibeträge, Kindergeld & Fahrtkosten',
value: 'freibetrage-kindergeld-and-fahrtkosten'
}
]
}
Updated form 1 for locale pl
Updated form 1 for locale de
+13
View File
@@ -0,0 +1,13 @@
[⣷] Pulling schema from database...
[✓] Pulling schema from database...
[16:07:07] INFO: [ipal] Plugin initialized.
Symulacja odebrania FormData(puste pola) na backendzie (zgodnie z logiką validateSubmission)...
Dane wejściowe (z FormData): { name: '', email: '', message: '', consent: true }
\n=== Wynik validateSubmission ===
{
"field": "name",
"kind": "required",
"ok": false,
"reason": "invalid"
}
\nFormularz odrzucony na poziomie API backendowego (validateSubmission) - rekord NIE trafił do bazy, użytkownik dostaje błąd o braku pola.
+30
View File
@@ -0,0 +1,30 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const headerDE = await payload.findGlobal({ slug: 'header', locale: 'de' });
const footerDE = await payload.findGlobal({ slug: 'footer', locale: 'de' });
console.log('--- HEADER NAV DE ---');
headerDE.navigation?.forEach((nav: any) => {
if (nav.page && nav.page.slug === 'kontakt') {
const page = nav.page;
console.log('Header Kontakt Page Subtitle:', page.layout[0].subtitle);
console.log('Header Kontakt Page Address:', page.layout[1].address);
}
});
console.log('--- FOOTER NAV DE ---');
footerDE.navigation?.forEach((nav: any) => {
if (nav.page && nav.page.slug === 'kontakt') {
const page = nav.page;
console.log('Footer Kontakt Page Subtitle:', page.layout[0].subtitle);
console.log('Footer Kontakt Page Address:', page.layout[1].address);
}
});
process.exit(0);
}
run()
+7 -18
View File
@@ -4,24 +4,13 @@ import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const plPage = await payload.findByID({
collection: 'pages',
id: 5,
locale: 'pl'
})
const dePage = await payload.findByID({
collection: 'pages',
id: 5,
locale: 'de'
})
console.log("=== KONTAKT PL LAYOUT ===")
console.log(JSON.stringify(plPage.layout, null, 2))
console.log("=== KONTAKT DE LAYOUT ===")
console.log(JSON.stringify(dePage.layout, null, 2))
const formConf = payload.collections['forms'].config;
const titleField = formConf.fields.find(f => f.name === 'title');
console.log('Form title is localized:', titleField?.localized);
process.exit(0)
}
const kontaktALL = await payload.find({ collection: 'pages', locale: 'all', where: { slug: { equals: 'kontakt' } } });
console.log(JSON.stringify(kontaktALL.docs[0], null, 2));
process.exit(0);
}
run()
+10
View File
@@ -0,0 +1,10 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const k = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'kontakt' } } });
console.log(JSON.stringify(k.docs[0].layout, null, 2));
process.exit(0);
}
run()
+27
View File
@@ -0,0 +1,27 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
console.log('--- VERIFICATION ---');
const k = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'kontakt' } } });
console.log('Kontakt DE layout[0].subtitle:', k.docs[0].layout[0].subtitle);
console.log('Kontakt DE layout[1].address:', k.docs[0].layout[1].address);
console.log('Kontakt DE layout[1].hours:', k.docs[0].layout[1].hours);
const j = await payload.find({ collection: 'pages', locale: 'de', where: { slug: { equals: 'terminvereinbarung' } } });
if (j.docs.length > 0) {
console.log('JSU DE layout[2].address:', j.docs[0].layout[2].address);
} else {
console.log('JSU DE not found with slug terminvereinbarung');
}
const c = await payload.findGlobal({ slug: 'company', locale: 'de' });
console.log('Company DE address:', c.address);
console.log('Company DE hours:', c.hours);
process.exit(0);
}
run()