Toon leesbare slug in plaats van GUID-ID op pakketkaarten
Continuous Integration / config (pull_request) Successful in 9s
Continuous Integration / prepare (pull_request) Successful in 1m17s
Continuous Integration / build-production (pull_request) Skipped
Continuous Integration / build (pull_request) Successful in 1m59s
Continuous Integration / test (pull_request) Successful in 1m51s
Continuous Integration / deploy-production (pull_request) Skipped
Deploy / deploy (pull_request) Successful in 38s
Continuous Integration / deploy-test (pull_request) Successful in 38s

Nu de pakketten dynamisch uit de API komen is het id een GUID, wat
niet leesbaar is op de pagina. Voeg een slug-veld toe aan
PackageCardData en toon dat op de kaart; id blijft ongewijzigd
gebruikt als React key en data-testid.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 11:31:29 +02:00
co-authored by Claude Sonnet 5
parent 5878cfe511
commit 0bf807f9c0
4 changed files with 10 additions and 3 deletions
@@ -66,7 +66,8 @@ Text alternative: A ThemePreference selects a set of ThemeTokens; SiteContent ag
### PackageCard ### PackageCard
| Field | Type | Required | Description | | Field | Type | Required | Description |
|---|---|---|---| |---|---|---|---|
| `id` | `string` | Yes | e.g. `pakket_01` | | `id` | `string` | Yes | Backend record identifier (GUID). Not shown on the page. |
| `slug` | `string` | Yes | Readable, URL-safe identifier derived from `title`, e.g. `landingspagina`. Shown on the card instead of `id`. |
| `title` | `string` | Yes | e.g. "Landingspagina" | | `title` | `string` | Yes | e.g. "Landingspagina" |
| `description` | `string` | Yes | Short description | | `description` | `string` | Yes | Short description |
| `price` | `string` | Yes | e.g. "€ 300" or "Op maat" | | `price` | `string` | Yes | e.g. "€ 300" or "Op maat" |
@@ -49,6 +49,7 @@ client-side sorting):
[ [
{ {
"id": "pakket_01", "id": "pakket_01",
"slug": "landingspagina",
"title": "Landingspagina", "title": "Landingspagina",
"description": "Eén overtuigende pagina die je product of dienst helder neerzet.", "description": "Eén overtuigende pagina die je product of dienst helder neerzet.",
"price": "€ 300", "price": "€ 300",
@@ -73,7 +74,8 @@ for a structured error body.
| Field | Type | Required | Content type / description | Used for | | Field | Type | Required | Content type / description | Used for |
|---|---|---|---|---| |---|---|---|---|---|
| `id` | `string` | Yes | Stable slug-like identifier, e.g. `pakket_01`. Currently just an ordinal slug, not a business meaning — reuse as the CMS entry's own key/slug. | React list key + `data-testid` on the card, and referenced in tests. Must be unique and stable across edits (don't regenerate on every content change, or it'll be treated as a different card). | | `id` | `string` | Yes | Stable record identifier (the CMS entry's own key, a GUID in practice). | React list key + `data-testid` on the card, and referenced in tests. Must be unique and stable across edits (don't regenerate on every content change, or it'll be treated as a different card). Not rendered on the page. |
| `slug` | `string` | Yes | Readable, URL-safe identifier derived from `title` (lowercase, hyphen-separated), e.g. `landingspagina`. Unique among offerings; regenerate it when `title` changes, keep it otherwise. | Displayed on the card in place of the raw `id`, so visitors see readable text instead of a GUID. |
| `title` | `string` | Yes | Short package name (e.g. "Landingspagina"). Plain text, no markup. | Card heading. | | `title` | `string` | Yes | Short package name (e.g. "Landingspagina"). Plain text, no markup. | Card heading. |
| `description` | `string` | Yes | One-sentence pitch, plain text. | Subheading under the title. | | `description` | `string` | Yes | One-sentence pitch, plain text. | Subheading under the title. |
| `price` | `string` | Yes | Pre-formatted price display string — e.g. `"€ 300"` or `"Op maat"` for the quote-based package. **Not a number**: it's rendered verbatim, so formatting (currency symbol, spacing, "Op maat") is the CMS editor's responsibility, not computed client-side. | Large price figure on the card. | | `price` | `string` | Yes | Pre-formatted price display string — e.g. `"€ 300"` or `"Op maat"` for the quote-based package. **Not a number**: it's rendered verbatim, so formatting (currency symbol, spacing, "Op maat") is the CMS editor's responsibility, not computed client-side. | Large price figure on the card. |
@@ -16,7 +16,7 @@ export function PackageCard({ pkg }: { pkg: PackageCardData }) {
Meest gekozen Meest gekozen
</span> </span>
)} )}
<span className="font-mono mb-3.5 text-[0.78rem] text-accent">{pkg.id}</span> <span className="font-mono mb-3.5 text-[0.78rem] text-accent">{pkg.slug}</span>
<h3 className="mb-2.5 text-xl font-bold">{pkg.title}</h3> <h3 className="mb-2.5 text-xl font-bold">{pkg.title}</h3>
<p className="mb-6 text-[0.95rem] text-muted">{pkg.description}</p> <p className="mb-6 text-[0.95rem] text-muted">{pkg.description}</p>
<div className="font-mono mb-1 text-3xl font-bold"> <div className="font-mono mb-1 text-3xl font-bold">
+4
View File
@@ -27,6 +27,7 @@ export interface HeroContent {
export interface PackageCardData { export interface PackageCardData {
id: string; id: string;
slug: string;
title: string; title: string;
description: string; description: string;
price: string; price: string;
@@ -76,6 +77,7 @@ export const heroContent: HeroContent = {
export const packages: PackageCardData[] = [ export const packages: PackageCardData[] = [
{ {
id: 'pakket_01', id: 'pakket_01',
slug: 'landingspagina',
title: 'Landingspagina', title: 'Landingspagina',
description: 'Eén overtuigende pagina die je product of dienst helder neerzet.', description: 'Eén overtuigende pagina die je product of dienst helder neerzet.',
price: '€ 300', price: '€ 300',
@@ -90,6 +92,7 @@ export const packages: PackageCardData[] = [
}, },
{ {
id: 'pakket_02', id: 'pakket_02',
slug: 'website',
title: 'Website', title: 'Website',
description: "Een complete website met meerdere pagina's, klaar om te groeien.", description: "Een complete website met meerdere pagina's, klaar om te groeien.",
price: '€ 750', price: '€ 750',
@@ -105,6 +108,7 @@ export const packages: PackageCardData[] = [
}, },
{ {
id: 'pakket_03', id: 'pakket_03',
slug: 'maatwerk',
title: 'Maatwerk', title: 'Maatwerk',
description: 'Grotere websites, een eigen back-end of andere .NET-projecten.', description: 'Grotere websites, een eigen back-end of andere .NET-projecten.',
price: 'Op maat', price: 'Op maat',