@xiwebdesign/xicms-core 7.26.0 → 7.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,7 +41,13 @@ const ShopSettingsSchema = z.object({
41
41
  * op te reageren.
42
42
  */
43
43
  businessEmail: z._default(z.string().check(z.maxLength(200)), "").register(z.globalRegistry, { description: "Contact-e-mail (factuur + mailfooter)" }),
44
- businessPhone: z._default(z.string().check(z.maxLength(40)), "").register(z.globalRegistry, { description: "Telefoon (factuur + mailfooter)" })
44
+ businessPhone: z._default(z.string().check(z.maxLength(40)), "").register(z.globalRegistry, { description: "Telefoon (factuur + mailfooter)" }),
45
+ /**
46
+ * Cadeauverpakking (7.27): uit = de checkout toont de optie niet. De meerprijs staat als eigen
47
+ * orderregel (kind "giftwrap"), dus btw/factuur/Stripe-Mollie-regels werken er al generiek mee.
48
+ */
49
+ giftWrapEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: "Cadeauverpakking aanbieden bij het afrekenen" }),
50
+ giftWrapPriceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e5)), 0).register(z.globalRegistry, { description: "Meerprijs cadeauverpakking (centen)" })
45
51
  });
46
52
  const defaultShopSettings = ShopSettingsSchema.parse({});
47
53
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/modules/shop/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\n\n/**\n * Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of\n * `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier\n * automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config\n * server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in\n * `sites/{siteId}/private/shop` en lopen via callables.\n */\nexport const ShopSettingsSchema = z.object({\n shopPath: z._default(z.string().check(z.maxLength(200)), \"/webwinkel\").register(z.globalRegistry, { description: \"Pad van de winkelpagina\" }),\n detailPath: z._default(z.string().check(z.maxLength(200)), \"/product\").register(z.globalRegistry, { description: \"Pad van de productpagina\" }),\n cartPath: z._default(z.string().check(z.maxLength(200)), \"/winkelwagen\").register(z.globalRegistry, { description: \"Pad van de winkelwagen\" }),\n checkoutPath: z._default(z.string().check(z.maxLength(200)), \"/afrekenen\").register(z.globalRegistry, { description: \"Pad van de afrekenpagina\" }),\n successPath: z._default(z.string().check(z.maxLength(200)), \"/bedankt\").register(z.globalRegistry, { description: \"Pad van de bedankt-pagina\" }),\n currency: z._default(z.string().check(z.minLength(3)).check(z.maxLength(3)), \"EUR\").register(z.globalRegistry, { description: \"Valuta (ISO-code)\" }),\n shippingFlatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 495).register(z.globalRegistry, { description: \"Verzendkosten (centen)\" }),\n shippingFreeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0).register(z.globalRegistry, { description: \"Gratis verzending vanaf (centen, 0 = nooit)\" }),\n /**\n * Verzendzones (7.20): tarief per (groep) land(en). Leeg = het enkele tarief hierboven voor\n * alles — het gedrag van vóór 7.20, dus bestaande winkels merken niets. Een zone ZONDER landen\n * is de \"overige landen\"-zone; staat die er niet, dan verzendt de winkel alleen naar de landen\n * die wél in een zone staan (en toont de checkout precies die keuze).\n */\n shippingZones: z._default(z.array(z.object({\n naam: z.string().check(z.minLength(1)).check(z.maxLength(60)),\n landen: z._default(z.array(z.string().check(z.maxLength(2))).check(z.maxLength(60)), []),\n flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0),\n freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n })).check(z.maxLength(10)), []).register(z.globalRegistry, { description: \"Verzendzones (tarief per land)\" }),\n orderPrefix: z._default(z.string().check(z.maxLength(12)), \"ORDER\").register(z.globalRegistry, { description: \"Ordernummer-prefix\" }),\n /**\n * Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is\n * een eigen doorlopende nummering die alleen bij betaling ophoogt en per jaar herstart —\n * het ordernummer mag gaten hebben (afgebroken checkouts), een factuurreeks niet.\n */\n invoicePrefix: z._default(z.string().check(z.maxLength(12)), \"\").register(z.globalRegistry, { description: \"Factuurnummer-prefix (leeg = zelfde als ordernummer)\" }),\n /* Bedrijfsgegevens — komen op de factuur-PDF (5.6). */\n businessName: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Bedrijfsnaam (factuur)\" }),\n businessAddress: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Adres (factuur)\" }),\n businessZip: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"Postcode (factuur)\" }),\n businessCity: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Plaats (factuur)\" }),\n businessKvk: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"KVK-nummer (factuur)\" }),\n businessBtw: z._default(z.string().check(z.maxLength(30)), \"\").register(z.globalRegistry, { description: \"Btw-nummer (factuur)\" }),\n /**\n * Contactgegevens in de mailfooter en op de factuur (7.21). `businessEmail` werd al door\n * `mailLayout.ts` en `invoice.ts` UITGELEZEN, maar bestond nergens als instelling — een dood\n * veld op drie plekken, waardoor de klant in zijn bestelbevestiging geen enkel adres zag om\n * op te reageren.\n */\n businessEmail: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Contact-e-mail (factuur + mailfooter)\" }),\n businessPhone: z._default(z.string().check(z.maxLength(40)), \"\").register(z.globalRegistry, { description: \"Telefoon (factuur + mailfooter)\" }),\n});\nexport type ShopSettings = z.infer<typeof ShopSettingsSchema>;\n\nexport const defaultShopSettings: ShopSettings = ShopSettingsSchema.parse({});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/modules/shop/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\n\n/**\n * Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of\n * `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier\n * automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config\n * server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in\n * `sites/{siteId}/private/shop` en lopen via callables.\n */\nexport const ShopSettingsSchema = z.object({\n shopPath: z._default(z.string().check(z.maxLength(200)), \"/webwinkel\").register(z.globalRegistry, { description: \"Pad van de winkelpagina\" }),\n detailPath: z._default(z.string().check(z.maxLength(200)), \"/product\").register(z.globalRegistry, { description: \"Pad van de productpagina\" }),\n cartPath: z._default(z.string().check(z.maxLength(200)), \"/winkelwagen\").register(z.globalRegistry, { description: \"Pad van de winkelwagen\" }),\n checkoutPath: z._default(z.string().check(z.maxLength(200)), \"/afrekenen\").register(z.globalRegistry, { description: \"Pad van de afrekenpagina\" }),\n successPath: z._default(z.string().check(z.maxLength(200)), \"/bedankt\").register(z.globalRegistry, { description: \"Pad van de bedankt-pagina\" }),\n currency: z._default(z.string().check(z.minLength(3)).check(z.maxLength(3)), \"EUR\").register(z.globalRegistry, { description: \"Valuta (ISO-code)\" }),\n shippingFlatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 495).register(z.globalRegistry, { description: \"Verzendkosten (centen)\" }),\n shippingFreeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0).register(z.globalRegistry, { description: \"Gratis verzending vanaf (centen, 0 = nooit)\" }),\n /**\n * Verzendzones (7.20): tarief per (groep) land(en). Leeg = het enkele tarief hierboven voor\n * alles — het gedrag van vóór 7.20, dus bestaande winkels merken niets. Een zone ZONDER landen\n * is de \"overige landen\"-zone; staat die er niet, dan verzendt de winkel alleen naar de landen\n * die wél in een zone staan (en toont de checkout precies die keuze).\n */\n shippingZones: z._default(z.array(z.object({\n naam: z.string().check(z.minLength(1)).check(z.maxLength(60)),\n landen: z._default(z.array(z.string().check(z.maxLength(2))).check(z.maxLength(60)), []),\n flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0),\n freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n })).check(z.maxLength(10)), []).register(z.globalRegistry, { description: \"Verzendzones (tarief per land)\" }),\n orderPrefix: z._default(z.string().check(z.maxLength(12)), \"ORDER\").register(z.globalRegistry, { description: \"Ordernummer-prefix\" }),\n /**\n * Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is\n * een eigen doorlopende nummering die alleen bij betaling ophoogt en per jaar herstart —\n * het ordernummer mag gaten hebben (afgebroken checkouts), een factuurreeks niet.\n */\n invoicePrefix: z._default(z.string().check(z.maxLength(12)), \"\").register(z.globalRegistry, { description: \"Factuurnummer-prefix (leeg = zelfde als ordernummer)\" }),\n /* Bedrijfsgegevens — komen op de factuur-PDF (5.6). */\n businessName: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Bedrijfsnaam (factuur)\" }),\n businessAddress: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Adres (factuur)\" }),\n businessZip: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"Postcode (factuur)\" }),\n businessCity: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Plaats (factuur)\" }),\n businessKvk: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"KVK-nummer (factuur)\" }),\n businessBtw: z._default(z.string().check(z.maxLength(30)), \"\").register(z.globalRegistry, { description: \"Btw-nummer (factuur)\" }),\n /**\n * Contactgegevens in de mailfooter en op de factuur (7.21). `businessEmail` werd al door\n * `mailLayout.ts` en `invoice.ts` UITGELEZEN, maar bestond nergens als instelling — een dood\n * veld op drie plekken, waardoor de klant in zijn bestelbevestiging geen enkel adres zag om\n * op te reageren.\n */\n businessEmail: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Contact-e-mail (factuur + mailfooter)\" }),\n businessPhone: z._default(z.string().check(z.maxLength(40)), \"\").register(z.globalRegistry, { description: \"Telefoon (factuur + mailfooter)\" }),\n /**\n * Cadeauverpakking (7.27): uit = de checkout toont de optie niet. De meerprijs staat als eigen\n * orderregel (kind \"giftwrap\"), dus btw/factuur/Stripe-Mollie-regels werken er al generiek mee.\n */\n giftWrapEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: \"Cadeauverpakking aanbieden bij het afrekenen\" }),\n giftWrapPriceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0).register(z.globalRegistry, { description: \"Meerprijs cadeauverpakking (centen)\" }),\n});\nexport type ShopSettings = z.infer<typeof ShopSettingsSchema>;\n\nexport const defaultShopSettings: ShopSettings = ShopSettingsSchema.parse({});\n"],"mappings":"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","names":[]}
@@ -59,6 +59,12 @@ declare const NL: {
59
59
  donationFailed: string;
60
60
  donationCustomAmount: string;
61
61
  donationAmountLabel: string;
62
+ billingSame: string;
63
+ billingHeading: string;
64
+ giftWrap: string;
65
+ giftWrapLabel: string;
66
+ giftWrapCardText: string;
67
+ giftWrapNote: string;
62
68
  };
63
69
  export type ShopStringKey = keyof typeof NL;
64
70
  export type ShopT = (key: ShopStringKey, vars?: Record<string, string | number>) => string;
@@ -60,7 +60,13 @@ const NL = {
60
60
  personalizationSurcharge: "+ {bedrag}",
61
61
  donationFailed: "Doneren is niet gelukt. Probeer het later opnieuw.",
62
62
  donationCustomAmount: "Ander bedrag",
63
- donationAmountLabel: "Bedrag in euro's (min. {min})"
63
+ donationAmountLabel: "Bedrag in euro's (min. {min})",
64
+ billingSame: "Factuuradres is hetzelfde als het verzendadres",
65
+ billingHeading: "Factuuradres",
66
+ giftWrap: "Cadeauverpakking",
67
+ giftWrapLabel: "Cadeauverpakking (+ {bedrag})",
68
+ giftWrapCardText: "Tekst op het kaartje (optioneel)",
69
+ giftWrapNote: "Opmerking voor het inpakken (optioneel)"
64
70
  };
65
71
  const EN = {
66
72
  addToCart: "Add to cart",
@@ -122,7 +128,13 @@ const EN = {
122
128
  personalizationSurcharge: "+ {bedrag}",
123
129
  donationFailed: "Donation failed. Please try again later.",
124
130
  donationCustomAmount: "Custom amount",
125
- donationAmountLabel: "Amount in euros (min. {min})"
131
+ donationAmountLabel: "Amount in euros (min. {min})",
132
+ billingSame: "Billing address is the same as the shipping address",
133
+ billingHeading: "Billing address",
134
+ giftWrap: "Gift wrap",
135
+ giftWrapLabel: "Gift wrap (+ {bedrag})",
136
+ giftWrapCardText: "Text for the card (optional)",
137
+ giftWrapNote: "Note for gift-wrapping (optional)"
126
138
  };
127
139
  const TABLES = { nl: NL, en: EN };
128
140
  function useShopStrings() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/modules/shop/strings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * UI-teksten van de shop-blocks, gelokaliseerd op `SiteConfig.lang` (nl = default, en).\n * Interpolatie via `{naam}`-placeholders. Bewust een platte tabel — geen i18n-framework;\n * de shop-strings zijn de enige plek in de blocks met vaste UI-tekst.\n */\nimport { useSiteConfig } from \"../../config\";\n\nconst NL = {\n addToCart: \"In winkelwagen\",\n added: \"✓ Toegevoegd aan je winkelwagen.\",\n addedGoToCart: \"✓ In winkelwagen — bekijk\",\n view: \"Bekijk\",\n toCart: \"Naar winkelwagen\",\n continueShopping: \"Verder winkelen\",\n checkout: \"Afrekenen\",\n cartEmpty: \"Je winkelwagen is leeg.\",\n toShop: \"Naar de winkel\",\n subtotal: \"Subtotaal\",\n shippingCosts: \"Verzendkosten\",\n free: \"gratis\",\n total: \"Totaal\",\n perPiece: \"p/st\",\n qty: \"Aantal\",\n outOfStock: \"Uitverkocht in deze uitvoering.\",\n variantUnavailable: \"Deze combinatie is niet leverbaar.\",\n stockLeft: \"Nog {n} beschikbaar\",\n soldOut: \"Uitverkocht\",\n productNotFound: \"Product niet gevonden.\",\n backToShop: \"Terug naar de winkel\",\n noProducts: \"Geen producten gevonden.\",\n noCategories: \"Nog geen categorieën.\",\n allCategories: \"Alle categorieën\",\n pay: \"Betalen — {bedrag}\",\n busy: \"Bezig…\",\n checkoutFailed: \"Afrekenen is niet gelukt. Controleer je gegevens en probeer het opnieuw.\",\n secureNote: \"Je rekent veilig af via een beveiligde betaalpagina (o.a. iDEAL). Na betaling ontvang je een bevestiging per e-mail.\",\n yourOrder: \"Je bestelling\",\n fieldName: \"Naam\",\n fieldEmail: \"E-mail\",\n fieldPhone: \"Telefoon (optioneel)\",\n fieldAddress: \"Straat + huisnummer\",\n fieldZip: \"Postcode\",\n fieldCity: \"Plaats\",\n fieldCountry: \"Land\",\n shippingFromCountry: \"(bij bezorging in Nederland — kies je land bij het afrekenen)\",\n fieldNote: \"Opmerking (optioneel)\",\n choose: \"Kies…\",\n discountCode: \"Kortingscode\",\n discountApply: \"Toepassen\",\n discount: \"Korting\",\n discountInvalid: \"Deze code is niet (meer) geldig.\",\n discountApplied: \"Korting toegepast: {code}\",\n related: \"Ook leuk\",\n filterAll: \"Alles\",\n sortLabel: \"Sorteren\",\n sortDefault: \"Aanbevolen\",\n sortName: \"Naam\",\n sortPriceAsc: \"Prijs (laag-hoog)\",\n sortPriceDesc: \"Prijs (hoog-laag)\",\n personalizationUpload: \"Kies bestand…\",\n personalizationUploading: \"Uploaden…\",\n personalizationUploaded: \"✓ Geüpload\",\n personalizationTooBig: \"Bestand te groot (max 5 MB).\",\n personalizationFailed: \"Uploaden mislukt — probeer het opnieuw.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Doneren is niet gelukt. Probeer het later opnieuw.\",\n donationCustomAmount: \"Ander bedrag\",\n donationAmountLabel: \"Bedrag in euro's (min. {min})\",\n};\n\nconst EN: typeof NL = {\n addToCart: \"Add to cart\",\n added: \"✓ Added to your cart.\",\n addedGoToCart: \"✓ In cart — view\",\n view: \"View\",\n toCart: \"Go to cart\",\n continueShopping: \"Continue shopping\",\n checkout: \"Checkout\",\n cartEmpty: \"Your cart is empty.\",\n toShop: \"Go to the shop\",\n subtotal: \"Subtotal\",\n shippingCosts: \"Shipping\",\n free: \"free\",\n total: \"Total\",\n perPiece: \"each\",\n qty: \"Quantity\",\n outOfStock: \"Sold out in this variant.\",\n variantUnavailable: \"This combination is unavailable.\",\n stockLeft: \"Only {n} left\",\n soldOut: \"Sold out\",\n productNotFound: \"Product not found.\",\n backToShop: \"Back to the shop\",\n noProducts: \"No products found.\",\n noCategories: \"No categories yet.\",\n allCategories: \"All categories\",\n pay: \"Pay — {bedrag}\",\n busy: \"Working…\",\n checkoutFailed: \"Checkout failed. Check your details and try again.\",\n secureNote: \"You pay securely via a protected checkout page (incl. iDEAL). You will receive a confirmation email after payment.\",\n yourOrder: \"Your order\",\n fieldName: \"Name\",\n fieldEmail: \"Email\",\n fieldPhone: \"Phone (optional)\",\n fieldAddress: \"Street + number\",\n fieldZip: \"Postal code\",\n fieldCity: \"City\",\n fieldCountry: \"Country\",\n shippingFromCountry: \"(for delivery in the Netherlands — choose your country at checkout)\",\n fieldNote: \"Note (optional)\",\n choose: \"Choose…\",\n discountCode: \"Discount code\",\n discountApply: \"Apply\",\n discount: \"Discount\",\n discountInvalid: \"This code is not (or no longer) valid.\",\n discountApplied: \"Discount applied: {code}\",\n related: \"You may also like\",\n filterAll: \"All\",\n sortLabel: \"Sort\",\n sortDefault: \"Recommended\",\n sortName: \"Name\",\n sortPriceAsc: \"Price (low-high)\",\n sortPriceDesc: \"Price (high-low)\",\n personalizationUpload: \"Choose file…\",\n personalizationUploading: \"Uploading…\",\n personalizationUploaded: \"✓ Uploaded\",\n personalizationTooBig: \"File too large (max 5 MB).\",\n personalizationFailed: \"Upload failed — please try again.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Donation failed. Please try again later.\",\n donationCustomAmount: \"Custom amount\",\n donationAmountLabel: \"Amount in euros (min. {min})\",\n};\n\nexport type ShopStringKey = keyof typeof NL;\nconst TABLES: Record<string, typeof NL> = { nl: NL, en: EN };\n\nexport type ShopT = (key: ShopStringKey, vars?: Record<string, string | number>) => string;\n\n/** Vertaalfunctie voor shop-blocks: `t(\"addToCart\")`, `t(\"stockLeft\", { n: 3 })`. */\nexport function useShopStrings(): ShopT {\n const lang = (useSiteConfig().lang ?? \"nl\").slice(0, 2).toLowerCase();\n const table = TABLES[lang] ?? NL;\n return (key, vars) => {\n let s = table[key] ?? NL[key] ?? key;\n if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, String(v));\n return s;\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/modules/shop/strings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * UI-teksten van de shop-blocks, gelokaliseerd op `SiteConfig.lang` (nl = default, en).\n * Interpolatie via `{naam}`-placeholders. Bewust een platte tabel — geen i18n-framework;\n * de shop-strings zijn de enige plek in de blocks met vaste UI-tekst.\n */\nimport { useSiteConfig } from \"../../config\";\n\nconst NL = {\n addToCart: \"In winkelwagen\",\n added: \"✓ Toegevoegd aan je winkelwagen.\",\n addedGoToCart: \"✓ In winkelwagen — bekijk\",\n view: \"Bekijk\",\n toCart: \"Naar winkelwagen\",\n continueShopping: \"Verder winkelen\",\n checkout: \"Afrekenen\",\n cartEmpty: \"Je winkelwagen is leeg.\",\n toShop: \"Naar de winkel\",\n subtotal: \"Subtotaal\",\n shippingCosts: \"Verzendkosten\",\n free: \"gratis\",\n total: \"Totaal\",\n perPiece: \"p/st\",\n qty: \"Aantal\",\n outOfStock: \"Uitverkocht in deze uitvoering.\",\n variantUnavailable: \"Deze combinatie is niet leverbaar.\",\n stockLeft: \"Nog {n} beschikbaar\",\n soldOut: \"Uitverkocht\",\n productNotFound: \"Product niet gevonden.\",\n backToShop: \"Terug naar de winkel\",\n noProducts: \"Geen producten gevonden.\",\n noCategories: \"Nog geen categorieën.\",\n allCategories: \"Alle categorieën\",\n pay: \"Betalen — {bedrag}\",\n busy: \"Bezig…\",\n checkoutFailed: \"Afrekenen is niet gelukt. Controleer je gegevens en probeer het opnieuw.\",\n secureNote: \"Je rekent veilig af via een beveiligde betaalpagina (o.a. iDEAL). Na betaling ontvang je een bevestiging per e-mail.\",\n yourOrder: \"Je bestelling\",\n fieldName: \"Naam\",\n fieldEmail: \"E-mail\",\n fieldPhone: \"Telefoon (optioneel)\",\n fieldAddress: \"Straat + huisnummer\",\n fieldZip: \"Postcode\",\n fieldCity: \"Plaats\",\n fieldCountry: \"Land\",\n shippingFromCountry: \"(bij bezorging in Nederland — kies je land bij het afrekenen)\",\n fieldNote: \"Opmerking (optioneel)\",\n choose: \"Kies…\",\n discountCode: \"Kortingscode\",\n discountApply: \"Toepassen\",\n discount: \"Korting\",\n discountInvalid: \"Deze code is niet (meer) geldig.\",\n discountApplied: \"Korting toegepast: {code}\",\n related: \"Ook leuk\",\n filterAll: \"Alles\",\n sortLabel: \"Sorteren\",\n sortDefault: \"Aanbevolen\",\n sortName: \"Naam\",\n sortPriceAsc: \"Prijs (laag-hoog)\",\n sortPriceDesc: \"Prijs (hoog-laag)\",\n personalizationUpload: \"Kies bestand…\",\n personalizationUploading: \"Uploaden…\",\n personalizationUploaded: \"✓ Geüpload\",\n personalizationTooBig: \"Bestand te groot (max 5 MB).\",\n personalizationFailed: \"Uploaden mislukt — probeer het opnieuw.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Doneren is niet gelukt. Probeer het later opnieuw.\",\n donationCustomAmount: \"Ander bedrag\",\n donationAmountLabel: \"Bedrag in euro's (min. {min})\",\n billingSame: \"Factuuradres is hetzelfde als het verzendadres\",\n billingHeading: \"Factuuradres\",\n giftWrap: \"Cadeauverpakking\",\n giftWrapLabel: \"Cadeauverpakking (+ {bedrag})\",\n giftWrapCardText: \"Tekst op het kaartje (optioneel)\",\n giftWrapNote: \"Opmerking voor het inpakken (optioneel)\",\n};\n\nconst EN: typeof NL = {\n addToCart: \"Add to cart\",\n added: \"✓ Added to your cart.\",\n addedGoToCart: \"✓ In cart — view\",\n view: \"View\",\n toCart: \"Go to cart\",\n continueShopping: \"Continue shopping\",\n checkout: \"Checkout\",\n cartEmpty: \"Your cart is empty.\",\n toShop: \"Go to the shop\",\n subtotal: \"Subtotal\",\n shippingCosts: \"Shipping\",\n free: \"free\",\n total: \"Total\",\n perPiece: \"each\",\n qty: \"Quantity\",\n outOfStock: \"Sold out in this variant.\",\n variantUnavailable: \"This combination is unavailable.\",\n stockLeft: \"Only {n} left\",\n soldOut: \"Sold out\",\n productNotFound: \"Product not found.\",\n backToShop: \"Back to the shop\",\n noProducts: \"No products found.\",\n noCategories: \"No categories yet.\",\n allCategories: \"All categories\",\n pay: \"Pay — {bedrag}\",\n busy: \"Working…\",\n checkoutFailed: \"Checkout failed. Check your details and try again.\",\n secureNote: \"You pay securely via a protected checkout page (incl. iDEAL). You will receive a confirmation email after payment.\",\n yourOrder: \"Your order\",\n fieldName: \"Name\",\n fieldEmail: \"Email\",\n fieldPhone: \"Phone (optional)\",\n fieldAddress: \"Street + number\",\n fieldZip: \"Postal code\",\n fieldCity: \"City\",\n fieldCountry: \"Country\",\n shippingFromCountry: \"(for delivery in the Netherlands — choose your country at checkout)\",\n fieldNote: \"Note (optional)\",\n choose: \"Choose…\",\n discountCode: \"Discount code\",\n discountApply: \"Apply\",\n discount: \"Discount\",\n discountInvalid: \"This code is not (or no longer) valid.\",\n discountApplied: \"Discount applied: {code}\",\n related: \"You may also like\",\n filterAll: \"All\",\n sortLabel: \"Sort\",\n sortDefault: \"Recommended\",\n sortName: \"Name\",\n sortPriceAsc: \"Price (low-high)\",\n sortPriceDesc: \"Price (high-low)\",\n personalizationUpload: \"Choose file…\",\n personalizationUploading: \"Uploading…\",\n personalizationUploaded: \"✓ Uploaded\",\n personalizationTooBig: \"File too large (max 5 MB).\",\n personalizationFailed: \"Upload failed — please try again.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Donation failed. Please try again later.\",\n donationCustomAmount: \"Custom amount\",\n donationAmountLabel: \"Amount in euros (min. {min})\",\n billingSame: \"Billing address is the same as the shipping address\",\n billingHeading: \"Billing address\",\n giftWrap: \"Gift wrap\",\n giftWrapLabel: \"Gift wrap (+ {bedrag})\",\n giftWrapCardText: \"Text for the card (optional)\",\n giftWrapNote: \"Note for gift-wrapping (optional)\",\n};\n\nexport type ShopStringKey = keyof typeof NL;\nconst TABLES: Record<string, typeof NL> = { nl: NL, en: EN };\n\nexport type ShopT = (key: ShopStringKey, vars?: Record<string, string | number>) => string;\n\n/** Vertaalfunctie voor shop-blocks: `t(\"addToCart\")`, `t(\"stockLeft\", { n: 3 })`. */\nexport function useShopStrings(): ShopT {\n const lang = (useSiteConfig().lang ?? \"nl\").slice(0, 2).toLowerCase();\n const table = TABLES[lang] ?? NL;\n return (key, vars) => {\n let s = table[key] ?? NL[key] ?? key;\n if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, String(v));\n return s;\n };\n}\n"],"mappings":"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","names":[]}
@@ -16,7 +16,7 @@ function PublishedPage({
16
16
  }) {
17
17
  const registry = useRegistry();
18
18
  const config = useSiteConfig();
19
- const { draftBlocks, editPath, fotoVervanger } = useEditor();
19
+ const { draftBlocks, editPath, fotoVervanger, publishedOverride } = useEditor();
20
20
  useEffect(() => {
21
21
  if (!isDemoActive()) return;
22
22
  const pad = huidigPad(window.location.pathname);
@@ -28,14 +28,16 @@ function PublishedPage({
28
28
  path: pad
29
29
  });
30
30
  }, [siteId, page]);
31
- const opDezePagina = draftBlocks !== null && typeof window !== "undefined" && (() => {
31
+ const huidigCanoniekPad = typeof window !== "undefined" ? (() => {
32
32
  const { slugs } = parseLocaleSlugs(
33
33
  window.location.pathname.split("/").filter(Boolean),
34
34
  siteLocales(config)
35
35
  );
36
- return huidigPad("/" + slugs.join("/")) === editPath;
37
- })();
38
- const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : page;
36
+ return huidigPad("/" + slugs.join("/"));
37
+ })() : null;
38
+ const opDezePagina = draftBlocks !== null && huidigCanoniekPad !== null && huidigCanoniekPad === editPath;
39
+ const overrideVoorDezePagina = !opDezePagina && publishedOverride !== null && huidigCanoniekPad !== null && huidigCanoniekPad === publishedOverride.path ? publishedOverride.blocks : null;
40
+ const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : overrideVoorDezePagina ? { ...page, blocks: overrideVoorDezePagina } : page;
39
41
  return /* @__PURE__ */ jsx(BlockDataProvider, { data: blockData, children: /* @__PURE__ */ jsx(InlineImageEditProvider, { onReplace: opDezePagina ? fotoVervanger : null, children: /* @__PURE__ */ jsx(PageRenderer, { page: teTonen, registry, siteId, mode }) }) });
40
42
  }
41
43
  function huidigPad(p) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/render/PublishedPage.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { PageRenderer } from \"./PageRenderer\";\nimport { useRegistry, BlockDataProvider } from \"../blocks/context\";\nimport { useEditor } from \"../editor/EditorProvider\";\nimport { isDemoActive, registerSeed } from \"../demo/demoStore\";\nimport { InlineImageEditProvider } from \"../media/ImageContext\";\nimport { useSiteConfig } from \"../config\";\nimport { parseLocaleSlugs, siteLocales } from \"../i18n/overlay\";\nimport type { Page } from \"../schema/pages\";\n\n/**\n * Rendert een (gepubliceerde) pagina via de **context-registry** (module-resolved, opgebouwd in\n * XiCMSProvider). Gebruik dit i.p.v. zelf `createRegistry([...builtinBlocks])` server-side te bouwen:\n * sinds de blokken op Astryx draaien zijn de meeste `\"use client\"`, en een server-opgebouwde registry\n * krijgt daar alleen opake client-referenties van → die blokken worden stil overgeslagen. Deze client-\n * component zit binnen de provider en heeft dus de volledige registry.\n *\n * `blockData` (5.6, optioneel): server-gefetchte startdata per domein (bv. `{ shop: … }` uit\n * `getShopPageData`). Data-blokken renderen dan direct met inhoud (SSR/ISR) i.p.v. eerst\n * client-side te fetchen. Moet serialiseerbare plain data zijn (server → client-prop).\n */\nexport function PublishedPage({\n page,\n siteId,\n mode = \"view\",\n blockData,\n}: {\n page: Pick<Page, \"blocks\">;\n siteId: string;\n mode?: \"view\" | \"preview\";\n blockData?: Record<string, unknown>;\n}) {\n const registry = useRegistry();\n const config = useSiteConfig();\n const { draftBlocks, editPath, fotoVervanger } = useEditor();\n\n /**\n * In een DEMO is deze pagina zijn eigen uitgangspunt.\n *\n * De demo-bewerkmodus bewaart wijzigingen in de browser en legt die over een \"seed\": de\n * oorspronkelijke pagina waar de bezoeker op verder bewerkt. Zonder geregistreerde seed geeft\n * `resolveDemoPage` niets terug, meldt de editor \"Nog geen werkversie\", en loopt de enige knop\n * die dan overblijft (\"+ Pagina aanmaken\") tegen de échte database aan.\n *\n * Dat overkwam elke demo-site behalve xicms.nl zelf, want daar stond de registratie met de hand\n * in een eigen catch-all route. Een klantsite heeft die route niet en had dus wél een\n * demo-bewerkmodus in de balk, maar geen enkele pagina om te bewerken — op sites die bestaan om\n * te laten zien hoe prettig het bewerken werkt.\n *\n * Hier hoort het thuis: dit component wéét welke pagina er op dit pad staat. Buiten de demo doet\n * het niets, en in de demo is de seed per definitie gelijk aan wat de bezoeker ziet.\n */\n useEffect(() => {\n if (!isDemoActive()) return;\n const pad = huidigPad(window.location.pathname);\n // Titel en slug horen erbij: de editor toont ze in zijn balk en in de pagina-instellingen.\n // `page` levert in de praktijk het hele pagina-object; deze twee zijn de terugval voor een site\n // die alleen blokken doorgeeft — het type belooft immers niet meer dan `blocks`.\n const volledig = page as Partial<Page> & Pick<Page, \"blocks\">;\n registerSeed(siteId, pad, {\n ...volledig,\n title: volledig.title || document.title,\n slug: volledig.slug || (pad.split(\"/\").filter(Boolean).pop() ?? \"\"),\n path: pad,\n } as Page);\n // Alleen op het pad en de inhoud: opnieuw registreren bij elke render zou de seed tijdens het\n // bewerken vervangen door de zojuist bewerkte tekst, en dan is er geen origineel meer om op\n // terug te vallen.\n }, [siteId, page]);\n\n /**\n * Staat de editor open op DEZE pagina, dan tonen we de werkversie in plaats van het\n * gepubliceerde. Zo blijft de site zijn eigen layout en huisstijl tekenen, en is wat je ziet\n * precies wat je bewerkt — in plaats van een nabootsing in een apart editorvenster.\n *\n * De padvergelijking is niet overdreven voorzichtig: een pagina kan meerdere gerenderde pagina's\n * in beeld hebben (een preview, een ingekaderde pagina). Zonder die controle zou de werkversie\n * van de ene pagina in de andere opduiken.\n */\n /**\n * `editPath` is het CANONIEKE pad — zonder taalprefix, want zo houdt de editor zijn werkversie\n * bij. De URL-balk heeft die prefix wél (`/de/over-ons`). Vergeleken zonder die prefix eraf te\n * halen was de werkversie op elke vertaalde pagina onzichtbaar: de editor stond open, je typte,\n * en de pagina bleef stug het gepubliceerde tonen. Eéntalige sites merkten hier niets van —\n * precies waarom dit zo lang kon blijven staan.\n */\n const opDezePagina =\n draftBlocks !== null &&\n typeof window !== \"undefined\" &&\n (() => {\n const { slugs } = parseLocaleSlugs(\n window.location.pathname.split(\"/\").filter(Boolean),\n siteLocales(config),\n );\n return huidigPad(\"/\" + slugs.join(\"/\")) === editPath;\n })();\n\n const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : page;\n\n return (\n <BlockDataProvider data={blockData}>\n {/* Alleen op de pagina die de editor open heeft: anders krijgt een preview of ingekaderde\n pagina óók 📷-knopjes, terwijl een klik daar in het verkeerde draft zou landen. */}\n <InlineImageEditProvider onReplace={opDezePagina ? fotoVervanger : null}>\n <PageRenderer page={teTonen} registry={registry} siteId={siteId} mode={mode} />\n </InlineImageEditProvider>\n </BlockDataProvider>\n );\n}\n\n/** Normaliseert een pad zoals de editor het bijhoudt: geen trailing slash, root blijft \"/\". */\nfunction huidigPad(p: string): string {\n const schoon = p.replace(/\\/+$/, \"\");\n return schoon === \"\" ? \"/\" : schoon;\n}\n"],"mappings":";AA0GQ;AAxGR,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa,yBAAyB;AAC/C,SAAS,iBAAiB;AAC1B,SAAS,cAAc,oBAAoB;AAC3C,SAAS,+BAA+B;AACxC,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,mBAAmB;AAcvC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,SAAS,cAAc;AAC7B,QAAM,EAAE,aAAa,UAAU,cAAc,IAAI,UAAU;AAkB3D,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,EAAG;AACrB,UAAM,MAAM,UAAU,OAAO,SAAS,QAAQ;AAI9C,UAAM,WAAW;AACjB,iBAAa,QAAQ,KAAK;AAAA,MACxB,GAAG;AAAA,MACH,OAAO,SAAS,SAAS,SAAS;AAAA,MAClC,MAAM,SAAS,SAAS,IAAI,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAAA,MAChE,MAAM;AAAA,IACR,CAAS;AAAA,EAIX,GAAG,CAAC,QAAQ,IAAI,CAAC;AAkBjB,QAAM,eACJ,gBAAgB,QAChB,OAAO,WAAW,gBACjB,MAAM;AACL,UAAM,EAAE,MAAM,IAAI;AAAA,MAChB,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,MAClD,YAAY,MAAM;AAAA,IACpB;AACA,WAAO,UAAU,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;AAAA,EAC9C,GAAG;AAEL,QAAM,UAAU,eAAe,EAAE,GAAG,MAAM,QAAQ,YAAY,IAAI;AAElE,SACE,oBAAC,qBAAkB,MAAM,WAGvB,8BAAC,2BAAwB,WAAW,eAAe,gBAAgB,MACjE,8BAAC,gBAAa,MAAM,SAAS,UAAoB,QAAgB,MAAY,GAC/E,GACF;AAEJ;AAGA,SAAS,UAAU,GAAmB;AACpC,QAAM,SAAS,EAAE,QAAQ,QAAQ,EAAE;AACnC,SAAO,WAAW,KAAK,MAAM;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../../src/render/PublishedPage.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { PageRenderer } from \"./PageRenderer\";\nimport { useRegistry, BlockDataProvider } from \"../blocks/context\";\nimport { useEditor } from \"../editor/EditorProvider\";\nimport { isDemoActive, registerSeed } from \"../demo/demoStore\";\nimport { InlineImageEditProvider } from \"../media/ImageContext\";\nimport { useSiteConfig } from \"../config\";\nimport { parseLocaleSlugs, siteLocales } from \"../i18n/overlay\";\nimport type { Page } from \"../schema/pages\";\n\n/**\n * Rendert een (gepubliceerde) pagina via de **context-registry** (module-resolved, opgebouwd in\n * XiCMSProvider). Gebruik dit i.p.v. zelf `createRegistry([...builtinBlocks])` server-side te bouwen:\n * sinds de blokken op Astryx draaien zijn de meeste `\"use client\"`, en een server-opgebouwde registry\n * krijgt daar alleen opake client-referenties van → die blokken worden stil overgeslagen. Deze client-\n * component zit binnen de provider en heeft dus de volledige registry.\n *\n * `blockData` (5.6, optioneel): server-gefetchte startdata per domein (bv. `{ shop: … }` uit\n * `getShopPageData`). Data-blokken renderen dan direct met inhoud (SSR/ISR) i.p.v. eerst\n * client-side te fetchen. Moet serialiseerbare plain data zijn (server → client-prop).\n */\nexport function PublishedPage({\n page,\n siteId,\n mode = \"view\",\n blockData,\n}: {\n page: Pick<Page, \"blocks\">;\n siteId: string;\n mode?: \"view\" | \"preview\";\n blockData?: Record<string, unknown>;\n}) {\n const registry = useRegistry();\n const config = useSiteConfig();\n const { draftBlocks, editPath, fotoVervanger, publishedOverride } = useEditor();\n\n /**\n * In een DEMO is deze pagina zijn eigen uitgangspunt.\n *\n * De demo-bewerkmodus bewaart wijzigingen in de browser en legt die over een \"seed\": de\n * oorspronkelijke pagina waar de bezoeker op verder bewerkt. Zonder geregistreerde seed geeft\n * `resolveDemoPage` niets terug, meldt de editor \"Nog geen werkversie\", en loopt de enige knop\n * die dan overblijft (\"+ Pagina aanmaken\") tegen de échte database aan.\n *\n * Dat overkwam elke demo-site behalve xicms.nl zelf, want daar stond de registratie met de hand\n * in een eigen catch-all route. Een klantsite heeft die route niet en had dus wél een\n * demo-bewerkmodus in de balk, maar geen enkele pagina om te bewerken — op sites die bestaan om\n * te laten zien hoe prettig het bewerken werkt.\n *\n * Hier hoort het thuis: dit component wéét welke pagina er op dit pad staat. Buiten de demo doet\n * het niets, en in de demo is de seed per definitie gelijk aan wat de bezoeker ziet.\n */\n useEffect(() => {\n if (!isDemoActive()) return;\n const pad = huidigPad(window.location.pathname);\n // Titel en slug horen erbij: de editor toont ze in zijn balk en in de pagina-instellingen.\n // `page` levert in de praktijk het hele pagina-object; deze twee zijn de terugval voor een site\n // die alleen blokken doorgeeft — het type belooft immers niet meer dan `blocks`.\n const volledig = page as Partial<Page> & Pick<Page, \"blocks\">;\n registerSeed(siteId, pad, {\n ...volledig,\n title: volledig.title || document.title,\n slug: volledig.slug || (pad.split(\"/\").filter(Boolean).pop() ?? \"\"),\n path: pad,\n } as Page);\n // Alleen op het pad en de inhoud: opnieuw registreren bij elke render zou de seed tijdens het\n // bewerken vervangen door de zojuist bewerkte tekst, en dan is er geen origineel meer om op\n // terug te vallen.\n }, [siteId, page]);\n\n /**\n * Staat de editor open op DEZE pagina, dan tonen we de werkversie in plaats van het\n * gepubliceerde. Zo blijft de site zijn eigen layout en huisstijl tekenen, en is wat je ziet\n * precies wat je bewerkt — in plaats van een nabootsing in een apart editorvenster.\n *\n * De padvergelijking is niet overdreven voorzichtig: een pagina kan meerdere gerenderde pagina's\n * in beeld hebben (een preview, een ingekaderde pagina). Zonder die controle zou de werkversie\n * van de ene pagina in de andere opduiken.\n */\n /**\n * `editPath` is het CANONIEKE pad — zonder taalprefix, want zo houdt de editor zijn werkversie\n * bij. De URL-balk heeft die prefix wél (`/de/over-ons`). Vergeleken zonder die prefix eraf te\n * halen was de werkversie op elke vertaalde pagina onzichtbaar: de editor stond open, je typte,\n * en de pagina bleef stug het gepubliceerde tonen. Eéntalige sites merkten hier niets van —\n * precies waarom dit zo lang kon blijven staan.\n */\n const huidigCanoniekPad =\n typeof window !== \"undefined\"\n ? (() => {\n const { slugs } = parseLocaleSlugs(\n window.location.pathname.split(\"/\").filter(Boolean),\n siteLocales(config),\n );\n return huidigPad(\"/\" + slugs.join(\"/\"));\n })()\n : null;\n\n const opDezePagina = draftBlocks !== null && huidigCanoniekPad !== null && huidigCanoniekPad === editPath;\n\n /**\n * Net gepubliceerd, maar de bewerkmodus staat uit (of nog niet aan) op DEZE pagina: dan valt\n * `page` terug op de server-props van de eerste keer laden, en die zijn niet ververst — \"Live\n * site\" bekijken vlak na publiceren toonde daardoor nog de OUDE tekst totdat je de pagina zelf\n * herlaadde. `publishedOverride` (gezet door de editor direct na `publishPage`) vangt precies\n * dit gat op, zonder dat elke publicatie een volledige page-refetch hoeft te triggeren.\n */\n const overrideVoorDezePagina =\n !opDezePagina && publishedOverride !== null && huidigCanoniekPad !== null && huidigCanoniekPad === publishedOverride.path\n ? publishedOverride.blocks\n : null;\n\n const teTonen = opDezePagina\n ? { ...page, blocks: draftBlocks }\n : overrideVoorDezePagina\n ? { ...page, blocks: overrideVoorDezePagina }\n : page;\n\n return (\n <BlockDataProvider data={blockData}>\n {/* Alleen op de pagina die de editor open heeft: anders krijgt een preview of ingekaderde\n pagina óók 📷-knopjes, terwijl een klik daar in het verkeerde draft zou landen. */}\n <InlineImageEditProvider onReplace={opDezePagina ? fotoVervanger : null}>\n <PageRenderer page={teTonen} registry={registry} siteId={siteId} mode={mode} />\n </InlineImageEditProvider>\n </BlockDataProvider>\n );\n}\n\n/** Normaliseert een pad zoals de editor het bijhoudt: geen trailing slash, root blijft \"/\". */\nfunction huidigPad(p: string): string {\n const schoon = p.replace(/\\/+$/, \"\");\n return schoon === \"\" ? \"/\" : schoon;\n}\n"],"mappings":";AA4HQ;AA1HR,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa,yBAAyB;AAC/C,SAAS,iBAAiB;AAC1B,SAAS,cAAc,oBAAoB;AAC3C,SAAS,+BAA+B;AACxC,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,mBAAmB;AAcvC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,SAAS,cAAc;AAC7B,QAAM,EAAE,aAAa,UAAU,eAAe,kBAAkB,IAAI,UAAU;AAkB9E,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,EAAG;AACrB,UAAM,MAAM,UAAU,OAAO,SAAS,QAAQ;AAI9C,UAAM,WAAW;AACjB,iBAAa,QAAQ,KAAK;AAAA,MACxB,GAAG;AAAA,MACH,OAAO,SAAS,SAAS,SAAS;AAAA,MAClC,MAAM,SAAS,SAAS,IAAI,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAAA,MAChE,MAAM;AAAA,IACR,CAAS;AAAA,EAIX,GAAG,CAAC,QAAQ,IAAI,CAAC;AAkBjB,QAAM,oBACJ,OAAO,WAAW,eACb,MAAM;AACL,UAAM,EAAE,MAAM,IAAI;AAAA,MAChB,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,MAClD,YAAY,MAAM;AAAA,IACpB;AACA,WAAO,UAAU,MAAM,MAAM,KAAK,GAAG,CAAC;AAAA,EACxC,GAAG,IACH;AAEN,QAAM,eAAe,gBAAgB,QAAQ,sBAAsB,QAAQ,sBAAsB;AASjG,QAAM,yBACJ,CAAC,gBAAgB,sBAAsB,QAAQ,sBAAsB,QAAQ,sBAAsB,kBAAkB,OACjH,kBAAkB,SAClB;AAEN,QAAM,UAAU,eACZ,EAAE,GAAG,MAAM,QAAQ,YAAY,IAC/B,yBACE,EAAE,GAAG,MAAM,QAAQ,uBAAuB,IAC1C;AAEN,SACE,oBAAC,qBAAkB,MAAM,WAGvB,8BAAC,2BAAwB,WAAW,eAAe,gBAAgB,MACjE,8BAAC,gBAAa,MAAM,SAAS,UAAoB,QAAgB,MAAY,GAC/E,GACF;AAEJ;AAGA,SAAS,UAAU,GAAmB;AACpC,QAAM,SAAS,EAAE,QAAQ,QAAQ,EAAE;AACnC,SAAO,WAAW,KAAK,MAAM;AAC/B;","names":[]}
@@ -164,6 +164,7 @@ export type OrderStatus = z.infer<typeof OrderStatusSchema>;
164
164
  export declare const OrderItemSchema: z.ZodMiniObject<{
165
165
  kind: z.ZodMiniDefault<z.ZodMiniEnum<{
166
166
  donation: "donation";
167
+ giftwrap: "giftwrap";
167
168
  product: "product";
168
169
  }>>;
169
170
  productId: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -212,6 +213,7 @@ export declare const OrderSchema: z.ZodMiniObject<{
212
213
  items: z.ZodMiniArray<z.ZodMiniObject<{
213
214
  kind: z.ZodMiniDefault<z.ZodMiniEnum<{
214
215
  donation: "donation";
216
+ giftwrap: "giftwrap";
215
217
  product: "product";
216
218
  }>>;
217
219
  productId: z.ZodMiniOptional<z.ZodMiniString<string>>;
@@ -256,8 +258,18 @@ export declare const OrderSchema: z.ZodMiniObject<{
256
258
  city: z.ZodMiniString<string>;
257
259
  country: z.ZodMiniDefault<z.ZodMiniString<string>>;
258
260
  }, z.core.$strip>>;
261
+ billing: z.ZodMiniOptional<z.ZodMiniObject<{
262
+ address: z.ZodMiniString<string>;
263
+ zip: z.ZodMiniString<string>;
264
+ city: z.ZodMiniString<string>;
265
+ country: z.ZodMiniDefault<z.ZodMiniString<string>>;
266
+ }, z.core.$strip>>;
259
267
  note: z.ZodMiniOptional<z.ZodMiniString<string>>;
260
268
  adminNote: z.ZodMiniOptional<z.ZodMiniString<string>>;
269
+ giftWrap: z.ZodMiniOptional<z.ZodMiniObject<{
270
+ cardText: z.ZodMiniOptional<z.ZodMiniString<string>>;
271
+ note: z.ZodMiniOptional<z.ZodMiniString<string>>;
272
+ }, z.core.$strip>>;
261
273
  invoiceNumber: z.ZodMiniOptional<z.ZodMiniString<string>>;
262
274
  manual: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
263
275
  refundedCents: z.ZodMiniOptional<z.ZodMiniNumberFormat>;
@@ -317,7 +329,17 @@ export declare const CreateOrderInputSchema: z.ZodMiniObject<{
317
329
  city: z.ZodMiniString<string>;
318
330
  country: z.ZodMiniDefault<z.ZodMiniString<string>>;
319
331
  }, z.core.$strip>>;
332
+ billing: z.ZodMiniOptional<z.ZodMiniObject<{
333
+ address: z.ZodMiniString<string>;
334
+ zip: z.ZodMiniString<string>;
335
+ city: z.ZodMiniString<string>;
336
+ country: z.ZodMiniDefault<z.ZodMiniString<string>>;
337
+ }, z.core.$strip>>;
320
338
  note: z.ZodMiniOptional<z.ZodMiniString<string>>;
339
+ giftWrap: z.ZodMiniOptional<z.ZodMiniObject<{
340
+ cardText: z.ZodMiniOptional<z.ZodMiniString<string>>;
341
+ note: z.ZodMiniOptional<z.ZodMiniString<string>>;
342
+ }, z.core.$strip>>;
321
343
  discountCode: z.ZodMiniOptional<z.ZodMiniString<string>>;
322
344
  successPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
323
345
  cancelPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
@@ -141,7 +141,7 @@ import {
141
141
  } from "./mail.js";
142
142
  const OrderStatusSchema = z.enum(["pending", "paid", "shipped", "cancelled", "refunded"]);
143
143
  const OrderItemSchema = z.object({
144
- kind: z._default(z.enum(["product", "donation"]), "product"),
144
+ kind: z._default(z.enum(["product", "donation", "giftwrap"]), "product"),
145
145
  productId: z.optional(z.string().check(z.maxLength(80))),
146
146
  name: z.string().check(z.minLength(1)).check(z.maxLength(240)),
147
147
  variantKey: z.optional(z.string().check(z.maxLength(200))),
@@ -214,9 +214,24 @@ const OrderSchema = z.object({
214
214
  })),
215
215
  customer: OrderCustomerSchema,
216
216
  shipping: z.optional(OrderAddressSchema),
217
+ /**
218
+ * 7.27: factuuradres, alleen aanwezig als het AFWIJKT van het verzendadres — afwezig betekent
219
+ * "hetzelfde als hierboven" (bestaande orders blijven zo correct zonder migratie).
220
+ */
221
+ billing: z.optional(OrderAddressSchema),
217
222
  note: z.optional(z.string().check(z.maxLength(2e3))),
218
223
  /** 7.18: interne notitie van de winkelier — de klant ziet hem nooit. */
219
224
  adminNote: z.optional(z.string().check(z.maxLength(2e3))),
225
+ /**
226
+ * 7.27: cadeauverpakking. De MEERPRIJS staat als eigen orderregel (kind "giftwrap") — dat hoeft
227
+ * dan nergens apart herrekend/getoond te worden (btw, factuur, Stripe/Mollie-regels werken al
228
+ * generiek over `items`). Dit veld draagt alleen de klant-tekst: wat op het kaartje moet staan
229
+ * en een eventuele opmerking voor het inpakken.
230
+ */
231
+ giftWrap: z.optional(z.object({
232
+ cardText: z.optional(z.string().check(z.maxLength(300))),
233
+ note: z.optional(z.string().check(z.maxLength(500)))
234
+ })),
220
235
  /** 7.18: doorlopend factuurnummer (eigen reeks, zonder gaten) — pas gezet bij betaling. */
221
236
  invoiceNumber: z.optional(z.string().check(z.maxLength(40))),
222
237
  /** 7.18: handmatig aangemaakt in /beheer (telefonisch, markt, overschrijving). */
@@ -263,7 +278,14 @@ const CreateOrderInputSchema = z.object({
263
278
  items: z.array(CreateOrderItemInputSchema).check(z.minLength(1)).check(z.maxLength(50)),
264
279
  customer: OrderCustomerSchema,
265
280
  shipping: z.optional(OrderAddressSchema),
281
+ /** 7.27: alleen meesturen als het factuuradres afwijkt van het verzendadres. */
282
+ billing: z.optional(OrderAddressSchema),
266
283
  note: z.optional(z.string().check(z.maxLength(2e3))),
284
+ /** 7.27: aanwezig = klant wil cadeauverpakking (mag met lege tekstvelden). Prijs/aan-uit komt server-side uit de shopconfig. */
285
+ giftWrap: z.optional(z.object({
286
+ cardText: z.optional(z.string().check(z.maxLength(300))),
287
+ note: z.optional(z.string().check(z.maxLength(500)))
288
+ })),
267
289
  /** 5.6: kortingscode (server-side gevalideerd en verrekend). */
268
290
  discountCode: z.optional(z.string().check(z.maxLength(30))),
269
291
  /** Paden op de klantsite waarheen Stripe terug redirect. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/schema/shop.ts"],"sourcesContent":["import * as z from \"zod/mini\";\nimport { blockBase } from \"./blockBase\";\n\n/**\n * Shop-schema's (5.5) — webwinkel + donaties. Pure Zod: gedeeld door core, admin en Functions.\n *\n * Datamodel per tenant:\n * sites/{siteId}/shopCategories/{id} — categorieën (editor-write, publiek leesbaar)\n * sites/{siteId}/products/{id} — producten (editor-write, publiek leesbaar als actief)\n * sites/{siteId}/orders/{id} — bestellingen (ALLEEN via Functions; editor leest,\n * en mag alleen status/verzendvelden muteren)\n * sites/{siteId}/private/shop — geheimen (Stripe-key, SMTP) — deny-all, alleen Functions\n *\n * Geld is ALTIJD een integer in centen (nooit floats). Publieke shopconfig (verzendkosten,\n * paden, donatie-grenzen) leeft in de module-settings van de `shop`-module\n * (settings/public.modules.shop.config) — zie modules/shop/module.ts.\n */\n\n/* ── Categorieën ─────────────────────────────────────────────────────────── */\n\nexport const ShopCategorySchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n slug: z.string().check(z.minLength(1)).check(z.maxLength(120)).check(z.regex(/^[a-z0-9-]+$/, \"slug: alleen kleine letters, cijfers en streepjes\")),\n description: z.optional(z.string().check(z.maxLength(2000))),\n imageUrl: z.optional(z.string().check(z.maxLength(2000))),\n order: z._default(z.int().check(z.minimum(0)).check(z.maximum(9999)), 0),\n visible: z._default(z.boolean(), true),\n});\nexport type ShopCategory = z.infer<typeof ShopCategorySchema>;\n\n/* ── Producten ───────────────────────────────────────────────────────────── */\n\n/** Optie-as, bv. { name: \"Maat\", values: [\"56\",\"62\",\"68\",\"74\"] }. Max 3 assen per product. */\nexport const ProductOptionSchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n values: z.array(z.string().check(z.minLength(1)).check(z.maxLength(60))).check(z.minLength(1)).check(z.maxLength(30)),\n /**\n * 5.6: afbeelding per optieWAARDE — `{ \"Roze\": \"https://…\" }`. De detailpagina wisselt het\n * hoofdbeeld mee met de keuze; bewust per as en niet per variant-combinatie (maat × kleur zou\n * het aantal afbeeldingen laten exploderen).\n */\n images: z.optional(z.record(z.string(), z.string().check(z.maxLength(2000)))),\n /**\n * 7.23: heeft élke waarde van deze as een eigen foto?\n *\n * Tot nu toe was dat geen keuze maar een naamtruc: alleen een as die \"Kleur\"/\"Color\"/\"Colour\"\n * heette kreeg fotoknoppen. Noemde je hem \"Print\", \"Dessin\" of \"Uitvoering\", dan kon je er geen\n * foto's aan hangen — en hernoemde je een bestaande kleur-as, dan verdwenen de knoppen terwijl\n * de foto's onzichtbaar in het document achterbleven. Nu is het een vinkje in het\n * productformulier en staat de naam er los van.\n *\n * Drie toestanden, met opzet: `true` = aan, `false` = uit, en **afwezig** = \"nooit ingesteld\",\n * en dan valt `beeldOptie()` terug op de oude naamcheck. Zo blijven alle bestaande producten\n * werken zonder migratie, terwijl één klik de nieuwe regel vastlegt.\n *\n * Eén as tegelijk: het hoofdbeeld kan maar één keuze volgen. Het formulier zet de vlag daarom\n * bij de andere assen uit zodra je hem hier aanzet.\n */\n imagePerValue: z.optional(z.boolean()),\n});\nexport type ProductOption = z.infer<typeof ProductOptionSchema>;\n\n/** Heeft deze as een eigen foto per waarde? Zonder expliciete keuze: de oude kleur-naamregel. */\nexport function optieHeeftBeeldPerWaarde(optie: Pick<ProductOption, \"name\" | \"imagePerValue\">): boolean {\n return optie.imagePerValue ?? /^kleur|^colou?r/i.test(optie.name);\n}\n\n/**\n * Personalisatie-veld (5.6): de klant geeft eigen tekst of een eigen afbeelding op\n * (bv. \"rompertje met naam\"). Meerprijs telt server-side mee in `createOrder`.\n */\nexport const PersonalizationFieldSchema = z.object({\n key: z.string().check(z.minLength(1)).check(z.maxLength(40)).check(z.regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, \"sleutel: letters/cijfers/underscore, beginnend met een letter\")),\n label: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n type: z.enum([\"text\", \"image\"]),\n required: z._default(z.boolean(), false),\n /** Alleen voor type \"text\". */\n maxLength: z._default(z.int().check(z.minimum(1)).check(z.maximum(200)), 40),\n /** Meerprijs in centen (per stuk). */\n priceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n helpText: z.optional(z.string().check(z.maxLength(200))),\n});\nexport type PersonalizationField = z.infer<typeof PersonalizationFieldSchema>;\n\n/** Ingevulde personalisatie op een orderregel/cartregel: per veld-key tekst of upload-pad. */\nexport const PersonalizationValueSchema = z.record(\n z.string(),\n z.object({\n text: z.optional(z.string().check(z.maxLength(200))),\n /** Storage-pad uit de uploadPersonalization-callable (géén vrije URL). */\n imagePath: z.optional(z.string().check(z.maxLength(400))),\n /** Oorspronkelijke bestandsnaam (weergave in beheer/mail). */\n fileName: z.optional(z.string().check(z.maxLength(200))),\n }),\n);\nexport type PersonalizationValue = z.infer<typeof PersonalizationValueSchema>;\n\n/**\n * Variant = één combinatie van optiewaarden. `key` is de waarden gejoined met \"|\" in\n * optie-volgorde (bv. \"68|Roze\"). Alleen aanwezig waar hij afwijkt van de product-defaults.\n */\nexport const ProductVariantSchema = z.object({\n key: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n priceCents: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00))),\n stock: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000))),\n sku: z.optional(z.string().check(z.maxLength(60))),\n active: z._default(z.boolean(), true),\n});\nexport type ProductVariant = z.infer<typeof ProductVariantSchema>;\n\nexport const ProductStatusSchema = z.enum([\"draft\", \"active\", \"archived\"]);\nexport type ProductStatus = z.infer<typeof ProductStatusSchema>;\n\n/**\n * Verwijdert top-level `null`-velden uit een productdoc vóór validatie (7.17.1).\n *\n * Er liggen productdocs met `personalization: null` (e.d.) in Firestore: de functions-SDK\n * encodeerde een client-side `undefined` als `null` over de draad (dezelfde klasse als de\n * \"+ Nieuw product\"-bug), en de callable schreef dat door. `z.optional()` accepteert een\n * ONTBREKEND veld maar geen `null`, en `parseProduct` op de leeskant slaat een ongeldig doc\n * stil over — waardoor een product dat gewoon \"actief\" in het beheer staat van de live winkel\n * verdween (gemeten op christelijkkraamcadeau: 2 van de 4 \"Maak een vrolijk geluid\"-varianten,\n * precies de twee die vóór de 7.16.2-fix nog eens waren opgeslagen). In dit model betekent\n * `null` nergens iets anders dan \"afwezig\", dus strippen is verliesvrij.\n */\nexport function saneerProductDoc<T>(data: T): T {\n if (typeof data !== \"object\" || data === null || Array.isArray(data)) return data;\n return Object.fromEntries(\n Object.entries(data as Record<string, unknown>).filter(([, v]) => v !== null),\n ) as T;\n}\n\nexport const ProductSchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n slug: z.string().check(z.minLength(1)).check(z.maxLength(120)).check(z.regex(/^[a-z0-9-]+$/, \"slug: alleen kleine letters, cijfers en streepjes\")),\n /**\n * Beschrijving als platte tekst (regeleinden blijven behouden). Bewust géén HTML:\n * producten worden client-side door editors geschreven (rules-pad, niet via de\n * publish-sanitizer), dus HTML zou hier een XSS-route zijn.\n */\n description: z._default(z.string().check(z.maxLength(20_000)), \"\"),\n categoryIds: z._default(z.array(z.string().check(z.maxLength(80))).check(z.maxLength(20)), []),\n /** Afbeeldings-URL's (via de mediabibliotheek). Eerste = hoofdbeeld. */\n images: z._default(z.array(z.string().check(z.maxLength(2000))).check(z.maxLength(12)), []),\n /** Prijs incl. btw, in centen. */\n priceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n /** Doorgestreepte \"van\"-prijs (optioneel). */\n compareAtCents: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00))),\n /** Btw-tarief (NL): 21, 9 of 0. Prijzen zijn inclusief. */\n vatRate: z._default(z.union([z.literal(21), z.literal(9), z.literal(0)]), 21),\n options: z._default(z.array(ProductOptionSchema).check(z.maxLength(3)), []),\n variants: z._default(z.array(ProductVariantSchema).check(z.maxLength(200)), []),\n /** Voorraad bijhouden? false = altijd bestelbaar (op-maat/print-on-demand). */\n trackStock: z._default(z.boolean(), false),\n /** Voorraad voor producten zónder varianten (met varianten telt de variant-stock). */\n stock: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000))),\n status: z._default(ProductStatusSchema, \"draft\"),\n /** Sorteervolgorde binnen een categorie (laag = eerst). */\n order: z._default(z.int().check(z.minimum(0)).check(z.maximum(9999)), 0),\n featured: z._default(z.boolean(), false),\n /** 5.6: personalisatie-velden (eigen naam/logo) — max 3 per product. */\n personalization: z.optional(z.array(PersonalizationFieldSchema).check(z.maxLength(3))),\n /**\n * Staat \"persoonlijk maken\" aan voor dit product? (7.19)\n *\n * Voorheen was dit impliciet: velden aanwezig = aan. Wie het tijdelijk wilde uitzetten (te\n * druk, vakantie, leverancier levert de bedrukking niet) moest de velden VERWIJDEREN en dus\n * ook zijn labels, meerprijzen en uitleg kwijtraken. Nu blijft de configuratie staan en gaat\n * alleen de functie uit. Default true zodat bestaande producten met velden niets merken.\n */\n personalizationEnabled: z._default(z.boolean(), true),\n});\nexport type Product = z.infer<typeof ProductSchema>;\n\n/* ── Kortingscodes ───────────────────────────────────────────────────────── */\n\n/** `sites/{siteId}/discountCodes/{CODE}` (doc-id = code in hoofdletters; editor beheert). */\nexport const DiscountCodeSchema = z.object({\n code: z.string().check(z.minLength(3)).check(z.maxLength(30)).check(z.regex(/^[A-Z0-9-]+$/, \"code: hoofdletters, cijfers en streepjes\")),\n type: z.enum([\"percent\", \"fixed\"]),\n /** percent: 1–100; fixed: bedrag in centen. */\n value: z.int().check(z.minimum(1)).check(z.maximum(1_000_000_00)),\n minOrderCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n freeShipping: z._default(z.boolean(), false),\n active: z._default(z.boolean(), true),\n /** ISO-datums (yyyy-mm-dd); leeg = geen grens. */\n startsAt: z.optional(z.string().check(z.maxLength(10))),\n endsAt: z.optional(z.string().check(z.maxLength(10))),\n /** 0 = onbeperkt. `usedCount` wordt door de webhook transactioneel opgehoogd. */\n maxUses: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000)), 0),\n usedCount: z._default(z.int().check(z.minimum(0)), 0),\n /**\n * Eén keer per e-mailadres (7.18) — de klassieke welkomstkorting. De server telt de eerder\n * BETAALDE orders van dat adres met deze code; een afgebroken checkout brandt hem dus niet op.\n */\n oncePerCustomer: z._default(z.boolean(), false),\n});\nexport type DiscountCode = z.infer<typeof DiscountCodeSchema>;\n\n/* ── Mail-templates ──────────────────────────────────────────────────────── */\n\n// Mailtemplates zijn site-breed (ook zonder shop) — de canonieke definitie staat in `./mail`.\n// Hier her-geëxporteerd voor backward-compat van bestaande shop-importeurs.\nexport {\n MAIL_TEMPLATE_KEYS,\n MAIL_TEMPLATE_DEFS,\n MailTemplateSchema,\n MailTemplatesSchema,\n type MailTemplateKey,\n type MailTemplates,\n} from \"./mail\";\n\n/* ── Bestellingen ────────────────────────────────────────────────────────── */\n\nexport const OrderStatusSchema = z.enum([\"pending\", \"paid\", \"shipped\", \"cancelled\", \"refunded\"]);\nexport type OrderStatus = z.infer<typeof OrderStatusSchema>;\n\n/** Orderregel: snapshot van naam/prijs op besteldatum — blijft kloppen als het product wijzigt. */\nexport const OrderItemSchema = z.object({\n kind: z._default(z.enum([\"product\", \"donation\"]), \"product\"),\n productId: z.optional(z.string().check(z.maxLength(80))),\n name: z.string().check(z.minLength(1)).check(z.maxLength(240)),\n variantKey: z.optional(z.string().check(z.maxLength(200))),\n qty: z.int().check(z.minimum(1)).check(z.maximum(999)),\n /** Incl. eventuele personalisatie-meerprijs. */\n unitPriceCents: z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)),\n vatRate: z._default(z.union([z.literal(21), z.literal(9), z.literal(0)]), 21),\n /** 5.6: ingevulde personalisatie (\"Naam: Boaz\", upload-pad). */\n personalization: z.optional(PersonalizationValueSchema),\n /**\n * 7.18: het deel van `unitPriceCents` dat personalisatie-meerprijs is.\n *\n * De meerprijs werkte al end-to-end, maar zat onzichtbaar in de stukprijs: een klant die\n * € 16,95 betaalde voor een product van € 13,95 zag nergens waar die € 3,00 vandaan kwam.\n * Apart opslaan (i.p.v. bij het tonen terugrekenen) houdt de historie kloppend als de\n * meerprijs van het product later verandert.\n */\n personalizationCents: z._default(z.int().check(z.minimum(0)), 0),\n /**\n * 7.22: de categorie waarin dit product verkocht is.\n *\n * Bij een winkel als Christelijk Kraamcadeau is `name` alleen het ontwerp (\"Blij blij\") en zegt\n * de categorie wát het is: rompertje, slabbetje, korte- of lange-mouw t-shirt. Hetzelfde ontwerp\n * bestaat in vijf categorieën, dus zonder dit veld staat er vier keer een identieke regel op de\n * pakbon, de factuur en in de bevestigingsmail — en weet niemand wat er de deur uit moet.\n *\n * Meegeschreven als momentopname, net als `name` en `unitPriceCents`: hernoem je later een\n * categorie, dan blijft een oude bestelling zeggen wat er destijds verkocht is.\n */\n categoryName: z.optional(z.string().check(z.maxLength(120))),\n});\nexport type OrderItem = z.infer<typeof OrderItemSchema>;\n\n/** \"Blij blij — Slabbetje\": de productnaam plus de categorie waarin hij verkocht is. */\nexport function orderRegelNaam(item: { name: string; categoryName?: string }): string {\n return item.categoryName ? `${item.name} — ${item.categoryName}` : item.name;\n}\n\nexport const OrderAddressSchema = z.object({\n address: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n zip: z.string().check(z.minLength(1)).check(z.maxLength(20)),\n city: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n country: z._default(z.string().check(z.minLength(2)).check(z.maxLength(2)), \"NL\"),\n});\nexport type OrderAddress = z.infer<typeof OrderAddressSchema>;\n\nexport const OrderCustomerSchema = z.object({\n email: z.email().check(z.maxLength(200)),\n name: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n phone: z.optional(z.string().check(z.maxLength(40))),\n});\nexport type OrderCustomer = z.infer<typeof OrderCustomerSchema>;\n\n/** Volledige order zoals door Functions geschreven (timestamps komen daarbovenop). */\nexport const OrderSchema = z.object({\n number: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n status: OrderStatusSchema,\n items: z.array(OrderItemSchema).check(z.minLength(1)).check(z.maxLength(50)),\n amount: z.object({\n itemsCents: z.int().check(z.minimum(0)),\n shippingCents: z.int().check(z.minimum(0)),\n /** 5.6: toegepaste korting (0 = geen). */\n discountCents: z._default(z.int().check(z.minimum(0)), 0),\n totalCents: z.int().check(z.minimum(0)),\n /**\n * 7.18: btw-bedrag in de order zelf. Werd eerder alleen op de factuur en in de CSV-export\n * afgeleid — twee losse kopieën van dezelfde som, terwijl dit voor de aangifte hét getal is.\n */\n vatCents: z.optional(z.int().check(z.minimum(0))),\n /** Btw per tarief (\"21\" → centen), voor de aangifte per categorie. */\n vatByRate: z.optional(z.record(z.string(), z.int())),\n }),\n /** 5.6: toegepaste kortingscode (snapshot). */\n discount: z.optional(z.object({\n code: z.string().check(z.maxLength(30)),\n type: z.enum([\"percent\", \"fixed\"]),\n value: z.int(),\n freeShipping: z._default(z.boolean(), false),\n })),\n customer: OrderCustomerSchema,\n shipping: z.optional(OrderAddressSchema),\n note: z.optional(z.string().check(z.maxLength(2000))),\n /** 7.18: interne notitie van de winkelier — de klant ziet hem nooit. */\n adminNote: z.optional(z.string().check(z.maxLength(2000))),\n /** 7.18: doorlopend factuurnummer (eigen reeks, zonder gaten) — pas gezet bij betaling. */\n invoiceNumber: z.optional(z.string().check(z.maxLength(40))),\n /** 7.18: handmatig aangemaakt in /beheer (telefonisch, markt, overschrijving). */\n manual: z.optional(z.boolean()),\n /** 7.18: som van alle (gedeeltelijke) terugbetalingen in centen. */\n refundedCents: z.optional(z.int().check(z.minimum(0))),\n /**\n * 7.18: berichten die naar de klant zijn gestuurd — handmatig vanuit /beheer, en sinds 7.25\n * ook automatisch (bevestiging, verzonden, geannuleerd, terugbetaald, betaalverzoek). Zonder\n * dat spoor was er geen manier om te zien of een klant-mail is aangekomen of dat de order\n * stilletjes zonder bericht is geannuleerd.\n */\n messages: z.optional(z.array(z.object({\n at: z.string().check(z.maxLength(40)),\n /** uid van de medewerker, of \"systeem\" bij een automatische mail. */\n by: z.optional(z.string().check(z.maxLength(200))),\n subject: z.string().check(z.maxLength(200)),\n body: z.string().check(z.maxLength(2000)),\n /** 7.25: automatisch verstuurd (order-gebeurtenis) i.p.v. handmatig getypt. */\n automatisch: z.optional(z.boolean()),\n /** 7.25: het versturen is mislukt — blijft zichtbaar i.p.v. stil te verdwijnen. */\n mislukt: z.optional(z.boolean()),\n })).check(z.maxLength(50))),\n /** 5.6: track & trace-link (gezet bij \"verzonden\"). */\n trackingUrl: z.optional(z.string().check(z.maxLength(500))),\n /** 5.6: factuur-pad in Storage (gezet door de webhook). */\n invoicePath: z.optional(z.string().check(z.maxLength(400))),\n stripe: z._default(z.object({\n sessionId: z.optional(z.string().check(z.maxLength(200))),\n paymentIntentId: z.optional(z.string().check(z.maxLength(200))),\n }), {}),\n});\nexport type Order = z.infer<typeof OrderSchema>;\n\n/* ── Callable-input (checkout) ───────────────────────────────────────────── */\n\n/**\n * Input van de `createOrder`-callable. Client-prijzen worden NOOIT vertrouwd: de functie\n * herrekent alles tegen de opgeslagen product-docs. Alleen `donationCents` komt van de\n * client (binnen de per-site ingestelde min/max van het donatie-block).\n */\nexport const CreateOrderItemInputSchema = z.object({\n productId: z.optional(z.string().check(z.minLength(1)).check(z.maxLength(80))),\n variantKey: z.optional(z.string().check(z.maxLength(200))),\n qty: z._default(z.int().check(z.minimum(1)).check(z.maximum(999)), 1),\n /** Alleen voor donaties (zonder productId). */\n donationCents: z.optional(z.int().check(z.minimum(50)).check(z.maximum(1_000_000_00))),\n /** 5.6: personalisatie-invoer (gevalideerd tegen product.personalization). */\n personalization: z.optional(PersonalizationValueSchema),\n});\n\nexport const CreateOrderInputSchema = z.object({\n siteId: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n items: z.array(CreateOrderItemInputSchema).check(z.minLength(1)).check(z.maxLength(50)),\n customer: OrderCustomerSchema,\n shipping: z.optional(OrderAddressSchema),\n note: z.optional(z.string().check(z.maxLength(2000))),\n /** 5.6: kortingscode (server-side gevalideerd en verrekend). */\n discountCode: z.optional(z.string().check(z.maxLength(30))),\n /** Paden op de klantsite waarheen Stripe terug redirect. */\n successPath: z._default(z.string().check(z.maxLength(400)), \"/bedankt\"),\n cancelPath: z._default(z.string().check(z.maxLength(400)), \"/winkelwagen\"),\n /** Honeypot — moet leeg zijn (bot-detectie). */\n _hp: z.optional(z.string().check(z.maxLength(0))),\n});\nexport type CreateOrderInput = z.infer<typeof CreateOrderInputSchema>;\n\n/* ── Block-schema's ──────────────────────────────────────────────────────── */\n\nexport const ShopCategoriesBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"shopCategories\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n columns: z._default(z.int().check(z.minimum(2)).check(z.maximum(4)), 3),\n});\n\nexport const ProductGridBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"productGrid\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n /** Vast categorie-filter (slug). Leeg + useQueryCategory → filter via `?cat=` in de URL. */\n categorySlug: z.optional(z.string().check(z.maxLength(120))),\n useQueryCategory: z._default(z.boolean(), true),\n featuredOnly: z._default(z.boolean(), false),\n columns: z._default(z.int().check(z.minimum(2)).check(z.maximum(4)), 3),\n limit: z._default(z.int().check(z.minimum(1)).check(z.maximum(200)), 60),\n sort: z._default(z.enum([\"order\", \"name\", \"priceAsc\", \"priceDesc\"]), \"order\"),\n /** 5.6: filterchips (kleur/maat) + sorteerkeuze boven het grid. */\n showFilters: z._default(z.boolean(), false),\n});\n\nexport const ProductDetailBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"productDetail\"),\n /** Vast product (slug); leeg → product uit `?p=` in de URL (één generieke detailpagina). */\n slug: z.optional(z.string().check(z.maxLength(120))),\n /** 5.6: \"Ook leuk\"-rij met producten uit dezelfde categorie. */\n showRelated: z._default(z.boolean(), true),\n});\n\nexport const CartBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"cart\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n});\n\nexport const CheckoutBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"checkout\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n introText: z.optional(z.string().check(z.maxLength(2000))),\n});\n\nexport const DonationBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"donation\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n introText: z.optional(z.string().check(z.maxLength(2000))),\n /** Voorgestelde bedragen in centen. */\n amountsCents: z._default(z.array(z.int().check(z.minimum(50)).check(z.maximum(1_000_000_00))).check(z.maxLength(8)), [500, 1000, 2500]),\n allowCustom: z._default(z.boolean(), true),\n customMinCents: z._default(z.int().check(z.minimum(50)), 100),\n customMaxCents: z._default(z.int().check(z.maximum(1_000_000_00)), 100_000),\n buttonLabel: z._default(z.string().check(z.maxLength(80)), \"Doneer\"),\n});\n\nexport const OrderStatusBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"orderStatus\"),\n successTitle: z._default(z.string().check(z.maxLength(200)), \"Bedankt voor je bestelling!\"),\n successText: z._default(z.string().check(z.maxLength(2000)), \"Je ontvangt zo een bevestiging per e-mail.\"),\n cancelledTitle: z._default(z.string().check(z.maxLength(200)), \"Betaling niet afgerond\"),\n cancelledText: z._default(z.string().check(z.maxLength(2000)), \"Je bestelling is niet betaald. Probeer het gerust opnieuw.\"),\n});\n\n/* ── Helpers (gedeeld client/server) ─────────────────────────────────────── */\n\nexport { variantKeyFor, productPriceCents, shippingCentsFor, formatCents } from \"./shopGeld\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/schema/shop.ts"],"sourcesContent":["import * as z from \"zod/mini\";\nimport { blockBase } from \"./blockBase\";\n\n/**\n * Shop-schema's (5.5) — webwinkel + donaties. Pure Zod: gedeeld door core, admin en Functions.\n *\n * Datamodel per tenant:\n * sites/{siteId}/shopCategories/{id} — categorieën (editor-write, publiek leesbaar)\n * sites/{siteId}/products/{id} — producten (editor-write, publiek leesbaar als actief)\n * sites/{siteId}/orders/{id} — bestellingen (ALLEEN via Functions; editor leest,\n * en mag alleen status/verzendvelden muteren)\n * sites/{siteId}/private/shop — geheimen (Stripe-key, SMTP) — deny-all, alleen Functions\n *\n * Geld is ALTIJD een integer in centen (nooit floats). Publieke shopconfig (verzendkosten,\n * paden, donatie-grenzen) leeft in de module-settings van de `shop`-module\n * (settings/public.modules.shop.config) — zie modules/shop/module.ts.\n */\n\n/* ── Categorieën ─────────────────────────────────────────────────────────── */\n\nexport const ShopCategorySchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n slug: z.string().check(z.minLength(1)).check(z.maxLength(120)).check(z.regex(/^[a-z0-9-]+$/, \"slug: alleen kleine letters, cijfers en streepjes\")),\n description: z.optional(z.string().check(z.maxLength(2000))),\n imageUrl: z.optional(z.string().check(z.maxLength(2000))),\n order: z._default(z.int().check(z.minimum(0)).check(z.maximum(9999)), 0),\n visible: z._default(z.boolean(), true),\n});\nexport type ShopCategory = z.infer<typeof ShopCategorySchema>;\n\n/* ── Producten ───────────────────────────────────────────────────────────── */\n\n/** Optie-as, bv. { name: \"Maat\", values: [\"56\",\"62\",\"68\",\"74\"] }. Max 3 assen per product. */\nexport const ProductOptionSchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n values: z.array(z.string().check(z.minLength(1)).check(z.maxLength(60))).check(z.minLength(1)).check(z.maxLength(30)),\n /**\n * 5.6: afbeelding per optieWAARDE — `{ \"Roze\": \"https://…\" }`. De detailpagina wisselt het\n * hoofdbeeld mee met de keuze; bewust per as en niet per variant-combinatie (maat × kleur zou\n * het aantal afbeeldingen laten exploderen).\n */\n images: z.optional(z.record(z.string(), z.string().check(z.maxLength(2000)))),\n /**\n * 7.23: heeft élke waarde van deze as een eigen foto?\n *\n * Tot nu toe was dat geen keuze maar een naamtruc: alleen een as die \"Kleur\"/\"Color\"/\"Colour\"\n * heette kreeg fotoknoppen. Noemde je hem \"Print\", \"Dessin\" of \"Uitvoering\", dan kon je er geen\n * foto's aan hangen — en hernoemde je een bestaande kleur-as, dan verdwenen de knoppen terwijl\n * de foto's onzichtbaar in het document achterbleven. Nu is het een vinkje in het\n * productformulier en staat de naam er los van.\n *\n * Drie toestanden, met opzet: `true` = aan, `false` = uit, en **afwezig** = \"nooit ingesteld\",\n * en dan valt `beeldOptie()` terug op de oude naamcheck. Zo blijven alle bestaande producten\n * werken zonder migratie, terwijl één klik de nieuwe regel vastlegt.\n *\n * Eén as tegelijk: het hoofdbeeld kan maar één keuze volgen. Het formulier zet de vlag daarom\n * bij de andere assen uit zodra je hem hier aanzet.\n */\n imagePerValue: z.optional(z.boolean()),\n});\nexport type ProductOption = z.infer<typeof ProductOptionSchema>;\n\n/** Heeft deze as een eigen foto per waarde? Zonder expliciete keuze: de oude kleur-naamregel. */\nexport function optieHeeftBeeldPerWaarde(optie: Pick<ProductOption, \"name\" | \"imagePerValue\">): boolean {\n return optie.imagePerValue ?? /^kleur|^colou?r/i.test(optie.name);\n}\n\n/**\n * Personalisatie-veld (5.6): de klant geeft eigen tekst of een eigen afbeelding op\n * (bv. \"rompertje met naam\"). Meerprijs telt server-side mee in `createOrder`.\n */\nexport const PersonalizationFieldSchema = z.object({\n key: z.string().check(z.minLength(1)).check(z.maxLength(40)).check(z.regex(/^[a-zA-Z][a-zA-Z0-9_]*$/, \"sleutel: letters/cijfers/underscore, beginnend met een letter\")),\n label: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n type: z.enum([\"text\", \"image\"]),\n required: z._default(z.boolean(), false),\n /** Alleen voor type \"text\". */\n maxLength: z._default(z.int().check(z.minimum(1)).check(z.maximum(200)), 40),\n /** Meerprijs in centen (per stuk). */\n priceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n helpText: z.optional(z.string().check(z.maxLength(200))),\n});\nexport type PersonalizationField = z.infer<typeof PersonalizationFieldSchema>;\n\n/** Ingevulde personalisatie op een orderregel/cartregel: per veld-key tekst of upload-pad. */\nexport const PersonalizationValueSchema = z.record(\n z.string(),\n z.object({\n text: z.optional(z.string().check(z.maxLength(200))),\n /** Storage-pad uit de uploadPersonalization-callable (géén vrije URL). */\n imagePath: z.optional(z.string().check(z.maxLength(400))),\n /** Oorspronkelijke bestandsnaam (weergave in beheer/mail). */\n fileName: z.optional(z.string().check(z.maxLength(200))),\n }),\n);\nexport type PersonalizationValue = z.infer<typeof PersonalizationValueSchema>;\n\n/**\n * Variant = één combinatie van optiewaarden. `key` is de waarden gejoined met \"|\" in\n * optie-volgorde (bv. \"68|Roze\"). Alleen aanwezig waar hij afwijkt van de product-defaults.\n */\nexport const ProductVariantSchema = z.object({\n key: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n priceCents: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00))),\n stock: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000))),\n sku: z.optional(z.string().check(z.maxLength(60))),\n active: z._default(z.boolean(), true),\n});\nexport type ProductVariant = z.infer<typeof ProductVariantSchema>;\n\nexport const ProductStatusSchema = z.enum([\"draft\", \"active\", \"archived\"]);\nexport type ProductStatus = z.infer<typeof ProductStatusSchema>;\n\n/**\n * Verwijdert top-level `null`-velden uit een productdoc vóór validatie (7.17.1).\n *\n * Er liggen productdocs met `personalization: null` (e.d.) in Firestore: de functions-SDK\n * encodeerde een client-side `undefined` als `null` over de draad (dezelfde klasse als de\n * \"+ Nieuw product\"-bug), en de callable schreef dat door. `z.optional()` accepteert een\n * ONTBREKEND veld maar geen `null`, en `parseProduct` op de leeskant slaat een ongeldig doc\n * stil over — waardoor een product dat gewoon \"actief\" in het beheer staat van de live winkel\n * verdween (gemeten op christelijkkraamcadeau: 2 van de 4 \"Maak een vrolijk geluid\"-varianten,\n * precies de twee die vóór de 7.16.2-fix nog eens waren opgeslagen). In dit model betekent\n * `null` nergens iets anders dan \"afwezig\", dus strippen is verliesvrij.\n */\nexport function saneerProductDoc<T>(data: T): T {\n if (typeof data !== \"object\" || data === null || Array.isArray(data)) return data;\n return Object.fromEntries(\n Object.entries(data as Record<string, unknown>).filter(([, v]) => v !== null),\n ) as T;\n}\n\nexport const ProductSchema = z.object({\n name: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n slug: z.string().check(z.minLength(1)).check(z.maxLength(120)).check(z.regex(/^[a-z0-9-]+$/, \"slug: alleen kleine letters, cijfers en streepjes\")),\n /**\n * Beschrijving als platte tekst (regeleinden blijven behouden). Bewust géén HTML:\n * producten worden client-side door editors geschreven (rules-pad, niet via de\n * publish-sanitizer), dus HTML zou hier een XSS-route zijn.\n */\n description: z._default(z.string().check(z.maxLength(20_000)), \"\"),\n categoryIds: z._default(z.array(z.string().check(z.maxLength(80))).check(z.maxLength(20)), []),\n /** Afbeeldings-URL's (via de mediabibliotheek). Eerste = hoofdbeeld. */\n images: z._default(z.array(z.string().check(z.maxLength(2000))).check(z.maxLength(12)), []),\n /** Prijs incl. btw, in centen. */\n priceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n /** Doorgestreepte \"van\"-prijs (optioneel). */\n compareAtCents: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00))),\n /** Btw-tarief (NL): 21, 9 of 0. Prijzen zijn inclusief. */\n vatRate: z._default(z.union([z.literal(21), z.literal(9), z.literal(0)]), 21),\n options: z._default(z.array(ProductOptionSchema).check(z.maxLength(3)), []),\n variants: z._default(z.array(ProductVariantSchema).check(z.maxLength(200)), []),\n /** Voorraad bijhouden? false = altijd bestelbaar (op-maat/print-on-demand). */\n trackStock: z._default(z.boolean(), false),\n /** Voorraad voor producten zónder varianten (met varianten telt de variant-stock). */\n stock: z.optional(z.int().check(z.minimum(0)).check(z.maximum(1_000_000))),\n status: z._default(ProductStatusSchema, \"draft\"),\n /** Sorteervolgorde binnen een categorie (laag = eerst). */\n order: z._default(z.int().check(z.minimum(0)).check(z.maximum(9999)), 0),\n featured: z._default(z.boolean(), false),\n /** 5.6: personalisatie-velden (eigen naam/logo) — max 3 per product. */\n personalization: z.optional(z.array(PersonalizationFieldSchema).check(z.maxLength(3))),\n /**\n * Staat \"persoonlijk maken\" aan voor dit product? (7.19)\n *\n * Voorheen was dit impliciet: velden aanwezig = aan. Wie het tijdelijk wilde uitzetten (te\n * druk, vakantie, leverancier levert de bedrukking niet) moest de velden VERWIJDEREN en dus\n * ook zijn labels, meerprijzen en uitleg kwijtraken. Nu blijft de configuratie staan en gaat\n * alleen de functie uit. Default true zodat bestaande producten met velden niets merken.\n */\n personalizationEnabled: z._default(z.boolean(), true),\n});\nexport type Product = z.infer<typeof ProductSchema>;\n\n/* ── Kortingscodes ───────────────────────────────────────────────────────── */\n\n/** `sites/{siteId}/discountCodes/{CODE}` (doc-id = code in hoofdletters; editor beheert). */\nexport const DiscountCodeSchema = z.object({\n code: z.string().check(z.minLength(3)).check(z.maxLength(30)).check(z.regex(/^[A-Z0-9-]+$/, \"code: hoofdletters, cijfers en streepjes\")),\n type: z.enum([\"percent\", \"fixed\"]),\n /** percent: 1–100; fixed: bedrag in centen. */\n value: z.int().check(z.minimum(1)).check(z.maximum(1_000_000_00)),\n minOrderCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n freeShipping: z._default(z.boolean(), false),\n active: z._default(z.boolean(), true),\n /** ISO-datums (yyyy-mm-dd); leeg = geen grens. */\n startsAt: z.optional(z.string().check(z.maxLength(10))),\n endsAt: z.optional(z.string().check(z.maxLength(10))),\n /** 0 = onbeperkt. `usedCount` wordt door de webhook transactioneel opgehoogd. */\n maxUses: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000)), 0),\n usedCount: z._default(z.int().check(z.minimum(0)), 0),\n /**\n * Eén keer per e-mailadres (7.18) — de klassieke welkomstkorting. De server telt de eerder\n * BETAALDE orders van dat adres met deze code; een afgebroken checkout brandt hem dus niet op.\n */\n oncePerCustomer: z._default(z.boolean(), false),\n});\nexport type DiscountCode = z.infer<typeof DiscountCodeSchema>;\n\n/* ── Mail-templates ──────────────────────────────────────────────────────── */\n\n// Mailtemplates zijn site-breed (ook zonder shop) — de canonieke definitie staat in `./mail`.\n// Hier her-geëxporteerd voor backward-compat van bestaande shop-importeurs.\nexport {\n MAIL_TEMPLATE_KEYS,\n MAIL_TEMPLATE_DEFS,\n MailTemplateSchema,\n MailTemplatesSchema,\n type MailTemplateKey,\n type MailTemplates,\n} from \"./mail\";\n\n/* ── Bestellingen ────────────────────────────────────────────────────────── */\n\nexport const OrderStatusSchema = z.enum([\"pending\", \"paid\", \"shipped\", \"cancelled\", \"refunded\"]);\nexport type OrderStatus = z.infer<typeof OrderStatusSchema>;\n\n/** Orderregel: snapshot van naam/prijs op besteldatum — blijft kloppen als het product wijzigt. */\nexport const OrderItemSchema = z.object({\n kind: z._default(z.enum([\"product\", \"donation\", \"giftwrap\"]), \"product\"),\n productId: z.optional(z.string().check(z.maxLength(80))),\n name: z.string().check(z.minLength(1)).check(z.maxLength(240)),\n variantKey: z.optional(z.string().check(z.maxLength(200))),\n qty: z.int().check(z.minimum(1)).check(z.maximum(999)),\n /** Incl. eventuele personalisatie-meerprijs. */\n unitPriceCents: z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)),\n vatRate: z._default(z.union([z.literal(21), z.literal(9), z.literal(0)]), 21),\n /** 5.6: ingevulde personalisatie (\"Naam: Boaz\", upload-pad). */\n personalization: z.optional(PersonalizationValueSchema),\n /**\n * 7.18: het deel van `unitPriceCents` dat personalisatie-meerprijs is.\n *\n * De meerprijs werkte al end-to-end, maar zat onzichtbaar in de stukprijs: een klant die\n * € 16,95 betaalde voor een product van € 13,95 zag nergens waar die € 3,00 vandaan kwam.\n * Apart opslaan (i.p.v. bij het tonen terugrekenen) houdt de historie kloppend als de\n * meerprijs van het product later verandert.\n */\n personalizationCents: z._default(z.int().check(z.minimum(0)), 0),\n /**\n * 7.22: de categorie waarin dit product verkocht is.\n *\n * Bij een winkel als Christelijk Kraamcadeau is `name` alleen het ontwerp (\"Blij blij\") en zegt\n * de categorie wát het is: rompertje, slabbetje, korte- of lange-mouw t-shirt. Hetzelfde ontwerp\n * bestaat in vijf categorieën, dus zonder dit veld staat er vier keer een identieke regel op de\n * pakbon, de factuur en in de bevestigingsmail — en weet niemand wat er de deur uit moet.\n *\n * Meegeschreven als momentopname, net als `name` en `unitPriceCents`: hernoem je later een\n * categorie, dan blijft een oude bestelling zeggen wat er destijds verkocht is.\n */\n categoryName: z.optional(z.string().check(z.maxLength(120))),\n});\nexport type OrderItem = z.infer<typeof OrderItemSchema>;\n\n/** \"Blij blij — Slabbetje\": de productnaam plus de categorie waarin hij verkocht is. */\nexport function orderRegelNaam(item: { name: string; categoryName?: string }): string {\n return item.categoryName ? `${item.name} — ${item.categoryName}` : item.name;\n}\n\nexport const OrderAddressSchema = z.object({\n address: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n zip: z.string().check(z.minLength(1)).check(z.maxLength(20)),\n city: z.string().check(z.minLength(1)).check(z.maxLength(120)),\n country: z._default(z.string().check(z.minLength(2)).check(z.maxLength(2)), \"NL\"),\n});\nexport type OrderAddress = z.infer<typeof OrderAddressSchema>;\n\nexport const OrderCustomerSchema = z.object({\n email: z.email().check(z.maxLength(200)),\n name: z.string().check(z.minLength(1)).check(z.maxLength(200)),\n phone: z.optional(z.string().check(z.maxLength(40))),\n});\nexport type OrderCustomer = z.infer<typeof OrderCustomerSchema>;\n\n/** Volledige order zoals door Functions geschreven (timestamps komen daarbovenop). */\nexport const OrderSchema = z.object({\n number: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n status: OrderStatusSchema,\n items: z.array(OrderItemSchema).check(z.minLength(1)).check(z.maxLength(50)),\n amount: z.object({\n itemsCents: z.int().check(z.minimum(0)),\n shippingCents: z.int().check(z.minimum(0)),\n /** 5.6: toegepaste korting (0 = geen). */\n discountCents: z._default(z.int().check(z.minimum(0)), 0),\n totalCents: z.int().check(z.minimum(0)),\n /**\n * 7.18: btw-bedrag in de order zelf. Werd eerder alleen op de factuur en in de CSV-export\n * afgeleid — twee losse kopieën van dezelfde som, terwijl dit voor de aangifte hét getal is.\n */\n vatCents: z.optional(z.int().check(z.minimum(0))),\n /** Btw per tarief (\"21\" → centen), voor de aangifte per categorie. */\n vatByRate: z.optional(z.record(z.string(), z.int())),\n }),\n /** 5.6: toegepaste kortingscode (snapshot). */\n discount: z.optional(z.object({\n code: z.string().check(z.maxLength(30)),\n type: z.enum([\"percent\", \"fixed\"]),\n value: z.int(),\n freeShipping: z._default(z.boolean(), false),\n })),\n customer: OrderCustomerSchema,\n shipping: z.optional(OrderAddressSchema),\n /**\n * 7.27: factuuradres, alleen aanwezig als het AFWIJKT van het verzendadres — afwezig betekent\n * \"hetzelfde als hierboven\" (bestaande orders blijven zo correct zonder migratie).\n */\n billing: z.optional(OrderAddressSchema),\n note: z.optional(z.string().check(z.maxLength(2000))),\n /** 7.18: interne notitie van de winkelier — de klant ziet hem nooit. */\n adminNote: z.optional(z.string().check(z.maxLength(2000))),\n /**\n * 7.27: cadeauverpakking. De MEERPRIJS staat als eigen orderregel (kind \"giftwrap\") — dat hoeft\n * dan nergens apart herrekend/getoond te worden (btw, factuur, Stripe/Mollie-regels werken al\n * generiek over `items`). Dit veld draagt alleen de klant-tekst: wat op het kaartje moet staan\n * en een eventuele opmerking voor het inpakken.\n */\n giftWrap: z.optional(z.object({\n cardText: z.optional(z.string().check(z.maxLength(300))),\n note: z.optional(z.string().check(z.maxLength(500))),\n })),\n /** 7.18: doorlopend factuurnummer (eigen reeks, zonder gaten) — pas gezet bij betaling. */\n invoiceNumber: z.optional(z.string().check(z.maxLength(40))),\n /** 7.18: handmatig aangemaakt in /beheer (telefonisch, markt, overschrijving). */\n manual: z.optional(z.boolean()),\n /** 7.18: som van alle (gedeeltelijke) terugbetalingen in centen. */\n refundedCents: z.optional(z.int().check(z.minimum(0))),\n /**\n * 7.18: berichten die naar de klant zijn gestuurd — handmatig vanuit /beheer, en sinds 7.25\n * ook automatisch (bevestiging, verzonden, geannuleerd, terugbetaald, betaalverzoek). Zonder\n * dat spoor was er geen manier om te zien of een klant-mail is aangekomen of dat de order\n * stilletjes zonder bericht is geannuleerd.\n */\n messages: z.optional(z.array(z.object({\n at: z.string().check(z.maxLength(40)),\n /** uid van de medewerker, of \"systeem\" bij een automatische mail. */\n by: z.optional(z.string().check(z.maxLength(200))),\n subject: z.string().check(z.maxLength(200)),\n body: z.string().check(z.maxLength(2000)),\n /** 7.25: automatisch verstuurd (order-gebeurtenis) i.p.v. handmatig getypt. */\n automatisch: z.optional(z.boolean()),\n /** 7.25: het versturen is mislukt — blijft zichtbaar i.p.v. stil te verdwijnen. */\n mislukt: z.optional(z.boolean()),\n })).check(z.maxLength(50))),\n /** 5.6: track & trace-link (gezet bij \"verzonden\"). */\n trackingUrl: z.optional(z.string().check(z.maxLength(500))),\n /** 5.6: factuur-pad in Storage (gezet door de webhook). */\n invoicePath: z.optional(z.string().check(z.maxLength(400))),\n stripe: z._default(z.object({\n sessionId: z.optional(z.string().check(z.maxLength(200))),\n paymentIntentId: z.optional(z.string().check(z.maxLength(200))),\n }), {}),\n});\nexport type Order = z.infer<typeof OrderSchema>;\n\n/* ── Callable-input (checkout) ───────────────────────────────────────────── */\n\n/**\n * Input van de `createOrder`-callable. Client-prijzen worden NOOIT vertrouwd: de functie\n * herrekent alles tegen de opgeslagen product-docs. Alleen `donationCents` komt van de\n * client (binnen de per-site ingestelde min/max van het donatie-block).\n */\nexport const CreateOrderItemInputSchema = z.object({\n productId: z.optional(z.string().check(z.minLength(1)).check(z.maxLength(80))),\n variantKey: z.optional(z.string().check(z.maxLength(200))),\n qty: z._default(z.int().check(z.minimum(1)).check(z.maximum(999)), 1),\n /** Alleen voor donaties (zonder productId). */\n donationCents: z.optional(z.int().check(z.minimum(50)).check(z.maximum(1_000_000_00))),\n /** 5.6: personalisatie-invoer (gevalideerd tegen product.personalization). */\n personalization: z.optional(PersonalizationValueSchema),\n});\n\nexport const CreateOrderInputSchema = z.object({\n siteId: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n items: z.array(CreateOrderItemInputSchema).check(z.minLength(1)).check(z.maxLength(50)),\n customer: OrderCustomerSchema,\n shipping: z.optional(OrderAddressSchema),\n /** 7.27: alleen meesturen als het factuuradres afwijkt van het verzendadres. */\n billing: z.optional(OrderAddressSchema),\n note: z.optional(z.string().check(z.maxLength(2000))),\n /** 7.27: aanwezig = klant wil cadeauverpakking (mag met lege tekstvelden). Prijs/aan-uit komt server-side uit de shopconfig. */\n giftWrap: z.optional(z.object({\n cardText: z.optional(z.string().check(z.maxLength(300))),\n note: z.optional(z.string().check(z.maxLength(500))),\n })),\n /** 5.6: kortingscode (server-side gevalideerd en verrekend). */\n discountCode: z.optional(z.string().check(z.maxLength(30))),\n /** Paden op de klantsite waarheen Stripe terug redirect. */\n successPath: z._default(z.string().check(z.maxLength(400)), \"/bedankt\"),\n cancelPath: z._default(z.string().check(z.maxLength(400)), \"/winkelwagen\"),\n /** Honeypot — moet leeg zijn (bot-detectie). */\n _hp: z.optional(z.string().check(z.maxLength(0))),\n});\nexport type CreateOrderInput = z.infer<typeof CreateOrderInputSchema>;\n\n/* ── Block-schema's ──────────────────────────────────────────────────────── */\n\nexport const ShopCategoriesBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"shopCategories\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n columns: z._default(z.int().check(z.minimum(2)).check(z.maximum(4)), 3),\n});\n\nexport const ProductGridBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"productGrid\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n /** Vast categorie-filter (slug). Leeg + useQueryCategory → filter via `?cat=` in de URL. */\n categorySlug: z.optional(z.string().check(z.maxLength(120))),\n useQueryCategory: z._default(z.boolean(), true),\n featuredOnly: z._default(z.boolean(), false),\n columns: z._default(z.int().check(z.minimum(2)).check(z.maximum(4)), 3),\n limit: z._default(z.int().check(z.minimum(1)).check(z.maximum(200)), 60),\n sort: z._default(z.enum([\"order\", \"name\", \"priceAsc\", \"priceDesc\"]), \"order\"),\n /** 5.6: filterchips (kleur/maat) + sorteerkeuze boven het grid. */\n showFilters: z._default(z.boolean(), false),\n});\n\nexport const ProductDetailBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"productDetail\"),\n /** Vast product (slug); leeg → product uit `?p=` in de URL (één generieke detailpagina). */\n slug: z.optional(z.string().check(z.maxLength(120))),\n /** 5.6: \"Ook leuk\"-rij met producten uit dezelfde categorie. */\n showRelated: z._default(z.boolean(), true),\n});\n\nexport const CartBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"cart\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n});\n\nexport const CheckoutBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"checkout\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n introText: z.optional(z.string().check(z.maxLength(2000))),\n});\n\nexport const DonationBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"donation\"),\n heading: z.optional(z.string().check(z.maxLength(200))),\n introText: z.optional(z.string().check(z.maxLength(2000))),\n /** Voorgestelde bedragen in centen. */\n amountsCents: z._default(z.array(z.int().check(z.minimum(50)).check(z.maximum(1_000_000_00))).check(z.maxLength(8)), [500, 1000, 2500]),\n allowCustom: z._default(z.boolean(), true),\n customMinCents: z._default(z.int().check(z.minimum(50)), 100),\n customMaxCents: z._default(z.int().check(z.maximum(1_000_000_00)), 100_000),\n buttonLabel: z._default(z.string().check(z.maxLength(80)), \"Doneer\"),\n});\n\nexport const OrderStatusBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"orderStatus\"),\n successTitle: z._default(z.string().check(z.maxLength(200)), \"Bedankt voor je bestelling!\"),\n successText: z._default(z.string().check(z.maxLength(2000)), \"Je ontvangt zo een bevestiging per e-mail.\"),\n cancelledTitle: z._default(z.string().check(z.maxLength(200)), \"Betaling niet afgerond\"),\n cancelledText: z._default(z.string().check(z.maxLength(2000)), \"Je bestelling is niet betaald. Probeer het gerust opnieuw.\"),\n});\n\n/* ── Helpers (gedeeld client/server) ─────────────────────────────────────── */\n\nexport { variantKeyFor, productPriceCents, shippingCentsFor, formatCents } from \"./shopGeld\";\n"],"mappings":"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","names":[]}
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
- const CORE_VERSION = true ? "7.26.0" : "0.0.0-dev";
1
+ const CORE_VERSION = true ? "7.28.0" : "0.0.0-dev";
2
2
  const CORE_PACKAGE = "@xiwebdesign/xicms-core";
3
3
  function isNieuwer(beschikbaar, huidig) {
4
4
  const delen = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiwebdesign/xicms-core",
3
- "version": "7.26.0",
3
+ "version": "7.28.0",
4
4
  "description": "XiCMS engine: gestructureerde content, pagina's, draft/publish, admin (TipTap+Radix), SEO en beveiliging voor klantsites.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {