From 3004247ceba0c10ce2bbfecd3db1c160dd07d173 Mon Sep 17 00:00:00 2001 From: MichalC <103170279+wSBMichalee@users.noreply.github.com> Date: Thu, 17 Sep 2026 23:47:24 +0200 Subject: [PATCH] feat(services): make detailed service cards clickable links to contact page with hover effects --- scripts/assign_heroes.ts | 100 ---------------------- scripts/assign_heroes_fixed.ts | 62 -------------- scripts/check_all_media.ts | 14 --- scripts/check_arrays.ts | 37 -------- scripts/check_hero_media.ts | 33 ------- scripts/check_testimonials.ts | 30 ------- scripts/dump_form.ts | 47 ---------- scripts/inspect_home_and_media.ts | 58 ------------- scripts/restore_jak_sie_umowic.ts | 93 -------------------- scripts/verify_kontakt_db.ts | 16 ---- scripts/verify_translations_final.ts | 27 ------ src/blocks/ServicesDetailed/Component.tsx | 66 ++++++++------ 12 files changed, 40 insertions(+), 543 deletions(-) delete mode 100644 scripts/assign_heroes.ts delete mode 100644 scripts/assign_heroes_fixed.ts delete mode 100644 scripts/check_all_media.ts delete mode 100644 scripts/check_arrays.ts delete mode 100644 scripts/check_hero_media.ts delete mode 100644 scripts/check_testimonials.ts delete mode 100644 scripts/dump_form.ts delete mode 100644 scripts/inspect_home_and_media.ts delete mode 100644 scripts/restore_jak_sie_umowic.ts delete mode 100644 scripts/verify_kontakt_db.ts delete mode 100644 scripts/verify_translations_final.ts diff --git a/scripts/assign_heroes.ts b/scripts/assign_heroes.ts deleted file mode 100644 index 37580eb..0000000 --- a/scripts/assign_heroes.ts +++ /dev/null @@ -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) diff --git a/scripts/assign_heroes_fixed.ts b/scripts/assign_heroes_fixed.ts deleted file mode 100644 index 9bad254..0000000 --- a/scripts/assign_heroes_fixed.ts +++ /dev/null @@ -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) diff --git a/scripts/check_all_media.ts b/scripts/check_all_media.ts deleted file mode 100644 index dd60b77..0000000 --- a/scripts/check_all_media.ts +++ /dev/null @@ -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) diff --git a/scripts/check_arrays.ts b/scripts/check_arrays.ts deleted file mode 100644 index a0e7417..0000000 --- a/scripts/check_arrays.ts +++ /dev/null @@ -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) diff --git a/scripts/check_hero_media.ts b/scripts/check_hero_media.ts deleted file mode 100644 index 96dbda6..0000000 --- a/scripts/check_hero_media.ts +++ /dev/null @@ -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) diff --git a/scripts/check_testimonials.ts b/scripts/check_testimonials.ts deleted file mode 100644 index 3d686ab..0000000 --- a/scripts/check_testimonials.ts +++ /dev/null @@ -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() diff --git a/scripts/dump_form.ts b/scripts/dump_form.ts deleted file mode 100644 index a27468e..0000000 --- a/scripts/dump_form.ts +++ /dev/null @@ -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' ? 'jan@przyklad.pl' : 'max@beispiel.de') : ''); - console.log(`- ${f.name} (${f.blockType}): label="${f.label}", placeholder="${placeholderValue}"`); - } - }); - } - } - } - - process.exit(0); -} - -run().catch(console.error); diff --git a/scripts/inspect_home_and_media.ts b/scripts/inspect_home_and_media.ts deleted file mode 100644 index 8fc1e5b..0000000 --- a/scripts/inspect_home_and_media.ts +++ /dev/null @@ -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) diff --git a/scripts/restore_jak_sie_umowic.ts b/scripts/restore_jak_sie_umowic.ts deleted file mode 100644 index b4c934d..0000000 --- a/scripts/restore_jak_sie_umowic.ts +++ /dev/null @@ -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) diff --git a/scripts/verify_kontakt_db.ts b/scripts/verify_kontakt_db.ts deleted file mode 100644 index 53292e3..0000000 --- a/scripts/verify_kontakt_db.ts +++ /dev/null @@ -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() diff --git a/scripts/verify_translations_final.ts b/scripts/verify_translations_final.ts deleted file mode 100644 index d3fc909..0000000 --- a/scripts/verify_translations_final.ts +++ /dev/null @@ -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() diff --git a/src/blocks/ServicesDetailed/Component.tsx b/src/blocks/ServicesDetailed/Component.tsx index de65bfc..6a6c22e 100644 --- a/src/blocks/ServicesDetailed/Component.tsx +++ b/src/blocks/ServicesDetailed/Component.tsx @@ -1,6 +1,8 @@ 'use client' import React from 'react' import { motion } from 'framer-motion' +import Link from 'next/link' +import { usePathname } from 'next/navigation' import { FileText, Calculator, @@ -10,6 +12,7 @@ import { Users, Coins, LucideIcon, + ArrowRight, } from 'lucide-react' import type { Page } from '../../payload-types' @@ -31,7 +34,10 @@ export const ServicesDetailedBlock: React.FC = ({ services, }) => { const serviceList = services || [] - const hasBento = serviceList.length >= 3 + const pathname = usePathname() + const isDe = pathname?.split('/').filter(Boolean)[0] === 'de' + const contactHref = isDe ? '/de/kontakt' : '/kontakt' + const contactText = isDe ? 'Kontakt aufnehmen' : 'Skontaktuj się' return (
@@ -73,35 +79,43 @@ export const ServicesDetailedBlock: React.FC = ({ transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] } } }} - className={`${isFirst ? 'md:col-span-2' : 'md:col-span-1'} - bg-card border border-border p-6 md:p-8 flex flex-col relative overflow-hidden group hover:border-border/80 transition-colors - `} + className={`${isFirst ? 'md:col-span-2' : 'md:col-span-1'} flex flex-col`} > - {/* Górny cienki akcent (line-draw przy wejściu) */} - + + {/* Górny cienki akcent (line-draw przy wejściu) */} + -
-
- +
+
+ +
+

+ {service.title} +

-

- {service.title} -

-
-

- {service.description} -

+

+ {service.description} +

+ +
+ {contactText} + +
+ ) })}