feat(services): make detailed service cards clickable links to contact page with hover effects

This commit is contained in:
MichalC
2026-09-17 23:47:24 +02:00
parent b281c5ffd1
commit 3004247ceb
12 changed files with 40 additions and 543 deletions
-100
View File
@@ -1,100 +0,0 @@
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 })
// 1. Create media records
const mediaDir = path.join(process.cwd(), 'media')
const files = fs.readdirSync(mediaDir).filter(f => f !== '.DS_Store' && f !== 'placeholder-desk.jpg' && f.endsWith('.png'))
const mediaIds = []
for (const file of files) {
const filePath = path.join(mediaDir, file)
const existing = await payload.find({
collection: 'media',
where: { filename: { equals: file } }
})
if (existing.docs.length > 0) {
mediaIds.push(existing.docs[0].id)
} else {
console.log(`Creating media record for ${file}`)
try {
const created = await payload.create({
collection: 'media',
data: { alt: 'Hero background' },
file: {
data: fs.readFileSync(filePath),
mimetype: 'image/png',
name: file,
size: fs.statSync(filePath).size
}
})
mediaIds.push(created.id)
} catch (e) {
console.error("Error creating", file, e.message)
}
}
}
console.log(`Available hero media IDs: ${mediaIds.join(', ')}`)
if (mediaIds.length === 0) {
console.error("No media ids found! Exiting.")
process.exit(1)
}
// 2. Update all pages
const locales = ['pl', 'de']
let mediaIndex = 0
for (const locale of locales) {
const pages = await payload.find({ collection: 'pages', locale: locale as any, limit: 100 })
for (const page of pages.docs) {
const imgId = mediaIds[mediaIndex % mediaIds.length]
mediaIndex++
let changed = false
const layout = page.layout || []
if (page.slug === 'home') {
// Find hero block
const heroBlock = layout.find((b: any) => b.blockType === 'hero')
if (heroBlock && !heroBlock.backgroundImage) {
heroBlock.backgroundImage = imgId
changed = true
console.log(`Updated home page (${locale}) hero image.`)
}
} else {
// Find pageHeader block
const headerBlock = layout.find((b: any) => b.blockType === 'pageHeader')
if (headerBlock && !headerBlock.image) {
headerBlock.image = imgId
changed = true
console.log(`Updated ${page.slug} (${locale}) pageHeader image.`)
} else if (!headerBlock) {
// If no pageHeader, should we add it?
// Usually every page has it, except some legal pages. Let's just update existing ones first.
}
}
if (changed) {
await payload.update({
collection: 'pages',
id: page.id,
locale: locale as any,
data: { layout }
})
}
}
}
console.log("Done updating pages.")
process.exit(0)
}
run().catch(console.error)
-62
View File
@@ -1,62 +0,0 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
// Get media ids
const media = await payload.find({ collection: 'media', limit: 100 })
const mediaIds = media.docs.map(m => m.id)
if (mediaIds.length === 0) {
console.error("No media ids found! Exiting.")
process.exit(1)
}
// Update all pages
const locales = ['pl', 'de']
let mediaIndex = 0
for (const locale of locales) {
const pages = await payload.find({ collection: 'pages', locale: locale as any, limit: 100 })
for (const page of pages.docs) {
const imgId = mediaIds[mediaIndex % mediaIds.length]
mediaIndex++
let changed = false
const layout = page.layout || []
if (page.slug === 'home') {
// Find hero block
const heroBlock = layout.find((b: any) => b.blockType === 'hero')
if (heroBlock && !heroBlock.image) {
heroBlock.image = imgId
changed = true
console.log(`Updated home page (${locale}) hero image.`)
}
} else {
// Find pageHeader block
const headerBlock = layout.find((b: any) => b.blockType === 'pageHeader')
if (headerBlock && !headerBlock.image) {
headerBlock.image = imgId
changed = true
console.log(`Updated ${page.slug} (${locale}) pageHeader image.`)
}
}
if (changed) {
await payload.update({
collection: 'pages',
id: page.id,
locale: locale as any,
data: { layout }
})
}
}
}
console.log("Done updating pages with FIXED fields.")
process.exit(0)
}
run().catch(console.error)
-14
View File
@@ -1,14 +0,0 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const media = await payload.find({ collection: 'media', limit: 100 })
console.log("=== ALL MEDIA ===")
media.docs.forEach(m => {
console.log(`- ID: ${m.id} | Filename: ${m.filename} | Alt: ${m.alt}`)
})
process.exit(0)
}
run().catch(console.error)
-37
View File
@@ -1,37 +0,0 @@
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)
-33
View File
@@ -1,33 +0,0 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const media = await payload.find({ collection: 'media', limit: 100 })
console.log("=== MEDIA ===")
media.docs.forEach(m => {
if (m.filename?.includes('hero') || m.alt?.toLowerCase().includes('hero') || m.url?.includes('hero')) {
console.log(`- ID: ${m.id} | Filename: ${m.filename} | Alt: ${m.alt}`)
}
})
// Fallback: list all media if no hero found
if (media.docs.length > 0 && !media.docs.some(m => m.filename?.includes('hero'))) {
console.log("No explicit 'hero' in filename. Listing all media:")
media.docs.forEach(m => console.log(`- ID: ${m.id} | Filename: ${m.filename} | Alt: ${m.alt}`))
}
const pages = await payload.find({ collection: 'pages', locale: 'pl', limit: 100 })
console.log("\n=== PAGES ===")
pages.docs.forEach(p => {
const heroBlock = p.layout?.find(b => b.blockType === 'pageHeader')
console.log(`Page: ${p.slug} | Has pageHeader: ${!!heroBlock}`)
if (heroBlock) {
console.log(` Title: ${heroBlock.title}`)
console.log(` Background: ${heroBlock.backgroundImage}`)
}
})
process.exit(0)
}
run().catch(console.error)
-30
View File
@@ -1,30 +0,0 @@
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', limit: 100 }) // fetch all locales?
const plPages = await payload.find({ collection: 'pages', locale: 'pl', limit: 100 })
const dePages = await payload.find({ collection: 'pages', locale: 'de', limit: 100 })
console.log("=== PL ===")
plPages.docs.forEach(page => {
page.layout?.forEach(block => {
if (block.blockType === 'testimonials' || block.blockType === 'testimonialsGrid') {
console.log(`Page: ${page.slug}, Block: ${block.blockType}, Items: ${block.testimonials?.length || 0}`)
}
})
})
console.log("=== DE ===")
dePages.docs.forEach(page => {
page.layout?.forEach(block => {
if (block.blockType === 'testimonials' || block.blockType === 'testimonialsGrid') {
console.log(`Page: ${page.slug}, Block: ${block.blockType}, Items: ${block.testimonials?.length || 0}`)
}
})
})
process.exit(0)
}
run()
-47
View File
@@ -1,47 +0,0 @@
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);
-58
View File
@@ -1,58 +0,0 @@
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 })
// Create media records if they don't exist
const mediaDir = path.join(__dirname, '../media')
const files = fs.readdirSync(mediaDir).filter(f => f !== '.DS_Store' && f !== 'placeholder-desk.jpg')
const mediaRecords = []
for (const file of files) {
const filePath = path.join(mediaDir, file)
// Check if exists in db
const existing = await payload.find({
collection: 'media',
where: { filename: { equals: file } }
})
if (existing.docs.length > 0) {
mediaRecords.push(existing.docs[0])
} else {
console.log(`Creating media record for ${file}`)
// Have to read file and pass to payload.create
// It's tricky to upload local file via local API without express req
// Let's just create the db record manually?
// No, payload.create({ collection: 'media', data: { alt: 'Hero image' }, file: { data: fs.readFileSync(filePath), mimetype: 'image/png', name: file, size: fs.statSync(filePath).size } })
try {
const created = await payload.create({
collection: 'media',
data: { alt: 'Hero background' },
file: {
data: fs.readFileSync(filePath),
mimetype: 'image/png',
name: file,
size: fs.statSync(filePath).size
}
})
mediaRecords.push(created)
} catch (e) {
console.error("Error creating", file, e.message)
}
}
}
console.log(`Found/Created ${mediaRecords.length} media records.`)
// Dump home page
const home = await payload.find({ collection: 'pages', where: { slug: { equals: 'home' } } })
console.log("Home Layout:")
home.docs[0]?.layout?.forEach(b => console.log(b.blockType))
process.exit(0)
}
run().catch(console.error)
-93
View File
@@ -1,93 +0,0 @@
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)
-16
View File
@@ -1,16 +0,0 @@
import { getPayload } from 'payload'
import configPromise from '../src/payload.config'
async function run() {
const payload = await getPayload({ config: configPromise })
const formConf = payload.collections['forms'].config;
const titleField = formConf.fields.find(f => f.name === 'title');
console.log('Form title is localized:', titleField?.localized);
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()
-27
View File
@@ -1,27 +0,0 @@
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()