diff --git a/scripts/migrate_faq.ts b/scripts/migrate_faq.ts new file mode 100644 index 0000000..35e7c06 --- /dev/null +++ b/scripts/migrate_faq.ts @@ -0,0 +1,176 @@ +import { getPayload } from 'payload' +import configPromise from '../src/payload.config' +import type { Page } from '../src/payload-types' +type FAQFullBlock = Extract[0], { blockType: 'faqFull' }>; + +const PLACEHOLDER_ANSWER_PL = "Odpowiedź w przygotowaniu — treść do potwierdzenia przez klienta/doradcę podatkowego"; +const PLACEHOLDER_ANSWER_DE = "Antwort in Vorbereitung — Inhalt muss vom Kunden/Steuerberater bestätigt werden"; + +const questions_pl: FAQFullBlock['questions'] = [ + { + category: 'Proces i dokumenty', + question: 'Czy muszę przyjeżdżać osobiście do biura?', + answer: 'Nie, wszystkie formalności możemy załatwić w 100% online lub pocztą tradycyjną. Dokumenty możesz wysłać bezpiecznym kurierem lub przez e-mail, a my zajmiemy się resztą.', + }, + { + category: 'Proces i dokumenty', + question: 'Jakie dokumenty są potrzebne do rozliczenia?', + answer: 'Podstawą jest roczne zestawienie zarobków (Lohnsteuerbescheinigung), dowód tożsamości oraz zaświadczenie o dochodach w Polsce (EU/EWR). Otrzymasz od nas szczegółową listę dopasowaną do Twojej sytuacji.', + }, + { + category: 'Proces i dokumenty', + question: 'Do kiedy muszę złożyć deklarację podatkową w Niemczech?', + answer: 'Standardowy termin to 31 lipca roku następującego po roku podatkowym. Jeśli korzystasz z usług doradcy podatkowego, termin jest automatycznie wydłużany, co daje Ci więcej czasu na zgromadzenie dokumentów.', + }, + { + category: 'Zwrot podatku i koszty', + question: 'Jak długo czeka się na zwrot podatku z urzędu skarbowego?', + answer: 'Średni czas oczekiwania na decyzję Finanzamtu to od 2 do 6 miesięcy, zależnie od obciążenia urzędu. Nasze staranne przygotowanie dokumentów minimalizuje ryzyko dodatkowych zapytań i przyspiesza proces.', + }, + { + category: 'Zwrot podatku i koszty', + question: 'Ile kosztuje rozliczenie podatku z Niemiec?', + answer: 'Opłaty doradców podatkowych w Niemczech są regulowane ustawowo (StBVV) i zależą od skomplikowania sprawy oraz wysokości dochodów. Zawsze przedstawiamy jasną wycenę przed podjęciem działań, bez ukrytych kosztów.', + }, + { + category: 'Świadczenia dodatkowe', + question: 'Czy załatwiacie również zasiłek Kindergeld?', + answer: 'Tak, pomagamy w pełnym procesie wnioskowania o zasiłek na dzieci (Kindergeld) z Familienkasse. Zajmujemy się kompletowaniem załączników, weryfikacją stanu rodziny oraz korespondencją z urzędem.', + }, + { + category: 'Dodatkowe (DO UZUPEŁNIENIA)', + question: 'Czy mogę się rozliczyć, jeśli pracowałem w Niemczech tylko kilka miesięcy?', + answer: PLACEHOLDER_ANSWER_PL, + }, + { + category: 'Dodatkowe (DO UZUPEŁNIENIA)', + question: 'Co się stanie, jeśli spóźnię się ze złożeniem deklaracji?', + answer: PLACEHOLDER_ANSWER_PL, + }, + { + category: 'Dodatkowe (DO UZUPEŁNIENIA)', + question: 'Czy mogę rozliczyć się wspólnie z małżonkiem, jeśli on/ona nie pracuje w Niemczech?', + answer: PLACEHOLDER_ANSWER_PL, + }, + { + category: 'Dodatkowe (DO UZUPEŁNIENIA)', + question: 'Czy pomagacie też w rozliczeniu za lata wcześniejsze (wsteczne)?', + answer: PLACEHOLDER_ANSWER_PL, + } +]; + +const questions_de: FAQFullBlock['questions'] = [ + { + category: 'Prozess und Dokumente', + question: 'Muss ich persönlich ins Büro kommen?', + answer: 'Nein, alle Formalitäten können wir zu 100% online oder per Post erledigen. Sie können die Dokumente sicher per Kurier oder E-Mail senden, und wir kümmern uns um den Rest.', + }, + { + category: 'Prozess und Dokumente', + question: 'Welche Dokumente werden für die Steuererklärung benötigt?', + answer: 'Grundlegend sind die Lohnsteuerbescheinigung, ein Ausweisdokument und die Bescheinigung EU/EWR über Einkünfte im Heimatland. Sie erhalten von uns eine detaillierte, auf Ihre Situation zugeschnittene Liste.', + }, + { + category: 'Prozess und Dokumente', + question: 'Bis wann muss ich die Steuererklärung in Deutschland abgeben?', + answer: 'Die Standardfrist ist der 31. Juli des auf das Steuerjahr folgenden Jahres. Wenn Sie die Dienste eines Steuerberaters in Anspruch nehmen, verlängert sich die Frist automatisch.', + }, + { + category: 'Steuererstattung und Kosten', + question: 'Wie lange dauert es, bis die Steuererstattung vom Finanzamt kommt?', + answer: 'Die durchschnittliche Wartezeit auf den Bescheid des Finanzamts beträgt 2 bis 6 Monate. Unsere sorgfältige Vorbereitung der Dokumente minimiert Rückfragen und beschleunigt den Prozess.', + }, + { + category: 'Steuererstattung und Kosten', + question: 'Was kostet eine Steuererklärung in Deutschland?', + answer: 'Die Gebühren von Steuerberatern sind in Deutschland gesetzlich geregelt (StBVV) und hängen von der Komplexität des Falles und der Höhe der Einkünfte ab. Wir machen immer einen klaren Kostenvoranschlag.', + }, + { + category: 'Zusätzliche Leistungen', + question: 'Beantragen Sie auch Kindergeld?', + answer: 'Ja, wir unterstützen Sie beim gesamten Antragsprozess für Kindergeld bei der Familienkasse. Wir kümmern uns um die Anlagen, die Überprüfung des Familienstands und den Schriftverkehr.', + }, + { + category: 'Zusätzlich (ZUM AUSFÜLLEN)', + question: 'Kann ich eine Steuererklärung abgeben, wenn ich nur wenige Monate in Deutschland gearbeitet habe?', + answer: PLACEHOLDER_ANSWER_DE, + }, + { + category: 'Zusätzlich (ZUM AUSFÜLLEN)', + question: 'Was passiert, wenn ich die Steuererklärung zu spät abgebe?', + answer: PLACEHOLDER_ANSWER_DE, + }, + { + category: 'Zusätzlich (ZUM AUSFÜLLEN)', + question: 'Kann ich mit meinem Ehepartner zusammenveranlagt werden, auch wenn er/sie nicht in Deutschland arbeitet?', + answer: PLACEHOLDER_ANSWER_DE, + }, + { + category: 'Zusätzlich (ZUM AUSFÜLLEN)', + question: 'Helfen Sie auch bei der Steuererklärung für Vorjahre (rückwirkend)?', + answer: PLACEHOLDER_ANSWER_DE, + } +]; + + +async function run() { + console.log('Rozpoczynam migrację strony FAQ...') + const payload = await getPayload({ config: configPromise }) + + const pageId = 6; // ID of FAQ page based on actual db + + for (const locale of ['pl', 'de'] as const) { + console.log(`[${locale}] Sprawdzam stan strony ${pageId}...`) + try { + const page = await payload.findByID({ + collection: 'pages', + id: pageId, + locale: locale + }) + + const hasFaqFull = page.layout?.some(block => block.blockType === 'faqFull'); + + if (hasFaqFull) { + console.log(`[${locale}] Migracja już wykonana - znaleziono blok faqFull. Pomijam.`) + continue; + } + + console.log(`[${locale}] Migruję... Dodaję faqFull...`) + + const title = locale === 'de' ? 'Häufig gestellte Fragen' : 'Często zadawane pytania' + const subtitle = locale === 'de' ? 'Hier finden Sie Antworten auf die wichtigsten Fragen zur Steuererklärung.' : 'Tutaj znajdziesz odpowiedzi na najważniejsze pytania dotyczące rozliczeń podatkowych.' + + const ctaText = locale === 'de' ? 'Haben Sie noch Fragen? Schreiben Sie uns auf WhatsApp' : 'Masz więcej pytań? Napisz na WhatsApp' + const ctaUrl = '#'; // CMS link, dynamically handled later if needed + + const newLayout = [ + { + blockType: 'faqFull', + title: title, + subtitle: subtitle, + questions: locale === 'pl' ? questions_pl : questions_de, + ctaText: ctaText, + ctaUrl: ctaUrl + } as FAQFullBlock + ] + + await payload.update({ + collection: 'pages', + id: pageId, + 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() diff --git a/src/app/(frontend)/[locale]/[[...slug]]/page.tsx b/src/app/(frontend)/[locale]/[[...slug]]/page.tsx index 0be9a7e..b7d1630 100644 --- a/src/app/(frontend)/[locale]/[[...slug]]/page.tsx +++ b/src/app/(frontend)/[locale]/[[...slug]]/page.tsx @@ -7,6 +7,17 @@ import { getLocalizedSlugs } from '@intecion/ipal-kit' import { i18n } from '../../../../i18n.config' import { SetLanguageSlugs } from '../../../../components/LanguageSlugsProvider' import { RenderBlocks } from '../../../../blocks/RenderBlocks' +import type { Page } from '../../../../payload-types' + +type FAQFullBlock = Extract[0], { blockType: 'faqFull' }> + +const PLACEHOLDER_PL = "Odpowiedź w przygotowaniu" +const PLACEHOLDER_DE = "Antwort in Vorbereitung" + +function isPlaceholder(answer: string | null | undefined): boolean { + if (!answer) return true; + return answer.includes(PLACEHOLDER_PL) || answer.includes(PLACEHOLDER_DE) || answer.includes('DO POTWIERDZENIA'); +} export default async function Page(props: { params: Promise<{ locale: string; slug?: string[] }> @@ -47,8 +58,35 @@ export default async function Page(props: { const layout = docForRender.layout || [] + // Generowanie schematu FAQPage dla bloku faqFull (na poziomie Server Component gwarantuje to SSR) + let faqSchema: Record | null = null; + const faqBlock = layout.find((b: any) => b.blockType === 'faqFull') as FAQFullBlock | undefined; + if (faqBlock && faqBlock.questions) { + const validQuestions = faqBlock.questions.filter((q: any) => !isPlaceholder(q.answer)); + if (validQuestions.length > 0) { + faqSchema = { + "@context": "https://schema.org", + "@type": "FAQPage", + "mainEntity": validQuestions.map((q: any) => ({ + "@type": "Question", + "name": q.question, + "acceptedAnswer": { + "@type": "Answer", + "text": q.answer + } + })) + }; + } + } + return (
+ {faqSchema && ( +