fix: caching of FAQ

Fix wrong caching of FAQs for correct generation
This commit is contained in:
webfussel 2025-07-10 10:05:08 +02:00
parent fa0435efdf
commit cffb719a05
2 changed files with 117 additions and 95 deletions

View file

@ -1,33 +1,44 @@
<template>
<section id="services" class="Services content">
<h1>Projekt buchen</h1>
<h2>Paketpreise für <Highlight>feste Ergebnisse</Highlight>.</h2>
<h2>Paketpreise für
<Highlight>feste Ergebnisse</Highlight>
.
</h2>
<p class="margin-top">Manchmal brauchen wir alle einfach nur eine Kleinigkeit und wollen uns nicht lange binden. Das ist natürlich
völlig in Ordnung und genau deshalb biete ich dir die Möglichkeit mich gezielt für <Highlight>kleinere Projekte</Highlight> zu buchen.</p>
<p class="margin-top-small">Hinter diesen Angeboten gibt es <Highlight>keinerlei Abos oder versteckte Kosten</Highlight>.
Aus Transparenzgründen sei aber gesagt, dass sich <Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight> verstehen.</p>
völlig in Ordnung und genau deshalb biete ich dir die Möglichkeit mich gezielt für
<Highlight>kleinere Projekte</Highlight>
zu buchen.
</p>
<p class="margin-top-small">Hinter diesen Angeboten gibt es
<Highlight>keinerlei Abos oder versteckte Kosten</Highlight>
.
Aus Transparenzgründen sei aber gesagt, dass sich
<Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight>
verstehen.
</p>
<FreeInfo />
<FreeInfo/>
<div class="Pricing margin-top">
<article v-for="(service, index) in oneOff" :class="{ 'z-3-all': index === 1, 'z-2-all': index !== 1}">
<header>
<strong>{{service.title}}</strong>
<p class="claim">{{service.smallClaim}}</p>
<strong>{{ service.title }}</strong>
<p class="claim">{{ service.smallClaim }}</p>
<div class="price">
<span v-if="service.price.pre">{{service.price.pre}}</span>
<span>{{typeof service.price.value === 'number' ? intl.format(service.price.value) : service.price.value}}</span>
<span v-if="service.price.post" class="post">{{service.price.post}}</span>
<span v-if="service.price.pre">{{ service.price.pre }}</span>
<span>{{ typeof service.price.value === 'number' ? intl.format(service.price.value) : service.price.value }}</span>
<span v-if="service.price.post" class="post">{{ service.price.post }}</span>
</div>
<div aria-hidden="true" class="bg-icon">
<Icon :name="service.icon" size="1.5em" mode="svg" />
<Icon :name="service.icon" size="1.5em" mode="svg"/>
</div>
</header>
<main>
<div class="list-container">
<ul>
<li v-for="point in service.list">
<Icon class="icon yes" name="ph:caret-circle-double-right-duotone" size="1.5em" mode="svg" />
<Icon class="icon yes" name="ph:caret-circle-double-right-duotone" size="1.5em" mode="svg"/>
<span class="label">{{ point }}</span>
</li>
</ul>
@ -44,7 +55,7 @@
</div>
<div v-if="faq" class="flex-col gap-sm margin-top">
<ContentRenderer :value="faq" :style="{ display: 'contents' }" />
<ContentRenderer :value="faq" :style="{ display: 'contents' }"/>
</div>
</section>
</template>
@ -65,16 +76,16 @@ type Service = {
}
const intl = new Intl.NumberFormat(
'de-DE',
{
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}
'de-DE',
{
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
},
)
const oneOff : Service[] = [
const oneOff: Service[] = [
{
title: 'Quick Check',
price: {
@ -129,7 +140,7 @@ const oneOff : Service[] = [
},
]
const { data: faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/booking').first())
const { data: faq } = await useAsyncData('faq_booking', () => queryCollection('faq').path('/snippets/faq/booking').first())
const texts = generatePlainText<['title']>(faq.value?.body.value)
if (faq) {
@ -143,7 +154,7 @@ if (faq) {
'@type': 'Answer',
'text': entity.text,
},
}))
})),
})
}
</script>

View file

@ -1,33 +1,44 @@
<template>
<section id="services" class="Services content">
<h1>Prepaid Flatrates</h1>
<h2>Genieße fusselige <Highlight>Qualität</Highlight> ohne groß herumzurechnen.</h2>
<h2>Genieße fusselige
<Highlight>Qualität</Highlight>
ohne groß herumzurechnen.
</h2>
<p class="margin-top">Bei dir fällt ständig was an oder du hast ein langlaufendes Projekt, bei dem du immer wieder mal Unterstützung brauchst? Kein Ding.
Hier gibt's die <Highlight>Entwickler-Flat</Highlight> für planbare Kosten und On-Demand-Entwicklung.</p>
<p class="margin-top-small">Aus Transparenzgründen sei gesagt, dass sich <Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight> verstehen.</p>
<p class="margin-top">Bei dir fällt ständig was an oder du hast ein langlaufendes Projekt, bei dem du immer wieder mal Unterstützung brauchst?
Kein Ding.
Hier gibt's die
<Highlight>Entwickler-Flat</Highlight>
für planbare Kosten und On-Demand-Entwicklung.
</p>
<p class="margin-top-small">Aus Transparenzgründen sei gesagt, dass sich
<Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight>
verstehen.
</p>
<FreeInfo />
<FreeInfo/>
<div class="Pricing margin-top">
<article v-for="(service, index) in flatrate" :class=" { 'z-2' : index === 1, 'z-1' : index !== 1 }">
<header>
<span v-if="service.best" class="chip dark z-2"><Icon name="ph:fire-duotone" mode="svg"/> Beschd</span>
<strong class="margin-top-small">{{service.title}}</strong>
<p class="claim">{{service.smallClaim}}</p>
<p class="price">{{intl.format(service.price)}}<span class="post">/ Monat</span></p>
<strong class="margin-top-small">{{ service.title }}</strong>
<p class="claim">{{ service.smallClaim }}</p>
<p class="price">{{ intl.format(service.price) }}<span class="post">/ Monat</span></p>
<div aria-hidden="true" class="bg-icon">
<Icon :name="service.icon" size="1.5em" mode="svg" />
<Icon :name="service.icon" size="1.5em" mode="svg"/>
</div>
</header>
<main>
<ul>
<li>
<Icon class="icon yes" name="ph:check-circle-duotone" mode="svg" />
<Icon class="icon yes" name="ph:check-circle-duotone" mode="svg"/>
<span class="value">{{ service.hours }} Stunden pro Woche zugesichert</span>
</li>
<li v-for="(check, index) in service.checks">
<Icon class="icon" :class="{ 'yes' : check, 'no' : !check }" :name="check ? 'ph:check-circle-duotone' : 'ph:x-circle-duotone'" mode="svg" />
<Icon class="icon" :class="{ 'yes' : check, 'no' : !check }" :name="check ? 'ph:check-circle-duotone' : 'ph:x-circle-duotone'"
mode="svg"/>
<span class="value">{{ points[index] }}</span>
</li>
</ul>
@ -44,7 +55,7 @@
</div>
<div v-if="faq" class="flex-col gap-sm margin-top">
<ContentRenderer :value="faq" :style="{ display: 'contents' }" />
<ContentRenderer :value="faq" :style="{ display: 'contents' }"/>
</div>
</section>
</template>
@ -72,7 +83,7 @@ const intl = new Intl.NumberFormat(
maximumFractionDigits: 0,
})
const points : string[] = [
const points: string[] = [
'Kontakt per E-Mail',
'Kontakt per Instant Messaging',
'Kontakt per Video Call',
@ -80,65 +91,65 @@ const points : string[] = [
'Framework Migration',
]
const flatrate : Service[] =
[
{
title: 'Casual',
smallClaim: 'Für kleine Aufgaben nebenbei.',
icon: 'ph:baby-carriage-thin',
button: 'Jetzt klar machen',
link: 'https://tidycal.com/webfussel/flatrate-casual',
best: false,
price: 2950,
hours: 5,
contractMin: 3,
checks: [
true,
false,
false,
false,
false,
],
},
{
title: 'Gold-Fussel',
smallClaim: 'Wenn\'s mal wieder zu viel wird.',
icon: 'ph:coins-thin',
button: 'Jetzt Gold schürfen',
link: 'https://tidycal.com/webfussel/flatrate-gold-fussel',
best: true,
price: 5555,
hours: 10,
contractMin: 3,
checks: [
true,
true,
false,
true,
false,
],
},
{
title: 'Big Chonker',
smallClaim: 'Für die richtig großen Sachen.',
icon: 'ph:skull-thin',
button: 'Jetzt Fett trimmen',
link: 'https://tidycal.com/webfussel/flatrate-big-chonker',
best: false,
price: 8550,
hours: 15,
contractMin: 6,
checks: [
true,
true,
true,
true,
true,
],
}
]
const flatrate: Service[] =
[
{
title: 'Casual',
smallClaim: 'Für kleine Aufgaben nebenbei.',
icon: 'ph:baby-carriage-thin',
button: 'Jetzt klar machen',
link: 'https://tidycal.com/webfussel/flatrate-casual',
best: false,
price: 2950,
hours: 5,
contractMin: 3,
checks: [
true,
false,
false,
false,
false,
],
},
{
title: 'Gold-Fussel',
smallClaim: 'Wenn\'s mal wieder zu viel wird.',
icon: 'ph:coins-thin',
button: 'Jetzt Gold schürfen',
link: 'https://tidycal.com/webfussel/flatrate-gold-fussel',
best: true,
price: 5555,
hours: 10,
contractMin: 3,
checks: [
true,
true,
false,
true,
false,
],
},
{
title: 'Big Chonker',
smallClaim: 'Für die richtig großen Sachen.',
icon: 'ph:skull-thin',
button: 'Jetzt Fett trimmen',
link: 'https://tidycal.com/webfussel/flatrate-big-chonker',
best: false,
price: 8550,
hours: 15,
contractMin: 6,
checks: [
true,
true,
true,
true,
true,
],
},
]
const { data : faq } = await useAsyncData('faq', () => queryCollection('faq').path('/snippets/faq/flatrate').first())
const { data: faq } = await useAsyncData('faq_flatrate', () => queryCollection('faq').path('/snippets/faq/flatrate').first())
const texts = generatePlainText<['title']>(faq.value?.body.value)
if (faq) {
@ -152,7 +163,7 @@ if (faq) {
'@type': 'Answer',
'text': entity.text,
},
}))
})),
})
}
</script>