@xiwebdesign/xicms-core 5.4.0 → 5.5.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.
Files changed (67) hide show
  1. package/dist/admin/panelRegistry.js +3 -0
  2. package/dist/admin/panelRegistry.js.map +1 -1
  3. package/dist/admin/shop/CategoriesTab.d.ts +3 -0
  4. package/dist/admin/shop/CategoriesTab.js +140 -0
  5. package/dist/admin/shop/CategoriesTab.js.map +1 -0
  6. package/dist/admin/shop/ConnectionsTab.d.ts +9 -0
  7. package/dist/admin/shop/ConnectionsTab.js +158 -0
  8. package/dist/admin/shop/ConnectionsTab.js.map +1 -0
  9. package/dist/admin/shop/OrdersTab.d.ts +3 -0
  10. package/dist/admin/shop/OrdersTab.js +236 -0
  11. package/dist/admin/shop/OrdersTab.js.map +1 -0
  12. package/dist/admin/shop/ProductsTab.d.ts +3 -0
  13. package/dist/admin/shop/ProductsTab.js +397 -0
  14. package/dist/admin/shop/ProductsTab.js.map +1 -0
  15. package/dist/admin/shop/ShopPanel.d.ts +4 -0
  16. package/dist/admin/shop/ShopPanel.js +25 -0
  17. package/dist/admin/shop/ShopPanel.js.map +1 -0
  18. package/dist/admin/shop/lib.d.ts +16 -0
  19. package/dist/admin/shop/lib.js +46 -0
  20. package/dist/admin/shop/lib.js.map +1 -0
  21. package/dist/admin.css +1 -1
  22. package/dist/modules/builtins.d.ts +1 -0
  23. package/dist/modules/builtins.js +4 -0
  24. package/dist/modules/builtins.js.map +1 -1
  25. package/dist/modules/index.d.ts +4 -0
  26. package/dist/modules/index.js +12 -0
  27. package/dist/modules/index.js.map +1 -1
  28. package/dist/modules/shop/blocks/Cart.d.ts +2 -0
  29. package/dist/modules/shop/blocks/Cart.js +91 -0
  30. package/dist/modules/shop/blocks/Cart.js.map +1 -0
  31. package/dist/modules/shop/blocks/Checkout.d.ts +2 -0
  32. package/dist/modules/shop/blocks/Checkout.js +126 -0
  33. package/dist/modules/shop/blocks/Checkout.js.map +1 -0
  34. package/dist/modules/shop/blocks/Donation.d.ts +2 -0
  35. package/dist/modules/shop/blocks/Donation.js +145 -0
  36. package/dist/modules/shop/blocks/Donation.js.map +1 -0
  37. package/dist/modules/shop/blocks/OrderStatus.d.ts +2 -0
  38. package/dist/modules/shop/blocks/OrderStatus.js +40 -0
  39. package/dist/modules/shop/blocks/OrderStatus.js.map +1 -0
  40. package/dist/modules/shop/blocks/ProductDetail.d.ts +2 -0
  41. package/dist/modules/shop/blocks/ProductDetail.js +168 -0
  42. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -0
  43. package/dist/modules/shop/blocks/ProductGrid.d.ts +8 -0
  44. package/dist/modules/shop/blocks/ProductGrid.js +136 -0
  45. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -0
  46. package/dist/modules/shop/blocks/ShopCategories.d.ts +2 -0
  47. package/dist/modules/shop/blocks/ShopCategories.js +69 -0
  48. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -0
  49. package/dist/modules/shop/cartStore.d.ts +22 -0
  50. package/dist/modules/shop/cartStore.js +85 -0
  51. package/dist/modules/shop/cartStore.js.map +1 -0
  52. package/dist/modules/shop/lib.d.ts +25 -0
  53. package/dist/modules/shop/lib.js +61 -0
  54. package/dist/modules/shop/lib.js.map +1 -0
  55. package/dist/modules/shop/module.d.ts +1 -0
  56. package/dist/modules/shop/module.js +39 -0
  57. package/dist/modules/shop/module.js.map +1 -0
  58. package/dist/modules/shop/settings.d.ts +41 -0
  59. package/dist/modules/shop/settings.js +18 -0
  60. package/dist/modules/shop/settings.js.map +1 -0
  61. package/dist/schema/index.d.ts +1 -0
  62. package/dist/schema/index.js +1 -0
  63. package/dist/schema/index.js.map +1 -1
  64. package/dist/schema/shop.d.ts +939 -0
  65. package/dist/schema/shop.js +209 -0
  66. package/dist/schema/shop.js.map +1 -0
  67. package/package.json +1 -1
@@ -0,0 +1,209 @@
1
+ import { z } from "zod";
2
+ import { blockBase } from "./blocks";
3
+ const ShopCategorySchema = z.object({
4
+ name: z.string().min(1).max(120),
5
+ slug: z.string().min(1).max(120).regex(/^[a-z0-9-]+$/, "slug: alleen kleine letters, cijfers en streepjes"),
6
+ description: z.string().max(2e3).optional(),
7
+ imageUrl: z.string().max(2e3).optional(),
8
+ order: z.number().int().min(0).max(9999).default(0),
9
+ visible: z.boolean().default(true)
10
+ });
11
+ const ProductOptionSchema = z.object({
12
+ name: z.string().min(1).max(40),
13
+ values: z.array(z.string().min(1).max(60)).min(1).max(30)
14
+ });
15
+ const ProductVariantSchema = z.object({
16
+ key: z.string().min(1).max(200),
17
+ priceCents: z.number().int().min(0).max(1e8).optional(),
18
+ stock: z.number().int().min(0).max(1e6).optional(),
19
+ sku: z.string().max(60).optional(),
20
+ active: z.boolean().default(true)
21
+ });
22
+ const ProductStatusSchema = z.enum(["draft", "active", "archived"]);
23
+ const ProductSchema = z.object({
24
+ name: z.string().min(1).max(200),
25
+ slug: z.string().min(1).max(120).regex(/^[a-z0-9-]+$/, "slug: alleen kleine letters, cijfers en streepjes"),
26
+ /**
27
+ * Beschrijving als platte tekst (regeleinden blijven behouden). Bewust géén HTML:
28
+ * producten worden client-side door editors geschreven (rules-pad, niet via de
29
+ * publish-sanitizer), dus HTML zou hier een XSS-route zijn.
30
+ */
31
+ description: z.string().max(2e4).default(""),
32
+ categoryIds: z.array(z.string().max(80)).max(20).default([]),
33
+ /** Afbeeldings-URL's (via de mediabibliotheek). Eerste = hoofdbeeld. */
34
+ images: z.array(z.string().max(2e3)).max(12).default([]),
35
+ /** Prijs incl. btw, in centen. */
36
+ priceCents: z.number().int().min(0).max(1e8).default(0),
37
+ /** Doorgestreepte "van"-prijs (optioneel). */
38
+ compareAtCents: z.number().int().min(0).max(1e8).optional(),
39
+ /** Btw-tarief (NL): 21, 9 of 0. Prijzen zijn inclusief. */
40
+ vatRate: z.union([z.literal(21), z.literal(9), z.literal(0)]).default(21),
41
+ options: z.array(ProductOptionSchema).max(3).default([]),
42
+ variants: z.array(ProductVariantSchema).max(200).default([]),
43
+ /** Voorraad bijhouden? false = altijd bestelbaar (op-maat/print-on-demand). */
44
+ trackStock: z.boolean().default(false),
45
+ /** Voorraad voor producten zónder varianten (met varianten telt de variant-stock). */
46
+ stock: z.number().int().min(0).max(1e6).optional(),
47
+ status: ProductStatusSchema.default("draft"),
48
+ /** Sorteervolgorde binnen een categorie (laag = eerst). */
49
+ order: z.number().int().min(0).max(9999).default(0),
50
+ featured: z.boolean().default(false)
51
+ });
52
+ const OrderStatusSchema = z.enum(["pending", "paid", "shipped", "cancelled", "refunded"]);
53
+ const OrderItemSchema = z.object({
54
+ kind: z.enum(["product", "donation"]).default("product"),
55
+ productId: z.string().max(80).optional(),
56
+ name: z.string().min(1).max(240),
57
+ variantKey: z.string().max(200).optional(),
58
+ qty: z.number().int().min(1).max(999),
59
+ unitPriceCents: z.number().int().min(0).max(1e8),
60
+ vatRate: z.union([z.literal(21), z.literal(9), z.literal(0)]).default(21)
61
+ });
62
+ const OrderAddressSchema = z.object({
63
+ address: z.string().min(1).max(200),
64
+ zip: z.string().min(1).max(20),
65
+ city: z.string().min(1).max(120),
66
+ country: z.string().min(2).max(2).default("NL")
67
+ });
68
+ const OrderCustomerSchema = z.object({
69
+ email: z.string().email().max(200),
70
+ name: z.string().min(1).max(200),
71
+ phone: z.string().max(40).optional()
72
+ });
73
+ const OrderSchema = z.object({
74
+ number: z.string().min(1).max(40),
75
+ status: OrderStatusSchema,
76
+ items: z.array(OrderItemSchema).min(1).max(50),
77
+ amount: z.object({
78
+ itemsCents: z.number().int().min(0),
79
+ shippingCents: z.number().int().min(0),
80
+ totalCents: z.number().int().min(0)
81
+ }),
82
+ customer: OrderCustomerSchema,
83
+ shipping: OrderAddressSchema.optional(),
84
+ note: z.string().max(2e3).optional(),
85
+ stripe: z.object({
86
+ sessionId: z.string().max(200).optional(),
87
+ paymentIntentId: z.string().max(200).optional()
88
+ }).default({})
89
+ });
90
+ const CreateOrderItemInputSchema = z.object({
91
+ productId: z.string().min(1).max(80).optional(),
92
+ variantKey: z.string().max(200).optional(),
93
+ qty: z.number().int().min(1).max(999).default(1),
94
+ /** Alleen voor donaties (zonder productId). */
95
+ donationCents: z.number().int().min(50).max(1e8).optional()
96
+ });
97
+ const CreateOrderInputSchema = z.object({
98
+ siteId: z.string().min(1).max(80),
99
+ items: z.array(CreateOrderItemInputSchema).min(1).max(50),
100
+ customer: OrderCustomerSchema,
101
+ shipping: OrderAddressSchema.optional(),
102
+ note: z.string().max(2e3).optional(),
103
+ /** Paden op de klantsite waarheen Stripe terug redirect. */
104
+ successPath: z.string().max(400).default("/bedankt"),
105
+ cancelPath: z.string().max(400).default("/winkelwagen"),
106
+ /** Honeypot — moet leeg zijn (bot-detectie). */
107
+ _hp: z.string().max(0).optional()
108
+ });
109
+ const ShopCategoriesBlockSchema = z.object({
110
+ ...blockBase,
111
+ _type: z.literal("shopCategories"),
112
+ heading: z.string().max(200).optional(),
113
+ columns: z.number().int().min(2).max(4).default(3)
114
+ });
115
+ const ProductGridBlockSchema = z.object({
116
+ ...blockBase,
117
+ _type: z.literal("productGrid"),
118
+ heading: z.string().max(200).optional(),
119
+ /** Vast categorie-filter (slug). Leeg + useQueryCategory → filter via `?cat=` in de URL. */
120
+ categorySlug: z.string().max(120).optional(),
121
+ useQueryCategory: z.boolean().default(true),
122
+ featuredOnly: z.boolean().default(false),
123
+ columns: z.number().int().min(2).max(4).default(3),
124
+ limit: z.number().int().min(1).max(200).default(60),
125
+ sort: z.enum(["order", "name", "priceAsc", "priceDesc"]).default("order")
126
+ });
127
+ const ProductDetailBlockSchema = z.object({
128
+ ...blockBase,
129
+ _type: z.literal("productDetail"),
130
+ /** Vast product (slug); leeg → product uit `?p=` in de URL (één generieke detailpagina). */
131
+ slug: z.string().max(120).optional()
132
+ });
133
+ const CartBlockSchema = z.object({
134
+ ...blockBase,
135
+ _type: z.literal("cart"),
136
+ heading: z.string().max(200).optional()
137
+ });
138
+ const CheckoutBlockSchema = z.object({
139
+ ...blockBase,
140
+ _type: z.literal("checkout"),
141
+ heading: z.string().max(200).optional(),
142
+ introText: z.string().max(2e3).optional()
143
+ });
144
+ const DonationBlockSchema = z.object({
145
+ ...blockBase,
146
+ _type: z.literal("donation"),
147
+ heading: z.string().max(200).optional(),
148
+ introText: z.string().max(2e3).optional(),
149
+ /** Voorgestelde bedragen in centen. */
150
+ amountsCents: z.array(z.number().int().min(50).max(1e8)).max(8).default([500, 1e3, 2500]),
151
+ allowCustom: z.boolean().default(true),
152
+ customMinCents: z.number().int().min(50).default(100),
153
+ customMaxCents: z.number().int().max(1e8).default(1e5),
154
+ buttonLabel: z.string().max(80).default("Doneer")
155
+ });
156
+ const OrderStatusBlockSchema = z.object({
157
+ ...blockBase,
158
+ _type: z.literal("orderStatus"),
159
+ successTitle: z.string().max(200).default("Bedankt voor je bestelling!"),
160
+ successText: z.string().max(2e3).default("Je ontvangt zo een bevestiging per e-mail."),
161
+ cancelledTitle: z.string().max(200).default("Betaling niet afgerond"),
162
+ cancelledText: z.string().max(2e3).default("Je bestelling is niet betaald. Probeer het gerust opnieuw.")
163
+ });
164
+ function variantKeyFor(values) {
165
+ return values.join("|");
166
+ }
167
+ function productPriceCents(product, variantKey) {
168
+ if (variantKey) {
169
+ const v = product.variants?.find((x) => x.key === variantKey);
170
+ if (v?.priceCents !== void 0) return v.priceCents;
171
+ }
172
+ return product.priceCents;
173
+ }
174
+ function shippingCentsFor(itemsCents, cfg, hasShippableItems) {
175
+ if (!hasShippableItems) return 0;
176
+ const flat = cfg.shippingFlatCents ?? 0;
177
+ const freeFrom = cfg.shippingFreeFromCents;
178
+ if (freeFrom !== void 0 && freeFrom > 0 && itemsCents >= freeFrom) return 0;
179
+ return flat;
180
+ }
181
+ function formatCents(cents, currency = "EUR") {
182
+ return new Intl.NumberFormat("nl-NL", { style: "currency", currency }).format(cents / 100);
183
+ }
184
+ export {
185
+ CartBlockSchema,
186
+ CheckoutBlockSchema,
187
+ CreateOrderInputSchema,
188
+ CreateOrderItemInputSchema,
189
+ DonationBlockSchema,
190
+ OrderAddressSchema,
191
+ OrderCustomerSchema,
192
+ OrderItemSchema,
193
+ OrderSchema,
194
+ OrderStatusBlockSchema,
195
+ OrderStatusSchema,
196
+ ProductDetailBlockSchema,
197
+ ProductGridBlockSchema,
198
+ ProductOptionSchema,
199
+ ProductSchema,
200
+ ProductStatusSchema,
201
+ ProductVariantSchema,
202
+ ShopCategoriesBlockSchema,
203
+ ShopCategorySchema,
204
+ formatCents,
205
+ productPriceCents,
206
+ shippingCentsFor,
207
+ variantKeyFor
208
+ };
209
+ //# sourceMappingURL=shop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/schema/shop.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { blockBase } from \"./blocks\";\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().min(1).max(120),\n slug: z\n .string()\n .min(1)\n .max(120)\n .regex(/^[a-z0-9-]+$/, \"slug: alleen kleine letters, cijfers en streepjes\"),\n description: z.string().max(2000).optional(),\n imageUrl: z.string().max(2000).optional(),\n order: z.number().int().min(0).max(9999).default(0),\n visible: z.boolean().default(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().min(1).max(40),\n values: z.array(z.string().min(1).max(60)).min(1).max(30),\n});\nexport type ProductOption = z.infer<typeof ProductOptionSchema>;\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().min(1).max(200),\n priceCents: z.number().int().min(0).max(1_000_000_00).optional(),\n stock: z.number().int().min(0).max(1_000_000).optional(),\n sku: z.string().max(60).optional(),\n active: z.boolean().default(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\nexport const ProductSchema = z.object({\n name: z.string().min(1).max(200),\n slug: z\n .string()\n .min(1)\n .max(120)\n .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.string().max(20_000).default(\"\"),\n categoryIds: z.array(z.string().max(80)).max(20).default([]),\n /** Afbeeldings-URL's (via de mediabibliotheek). Eerste = hoofdbeeld. */\n images: z.array(z.string().max(2000)).max(12).default([]),\n /** Prijs incl. btw, in centen. */\n priceCents: z.number().int().min(0).max(1_000_000_00).default(0),\n /** Doorgestreepte \"van\"-prijs (optioneel). */\n compareAtCents: z.number().int().min(0).max(1_000_000_00).optional(),\n /** Btw-tarief (NL): 21, 9 of 0. Prijzen zijn inclusief. */\n vatRate: z.union([z.literal(21), z.literal(9), z.literal(0)]).default(21),\n options: z.array(ProductOptionSchema).max(3).default([]),\n variants: z.array(ProductVariantSchema).max(200).default([]),\n /** Voorraad bijhouden? false = altijd bestelbaar (op-maat/print-on-demand). */\n trackStock: z.boolean().default(false),\n /** Voorraad voor producten zónder varianten (met varianten telt de variant-stock). */\n stock: z.number().int().min(0).max(1_000_000).optional(),\n status: ProductStatusSchema.default(\"draft\"),\n /** Sorteervolgorde binnen een categorie (laag = eerst). */\n order: z.number().int().min(0).max(9999).default(0),\n featured: z.boolean().default(false),\n});\nexport type Product = z.infer<typeof ProductSchema>;\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.enum([\"product\", \"donation\"]).default(\"product\"),\n productId: z.string().max(80).optional(),\n name: z.string().min(1).max(240),\n variantKey: z.string().max(200).optional(),\n qty: z.number().int().min(1).max(999),\n unitPriceCents: z.number().int().min(0).max(1_000_000_00),\n vatRate: z.union([z.literal(21), z.literal(9), z.literal(0)]).default(21),\n});\nexport type OrderItem = z.infer<typeof OrderItemSchema>;\n\nexport const OrderAddressSchema = z.object({\n address: z.string().min(1).max(200),\n zip: z.string().min(1).max(20),\n city: z.string().min(1).max(120),\n country: z.string().min(2).max(2).default(\"NL\"),\n});\nexport type OrderAddress = z.infer<typeof OrderAddressSchema>;\n\nexport const OrderCustomerSchema = z.object({\n email: z.string().email().max(200),\n name: z.string().min(1).max(200),\n phone: z.string().max(40).optional(),\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().min(1).max(40),\n status: OrderStatusSchema,\n items: z.array(OrderItemSchema).min(1).max(50),\n amount: z.object({\n itemsCents: z.number().int().min(0),\n shippingCents: z.number().int().min(0),\n totalCents: z.number().int().min(0),\n }),\n customer: OrderCustomerSchema,\n shipping: OrderAddressSchema.optional(),\n note: z.string().max(2000).optional(),\n stripe: z\n .object({\n sessionId: z.string().max(200).optional(),\n paymentIntentId: z.string().max(200).optional(),\n })\n .default({}),\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.string().min(1).max(80).optional(),\n variantKey: z.string().max(200).optional(),\n qty: z.number().int().min(1).max(999).default(1),\n /** Alleen voor donaties (zonder productId). */\n donationCents: z.number().int().min(50).max(1_000_000_00).optional(),\n});\n\nexport const CreateOrderInputSchema = z.object({\n siteId: z.string().min(1).max(80),\n items: z.array(CreateOrderItemInputSchema).min(1).max(50),\n customer: OrderCustomerSchema,\n shipping: OrderAddressSchema.optional(),\n note: z.string().max(2000).optional(),\n /** Paden op de klantsite waarheen Stripe terug redirect. */\n successPath: z.string().max(400).default(\"/bedankt\"),\n cancelPath: z.string().max(400).default(\"/winkelwagen\"),\n /** Honeypot — moet leeg zijn (bot-detectie). */\n _hp: z.string().max(0).optional(),\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.string().max(200).optional(),\n columns: z.number().int().min(2).max(4).default(3),\n});\n\nexport const ProductGridBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"productGrid\"),\n heading: z.string().max(200).optional(),\n /** Vast categorie-filter (slug). Leeg + useQueryCategory → filter via `?cat=` in de URL. */\n categorySlug: z.string().max(120).optional(),\n useQueryCategory: z.boolean().default(true),\n featuredOnly: z.boolean().default(false),\n columns: z.number().int().min(2).max(4).default(3),\n limit: z.number().int().min(1).max(200).default(60),\n sort: z.enum([\"order\", \"name\", \"priceAsc\", \"priceDesc\"]).default(\"order\"),\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.string().max(120).optional(),\n});\n\nexport const CartBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"cart\"),\n heading: z.string().max(200).optional(),\n});\n\nexport const CheckoutBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"checkout\"),\n heading: z.string().max(200).optional(),\n introText: z.string().max(2000).optional(),\n});\n\nexport const DonationBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"donation\"),\n heading: z.string().max(200).optional(),\n introText: z.string().max(2000).optional(),\n /** Voorgestelde bedragen in centen. */\n amountsCents: z.array(z.number().int().min(50).max(1_000_000_00)).max(8).default([500, 1000, 2500]),\n allowCustom: z.boolean().default(true),\n customMinCents: z.number().int().min(50).default(100),\n customMaxCents: z.number().int().max(1_000_000_00).default(100_000),\n buttonLabel: z.string().max(80).default(\"Doneer\"),\n});\n\nexport const OrderStatusBlockSchema = z.object({\n ...blockBase,\n _type: z.literal(\"orderStatus\"),\n successTitle: z.string().max(200).default(\"Bedankt voor je bestelling!\"),\n successText: z.string().max(2000).default(\"Je ontvangt zo een bevestiging per e-mail.\"),\n cancelledTitle: z.string().max(200).default(\"Betaling niet afgerond\"),\n cancelledText: z.string().max(2000).default(\"Je bestelling is niet betaald. Probeer het gerust opnieuw.\"),\n});\n\n/* ── Helpers (gedeeld client/server) ─────────────────────────────────────── */\n\n/** Variant-key uit gekozen optiewaarden, in optie-volgorde: [\"68\",\"Roze\"] → \"68|Roze\". */\nexport function variantKeyFor(values: string[]): string {\n return values.join(\"|\");\n}\n\n/** Effectieve prijs van een product(-variant) in centen. */\nexport function productPriceCents(product: Pick<Product, \"priceCents\" | \"variants\">, variantKey?: string): number {\n if (variantKey) {\n const v = product.variants?.find((x) => x.key === variantKey);\n if (v?.priceCents !== undefined) return v.priceCents;\n }\n return product.priceCents;\n}\n\n/** Verzendkosten volgens de publieke shopconfig (flat + gratis-vanaf). Donatie-only = gratis. */\nexport function shippingCentsFor(\n itemsCents: number,\n cfg: { shippingFlatCents?: number; shippingFreeFromCents?: number },\n hasShippableItems: boolean,\n): number {\n if (!hasShippableItems) return 0;\n const flat = cfg.shippingFlatCents ?? 0;\n const freeFrom = cfg.shippingFreeFromCents;\n if (freeFrom !== undefined && freeFrom > 0 && itemsCents >= freeFrom) return 0;\n return flat;\n}\n\n/** Centen → \"€ 13,95\" (nl-NL). */\nexport function formatCents(cents: number, currency = \"EUR\"): string {\n return new Intl.NumberFormat(\"nl-NL\", { style: \"currency\", currency }).format(cents / 100);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiwebdesign/xicms-core",
3
- "version": "5.4.0",
3
+ "version": "5.5.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": {