@xiwebdesign/xicms-core 7.30.0 → 8.15.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.
- package/dist/XiCMSProvider.js +22 -7
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.js +175 -93
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +1 -1
- package/dist/admin/AdminHelp.js +44 -36
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/CoreVersion.d.ts +6 -3
- package/dist/admin/CoreVersion.js +60 -24
- package/dist/admin/CoreVersion.js.map +1 -1
- package/dist/admin/NewsEditor.d.ts +7 -0
- package/dist/admin/NewsEditor.js +117 -75
- package/dist/admin/NewsEditor.js.map +1 -1
- package/dist/admin/SuperadminPanel.js +1 -1
- package/dist/admin/SuperadminPanel.js.map +1 -1
- package/dist/admin/ZoekPalet.d.ts +15 -0
- package/dist/admin/ZoekPalet.js +123 -0
- package/dist/admin/ZoekPalet.js.map +1 -0
- package/dist/admin/blockEditors/GenericEditor.js +36 -18
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +37 -3
- package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
- package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
- package/dist/admin/blockEditors/index.js +154 -73
- package/dist/admin/blockEditors/index.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/dashboard/DashboardPanel.js +26 -16
- package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
- package/dist/admin/editors/RichTextEditor.d.ts +4 -3
- package/dist/admin/editors/RichTextEditor.js +19 -56
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +7 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/editors/slashMenu.d.ts +18 -0
- package/dist/admin/editors/slashMenu.js +34 -0
- package/dist/admin/editors/slashMenu.js.map +1 -0
- package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
- package/dist/admin/editors/useRijkeTekst.js +310 -0
- package/dist/admin/editors/useRijkeTekst.js.map +1 -0
- package/dist/admin/forms/FormsPanel.d.ts +11 -2
- package/dist/admin/forms/FormsPanel.js +218 -65
- package/dist/admin/forms/FormsPanel.js.map +1 -1
- package/dist/admin/lib/blokInfo.d.ts +17 -0
- package/dist/admin/lib/blokInfo.js +80 -0
- package/dist/admin/lib/blokInfo.js.map +1 -0
- package/dist/admin/lib/foutNaarMens.d.ts +1 -0
- package/dist/admin/lib/foutNaarMens.js +22 -0
- package/dist/admin/lib/foutNaarMens.js.map +1 -0
- package/dist/admin/lib/gewisteVelden.d.ts +13 -0
- package/dist/admin/lib/gewisteVelden.js +31 -0
- package/dist/admin/lib/gewisteVelden.js.map +1 -0
- package/dist/admin/lib/heroHulp.d.ts +11 -0
- package/dist/admin/lib/heroHulp.js +18 -0
- package/dist/admin/lib/heroHulp.js.map +1 -0
- package/dist/admin/lib/kleur.js +2 -3
- package/dist/admin/lib/kleur.js.map +1 -1
- package/dist/admin/lib/leesbaarheid.d.ts +34 -0
- package/dist/admin/lib/leesbaarheid.js +82 -0
- package/dist/admin/lib/leesbaarheid.js.map +1 -0
- package/dist/admin/lib/lengteAdvies.d.ts +1 -0
- package/dist/admin/lib/lengteAdvies.js +16 -0
- package/dist/admin/lib/lengteAdvies.js.map +1 -0
- package/dist/admin/lib/mediaLijst.d.ts +26 -0
- package/dist/admin/lib/mediaLijst.js +42 -0
- package/dist/admin/lib/mediaLijst.js.map +1 -0
- package/dist/admin/lib/mediaUsage.d.ts +12 -1
- package/dist/admin/lib/mediaUsage.js +43 -33
- package/dist/admin/lib/mediaUsage.js.map +1 -1
- package/dist/admin/lib/menuHulp.d.ts +16 -0
- package/dist/admin/lib/menuHulp.js +41 -0
- package/dist/admin/lib/menuHulp.js.map +1 -0
- package/dist/admin/lib/onopgeslagen.d.ts +10 -0
- package/dist/admin/lib/onopgeslagen.js +35 -0
- package/dist/admin/lib/onopgeslagen.js.map +1 -0
- package/dist/admin/lib/pagesClient.d.ts +55 -2
- package/dist/admin/lib/pagesClient.js +126 -28
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/paginaGebruik.d.ts +56 -0
- package/dist/admin/lib/paginaGebruik.js +109 -0
- package/dist/admin/lib/paginaGebruik.js.map +1 -0
- package/dist/admin/lib/publicatieCheck.d.ts +25 -0
- package/dist/admin/lib/publicatieCheck.js +114 -0
- package/dist/admin/lib/publicatieCheck.js.map +1 -0
- package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
- package/dist/admin/lib/scrollNaarDetail.js +20 -0
- package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +10 -0
- package/dist/admin/lib/symbolsClient.js +14 -1
- package/dist/admin/lib/symbolsClient.js.map +1 -1
- package/dist/admin/lib/tekstVeld.d.ts +8 -0
- package/dist/admin/lib/tekstVeld.js +10 -0
- package/dist/admin/lib/tekstVeld.js.map +1 -0
- package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
- package/dist/admin/lib/useIsSuperadmin.js +13 -0
- package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
- package/dist/admin/lib/veldTaal.d.ts +14 -0
- package/dist/admin/lib/veldTaal.js +247 -0
- package/dist/admin/lib/veldTaal.js.map +1 -0
- package/dist/admin/lib/versieVergelijk.d.ts +17 -0
- package/dist/admin/lib/versieVergelijk.js +24 -0
- package/dist/admin/lib/versieVergelijk.js.map +1 -0
- package/dist/admin/lib/zodFields.js +22 -4
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/lib/zodFout.d.ts +9 -0
- package/dist/admin/lib/zodFout.js +63 -0
- package/dist/admin/lib/zodFout.js.map +1 -0
- package/dist/admin/media/MediaManager.js +162 -32
- package/dist/admin/media/MediaManager.js.map +1 -1
- package/dist/admin/media/MediaPicker.d.ts +3 -0
- package/dist/admin/media/MediaPicker.js +84 -31
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/menu/MenuPanel.js +144 -83
- package/dist/admin/menu/MenuPanel.js.map +1 -1
- package/dist/admin/navContext.d.ts +3 -0
- package/dist/admin/navContext.js +13 -1
- package/dist/admin/navContext.js.map +1 -1
- package/dist/admin/pages/PageEditor.js +146 -30
- package/dist/admin/pages/PageEditor.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +215 -61
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/pages/StarterKiezer.d.ts +12 -0
- package/dist/admin/pages/StarterKiezer.js +113 -0
- package/dist/admin/pages/StarterKiezer.js.map +1 -0
- package/dist/admin/panelRegistry.d.ts +1 -1
- package/dist/admin/panelRegistry.js +2 -1
- package/dist/admin/panelRegistry.js.map +1 -1
- package/dist/admin/patterns/PatternInserter.js +1 -1
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
- package/dist/admin/settings/BedrijfInstellingen.js +144 -0
- package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
- package/dist/admin/settings/MailSettings.js +2 -2
- package/dist/admin/settings/MailSettings.js.map +1 -1
- package/dist/admin/settings/MailTemplates.js +5 -4
- package/dist/admin/settings/MailTemplates.js.map +1 -1
- package/dist/admin/settings/SettingsPanel.js +120 -78
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +4 -4
- package/dist/admin/settings/SnapshotsCard.js.map +1 -1
- package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
- package/dist/admin/settings/VorigeTerugzetten.js +89 -0
- package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
- package/dist/admin/shop/CategoriesTab.js +6 -4
- package/dist/admin/shop/CategoriesTab.js.map +1 -1
- package/dist/admin/shop/DiscountsTab.js +4 -2
- package/dist/admin/shop/DiscountsTab.js.map +1 -1
- package/dist/admin/shop/OrdersTab.js +57 -19
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductPaneel.js +2 -1
- package/dist/admin/shop/ProductPaneel.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +40 -19
- package/dist/admin/shop/ProductsTab.js.map +1 -1
- package/dist/admin/shop/ShopPanel.js +13 -1
- package/dist/admin/shop/ShopPanel.js.map +1 -1
- package/dist/admin/shop/ShopSettingsTab.js +27 -1
- package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
- package/dist/admin/shop/productClient.js +7 -3
- package/dist/admin/shop/productClient.js.map +1 -1
- package/dist/admin/stats/NietGevonden.d.ts +10 -0
- package/dist/admin/stats/NietGevonden.js +78 -0
- package/dist/admin/stats/NietGevonden.js.map +1 -0
- package/dist/admin/stats/StatsPanel.js +6 -1
- package/dist/admin/stats/StatsPanel.js.map +1 -1
- package/dist/admin/stats/lib.d.ts +2 -0
- package/dist/admin/stats/lib.js.map +1 -1
- package/dist/admin/ui/ConfirmDialog.js +10 -1
- package/dist/admin/ui/ConfirmDialog.js.map +1 -1
- package/dist/admin/ui/Icon.d.ts +34 -0
- package/dist/admin/ui/Icon.js +44 -0
- package/dist/admin/ui/Icon.js.map +1 -0
- package/dist/admin/ui/ImageField.d.ts +15 -0
- package/dist/admin/ui/ImageField.js +67 -0
- package/dist/admin/ui/ImageField.js.map +1 -0
- package/dist/admin/ui/KleurVeld.d.ts +25 -0
- package/dist/admin/ui/KleurVeld.js +76 -0
- package/dist/admin/ui/KleurVeld.js.map +1 -0
- package/dist/admin/ui/LaadStaat.d.ts +21 -0
- package/dist/admin/ui/LaadStaat.js +43 -0
- package/dist/admin/ui/LaadStaat.js.map +1 -0
- package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
- package/dist/admin/ui/LinkDialog.d.ts +22 -0
- package/dist/admin/ui/LinkDialog.js +131 -0
- package/dist/admin/ui/LinkDialog.js.map +1 -0
- package/dist/admin/ui/LinkVeld.d.ts +14 -0
- package/dist/admin/ui/LinkVeld.js +49 -0
- package/dist/admin/ui/LinkVeld.js.map +1 -0
- package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
- package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
- package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
- package/dist/admin/ui/charts.js +5 -5
- package/dist/admin/ui/charts.js.map +1 -1
- package/dist/admin/ui/primitives.d.ts +16 -6
- package/dist/admin/ui/primitives.js +98 -26
- package/dist/admin/ui/primitives.js.map +1 -1
- package/dist/admin/ui/select.js +5 -2
- package/dist/admin/ui/select.js.map +1 -1
- package/dist/admin/ui/switch.d.ts +3 -1
- package/dist/admin/ui/switch.js +6 -3
- package/dist/admin/ui/switch.js.map +1 -1
- package/dist/admin/ui/toast.d.ts +2 -1
- package/dist/admin/ui/toast.js +17 -11
- package/dist/admin/ui/toast.js.map +1 -1
- package/dist/admin/visual/BlokKiezer.d.ts +34 -0
- package/dist/admin/visual/BlokKiezer.js +225 -0
- package/dist/admin/visual/BlokKiezer.js.map +1 -0
- package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
- package/dist/admin/visual/InlineGereedschap.js +356 -0
- package/dist/admin/visual/InlineGereedschap.js.map +1 -0
- package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
- package/dist/admin/visual/InlineRijkeTekst.js +152 -0
- package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
- package/dist/admin/visual/VisualEditor.js +273 -125
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/bedrijf/bedrijf.d.ts +36 -0
- package/dist/bedrijf/bedrijf.js +110 -0
- package/dist/bedrijf/bedrijf.js.map +1 -0
- package/dist/blocks/BlockRenderer.js +11 -1
- package/dist/blocks/BlockRenderer.js.map +1 -1
- package/dist/blocks/blockStyle.d.ts +7 -0
- package/dist/blocks/blockStyle.js +16 -3
- package/dist/blocks/blockStyle.js.map +1 -1
- package/dist/blocks/builtinSchemas.js +6 -0
- package/dist/blocks/builtinSchemas.js.map +1 -1
- package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
- package/dist/blocks/builtins/AgendaRender.js +69 -9
- package/dist/blocks/builtins/AgendaRender.js.map +1 -1
- package/dist/blocks/builtins/Availability.d.ts +1 -0
- package/dist/blocks/builtins/Availability.js +23 -0
- package/dist/blocks/builtins/Availability.js.map +1 -0
- package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
- package/dist/blocks/builtins/AvailabilityRender.js +105 -0
- package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
- package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
- package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
- package/dist/blocks/builtins/Booking.js +1 -1
- package/dist/blocks/builtins/Booking.js.map +1 -1
- package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
- package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
- package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
- package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
- package/dist/blocks/builtins/ColumnsRender.js +3 -1
- package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
- package/dist/blocks/builtins/Contact.js +1 -1
- package/dist/blocks/builtins/Contact.js.map +1 -1
- package/dist/blocks/builtins/ContactRender.d.ts +1 -1
- package/dist/blocks/builtins/ContactRender.js +29 -8
- package/dist/blocks/builtins/ContactRender.js.map +1 -1
- package/dist/blocks/builtins/Cta.js +1 -1
- package/dist/blocks/builtins/Cta.js.map +1 -1
- package/dist/blocks/builtins/CtaRender.d.ts +1 -1
- package/dist/blocks/builtins/CtaRender.js +5 -4
- package/dist/blocks/builtins/CtaRender.js.map +1 -1
- package/dist/blocks/builtins/Embed.js +1 -1
- package/dist/blocks/builtins/Embed.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.js +1 -0
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
- package/dist/blocks/builtins/FormBlockRender.js +88 -16
- package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
- package/dist/blocks/builtins/GalleryRender.js +3 -2
- package/dist/blocks/builtins/GalleryRender.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/HeroRender.js +7 -3
- package/dist/blocks/builtins/HeroRender.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
- package/dist/blocks/builtins/OpenNowBadge.js +6 -6
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
- package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
- package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
- package/dist/blocks/builtins/PriceList.d.ts +1 -0
- package/dist/blocks/builtins/PriceList.js +25 -0
- package/dist/blocks/builtins/PriceList.js.map +1 -0
- package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
- package/dist/blocks/builtins/PriceListRender.js +87 -0
- package/dist/blocks/builtins/PriceListRender.js.map +1 -0
- package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
- package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
- package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
- package/dist/blocks/builtins/SectionHeading.js +14 -0
- package/dist/blocks/builtins/SectionHeading.js.map +1 -0
- package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
- package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
- package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
- package/dist/blocks/builtins/SliderRender.js +3 -2
- package/dist/blocks/builtins/SliderRender.js.map +1 -1
- package/dist/blocks/builtins/SymbolRef.js +1 -1
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/TeamRender.js +6 -1
- package/dist/blocks/builtins/TeamRender.js.map +1 -1
- package/dist/blocks/builtins/Testimonials.js +3 -1
- package/dist/blocks/builtins/Testimonials.js.map +1 -1
- package/dist/blocks/builtins/TestimonialsRender.js +4 -0
- package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
- package/dist/blocks/builtins/Widgets.js +2 -2
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/WidgetsRender.js +3 -1
- package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
- package/dist/blocks/builtins/index.d.ts +3 -0
- package/dist/blocks/builtins/index.js +6 -0
- package/dist/blocks/builtins/index.js.map +1 -1
- package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
- package/dist/blocks/builtins/lib/autoComplete.js +20 -0
- package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
- package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
- package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
- package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
- package/dist/blocks/builtins/lib/ical.d.ts +24 -0
- package/dist/blocks/builtins/lib/ical.js +82 -0
- package/dist/blocks/builtins/lib/ical.js.map +1 -0
- package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
- package/dist/blocks/builtins/lib/vandaag.js +22 -0
- package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
- package/dist/blocks/registry.d.ts +6 -0
- package/dist/blocks/registry.js.map +1 -1
- package/dist/blocks/ui/index.js +1 -0
- package/dist/blocks/ui/index.js.map +1 -1
- package/dist/components/EditBar.js +2 -4
- package/dist/components/EditBar.js.map +1 -1
- package/dist/components/News.js +26 -18
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.d.ts +7 -1
- package/dist/components/PageView.js +17 -0
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.js +18 -20
- package/dist/components/ResponsiveImage.js.map +1 -1
- package/dist/components/site/SiteFooter.d.ts +6 -1
- package/dist/components/site/SiteFooter.js +61 -9
- package/dist/components/site/SiteFooter.js.map +1 -1
- package/dist/components/site/SiteHeader.d.ts +15 -0
- package/dist/components/site/SiteHeader.js +70 -0
- package/dist/components/site/SiteHeader.js.map +1 -0
- package/dist/components/site/SiteNav.d.ts +2 -0
- package/dist/components/site/SiteNav.js +29 -5
- package/dist/components/site/SiteNav.js.map +1 -1
- package/dist/demo/DemoStudio.js +2 -2
- package/dist/demo/DemoStudio.js.map +1 -1
- package/dist/demo/demoStore.d.ts +13 -0
- package/dist/demo/demoStore.js +36 -0
- package/dist/demo/demoStore.js.map +1 -1
- package/dist/editor/EditorProvider.js +15 -4
- package/dist/editor/EditorProvider.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/media/ImageContext.d.ts +17 -0
- package/dist/media/ImageContext.js +65 -20
- package/dist/media/ImageContext.js.map +1 -1
- package/dist/media/altInHtml.d.ts +9 -0
- package/dist/media/altInHtml.js +17 -0
- package/dist/media/altInHtml.js.map +1 -0
- package/dist/media/srcset.d.ts +12 -0
- package/dist/media/srcset.js +13 -0
- package/dist/media/srcset.js.map +1 -0
- package/dist/modules/builtins.d.ts +1 -0
- package/dist/modules/builtins.js +16 -3
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.js +5 -3
- package/dist/modules/shop/blocks/Cart.js.map +1 -1
- package/dist/modules/shop/blocks/Checkout.js +56 -35
- package/dist/modules/shop/blocks/Checkout.js.map +1 -1
- package/dist/modules/shop/blocks/Donation.js +4 -4
- package/dist/modules/shop/blocks/Donation.js.map +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +19 -3
- package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
- package/dist/modules/shop/blocks/ProductGrid.js +8 -4
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +4 -3
- package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
- package/dist/modules/shop/lib.d.ts +4 -0
- package/dist/modules/shop/lib.js +14 -0
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/settings.d.ts +3 -0
- package/dist/modules/shop/settings.js +14 -0
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.d.ts +4 -0
- package/dist/modules/shop/strings.js +8 -0
- package/dist/modules/shop/strings.js.map +1 -1
- package/dist/next/envCheck.d.ts +42 -0
- package/dist/next/envCheck.js +106 -0
- package/dist/next/envCheck.js.map +1 -0
- package/dist/next/index.cjs +185 -2
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +8 -1
- package/dist/next/index.js.map +1 -1
- package/dist/next/securityHeaders.d.ts +36 -0
- package/dist/next/securityHeaders.js +74 -0
- package/dist/next/securityHeaders.js.map +1 -0
- package/dist/patterns/builtins.d.ts +7 -0
- package/dist/patterns/builtins.js +138 -3
- package/dist/patterns/builtins.js.map +1 -1
- package/dist/releaseNotes.js +140 -0
- package/dist/releaseNotes.js.map +1 -1
- package/dist/render/PublishedPage.d.ts +2 -1
- package/dist/render/PublishedPage.js +10 -4
- package/dist/render/PublishedPage.js.map +1 -1
- package/dist/schema/blocks.d.ts +470 -0
- package/dist/schema/blocks.js +102 -4
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/business.d.ts +117 -0
- package/dist/schema/business.js +73 -0
- package/dist/schema/business.js.map +1 -0
- package/dist/schema/fields.d.ts +2 -1
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +18 -0
- package/dist/schema/forms.js +18 -3
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/mail.d.ts +10 -0
- package/dist/schema/mail.js +7 -0
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/settings.d.ts +101 -0
- package/dist/schema/settings.js +24 -3
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +2 -0
- package/dist/schema/shop.js +4 -0
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/shopGeld.d.ts +1 -0
- package/dist/schema/shopGeld.js +1 -0
- package/dist/schema/shopGeld.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +68 -1
- package/dist/schema/siteConfig.js +7 -2
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/server/blockData.d.ts +1 -1
- package/dist/server/blockData.js +74 -18
- package/dist/server/blockData.js.map +1 -1
- package/dist/server/cspRapport.d.ts +20 -0
- package/dist/server/cspRapport.js +56 -0
- package/dist/server/cspRapport.js.map +1 -0
- package/dist/server/fonts.d.ts +3 -0
- package/dist/server/fonts.js +39 -0
- package/dist/server/fonts.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/sanitize.js +15 -2
- package/dist/server/sanitize.js.map +1 -1
- package/dist/settings/useSiteSettings.js +4 -1
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/starters/starters.d.ts +69 -0
- package/dist/starters/starters.js +171 -0
- package/dist/starters/starters.js.map +1 -0
- package/dist/styles.css +1149 -208
- package/dist/theme/color.d.ts +10 -0
- package/dist/theme/color.js +17 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/fontFallback.d.ts +23 -0
- package/dist/theme/fontFallback.js +58 -0
- package/dist/theme/fontFallback.js.map +1 -0
- package/dist/theme/fonts.d.ts +11 -0
- package/dist/theme/fonts.js +16 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schema/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\nimport { SeoSchema } from \"./seo\";\n\n/**\n * Eén navigatie-item.\n *\n * `target` is OPTIONEEL en dat is opzet: elk bestaand menu in Git en in Firestore mist dit veld, en\n * moet blijven valideren. Ontbreekt het, dan opent de link in hetzelfde venster — precies wat een\n * gewone `<a href>` altijd al deed.\n *\n * Er staat bewust geen `type: \"page\" | \"extern\"` in. Dat onderscheid is uit de href zelf af te\n * lezen (begint hij met `/` of met `http`), en een apart veld zou een tweede waarheid introduceren\n * die uit de pas kan lopen met de href. Het beheerscherm mag de gebruiker wél die keuze voorleggen;\n * wat er wordt opgeslagen is één ondubbelzinnig adres.\n */\nconst NavLeafSchema = z.object({\n label: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n /**\n * `_embed` toont een externe pagina in een kader BINNEN de site, onder de logo/menubalk, alsof\n * hij erbij hoort. Alleen zinvol bij een externe href.\n */\n target: z.optional(z.enum([\"_self\", \"_blank\", \"_embed\"])),\n});\nexport const NavItemSchema = z.object({\n ...NavLeafSchema.shape,\n /**\n * Submenu (7.24): één niveau diep, bewust niet recursief. \"Diensten ▾ Tuinaanleg / Onderhoud\"\n * dekt vrijwel elke bedrijfssite; een tweede niveau is op mobiel niet meer te bedienen en op\n * desktop een hover-doolhof. Een item mét kinderen blijft zelf klikbaar (href = de\n * overzichtspagina), zodat het menu ook zonder JavaScript en met het toetsenbord werkt.\n */\n children: z.optional(z.array(NavLeafSchema).check(z.maxLength(20))),\n});\nexport type NavItem = z.infer<typeof NavItemSchema>;\nexport type NavLeaf = z.infer<typeof NavLeafSchema>;\n\n/** Verwijst dit item naar buiten? Afgeleid uit de href, zodat er geen tweede waarheid ontstaat. */\nexport function isExterneLink(href: string): boolean {\n return /^https?:\\/\\//i.test(href);\n}\n\n/**\n * Eén doorverwijzing (7.24): een oud pad dat permanent naar een nieuw pad wijst.\n *\n * Ontstaat vanzelf wanneer een klant het pad van een pagina wijzigt — de oude URL staat in\n * zoekmachines, in mails en op visitekaartjes, en zonder redirect wordt dat een 404. Alleen\n * interne paden (beginnen met `/`): een open redirect naar buiten is een phishing-hulpmiddel.\n */\nexport const RedirectSchema = z.object({\n from: z.string().check(z.minLength(1)).check(z.maxLength(400)).check(z.regex(/^\\/[^\\s?#]*$/, \"een pad begint met / en bevat geen spaties\")),\n to: z.string().check(z.minLength(1)).check(z.maxLength(400)).check(z.regex(/^\\/[^\\s]*$/, \"een pad begint met /\")),\n});\nexport type Redirect = z.infer<typeof RedirectSchema>;\n\n/**\n * Normaliseert een pad zoals de catch-all dat doet (\"/over-ons/\" → \"/over-ons\", \"\" → \"/\"), zodat\n * een redirect matcht ongeacht een afsluitende slash.\n */\nexport function normaliseerPad(pad: string): string {\n const p = pad.split(\"?\")[0].split(\"#\")[0].replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p.startsWith(\"/\") ? p : `/${p}`;\n}\n\n/**\n * Zoekt de bestemming voor een pad in de redirect-lijst. Volgt ketens (a→b, b→c) tot een diepte\n * van vijf en weigert lussen: een klant die eerst /a naar /b hernoemt en later terug, mag daar\n * geen eindeloze redirect aan overhouden. `null` = geen doorverwijzing.\n */\nexport function zoekRedirect(pad: string, redirects: Redirect[] | undefined): string | null {\n if (!redirects?.length) return null;\n const kaart = new Map(redirects.map((r) => [normaliseerPad(r.from), normaliseerPad(r.to)]));\n let huidig = normaliseerPad(pad);\n const gezien = new Set<string>([huidig]);\n let doel: string | null = null;\n for (let i = 0; i < 5; i++) {\n const volgende = kaart.get(huidig);\n if (!volgende || gezien.has(volgende)) break;\n gezien.add(volgende);\n doel = volgende;\n huidig = volgende;\n }\n return doel;\n}\n\n/** Het pad waarop een ingekaderde externe pagina wordt getoond. */\nexport const EMBED_PAD = \"/extern\";\n\n/**\n * De href waar dit menu-item feitelijk heen linkt.\n *\n * Bij `_embed` is dat niet de externe URL zelf maar de eigen `/extern`-route, die hem in een kader\n * binnen de site toont. De externe URL gaat als parameter mee; de route controleert vervolgens of\n * dat adres écht in het menu staat vóór hij het inlaadt. Zonder die controle zou iedereen een\n * willekeurige pagina in jouw huisstijl kunnen laten verschijnen door de URL te bewerken.\n */\nexport function navHref(item: NavItem): string {\n if (item.target === \"_embed\" && isExterneLink(item.href)) {\n return `${EMBED_PAD}?url=${encodeURIComponent(item.href)}`;\n }\n return item.href;\n}\n\n/** Staat dit adres als ingekaderd menu-item in de navigatie? Zo niet, dan niet tonen. */\nexport function isToegestaneEmbed(url: string, nav: NavItem[] | undefined): boolean {\n return (nav ?? []).some((i) => i.target === \"_embed\" && i.href === url);\n}\n\n/** Huisstijl-tokens (worden CSS custom properties). Alle uitbreidingen zijn optioneel/update-veilig. */\nexport const ThemeSchema = z.object({\n primary: z.string().check(z.maxLength(40)),\n accent: z.optional(z.string().check(z.maxLength(40))),\n /** Logo-URL (absoluut, https) — gebruikt in de mail-header en op de factuur-PDF. */\n logo: z.optional(z.string().check(z.maxLength(500))),\n background: z.optional(z.string().check(z.maxLength(40))),\n foreground: z.optional(z.string().check(z.maxLength(40))),\n fontFamily: z.optional(z.string().check(z.maxLength(200))),\n /** Optioneel apart lettertype voor koppen (display/serif), voor een elegantere typografie. */\n headingFont: z.optional(z.string().check(z.maxLength(200))),\n /** Optionele stylesheet-URL voor het lettertype (bv. een Google Fonts CSS-link). */\n fontUrl: z.optional(z.string().check(z.maxLength(500))),\n /** Afrondingsschaal (sm/md/lg). */\n radius: z.optional(z.object({ sm: z.optional(z.string().check(z.maxLength(20))), md: z.optional(z.string().check(z.maxLength(20))), lg: z.optional(z.string().check(z.maxLength(20))) })),\n /** Ruimteschaal voor block-padding (xs..xl). */\n spacing: z.optional(z.object({\n xs: z.optional(z.string().check(z.maxLength(20))),\n sm: z.optional(z.string().check(z.maxLength(20))),\n md: z.optional(z.string().check(z.maxLength(20))),\n lg: z.optional(z.string().check(z.maxLength(20))),\n xl: z.optional(z.string().check(z.maxLength(20))),\n })),\n /** Maximale container-breedte + horizontale padding. */\n container: z.optional(z.object({ maxWidth: z.optional(z.string().check(z.maxLength(20))), padding: z.optional(z.string().check(z.maxLength(20))) })),\n /** Donkere modus: uit, altijd aan, of meebewegen met het systeem van de bezoeker. */\n dark: z.optional(z.object({\n /**\n * \"auto\" — volgt het besturingssysteem van de bezoeker (light-dark()).\n * \"dark\" — de site is altijd donker, ongeacht de bezoeker.\n * \"light\" — de site is altijd licht (gelijk aan geen donkere modus).\n *\n * Vervangt de oude `auto`-boolean, die alleen \"volg het systeem\" of \"niets\" kon zeggen —\n * \"deze site is gewoon donker\" was daarmee niet uit te drukken. `auto` blijft gelezen worden\n * zodat bestaande site-configs blijven werken (zie themeMode in XiCMSProvider).\n */\n mode: z.optional(z.enum([\"light\", \"dark\", \"auto\"])),\n /**\n * @deprecated Gebruik `mode`. Blijft werken: true → \"auto\", afwezig/false → \"light\".\n * OPTIONEEL (niet `_default(false)`): met een verplichte default draagt elk gemerged\n * dark-object een `auto`, en dan botst een partiële update uit /beheer op het type.\n */\n auto: z.optional(z.boolean()),\n background: z.optional(z.string().check(z.maxLength(40))),\n foreground: z.optional(z.string().check(z.maxLength(40))),\n primary: z.optional(z.string().check(z.maxLength(40))),\n })),\n});\nexport type ThemeTokens = z.infer<typeof ThemeSchema>;\n\n/**\n * Voegt live thema-instellingen (uit `settings/public.theme`, /beheer) per token samen met het\n * statische SiteConfig-thema. Firestore wint per veld waar gezet; geneste schalen (radius/spacing/\n * container/dark) mergen per subveld, zodat een klant die alleen kleuren wijzigt de fonts/radius\n * uit de repo behoudt. Puur (geen React) — gedeeld door provider en `useMergedSiteConfig`.\n */\nexport function mergeThemeTokens(base: ThemeTokens, override?: ThemeTokens): ThemeTokens {\n if (!override) return base;\n const merged: ThemeTokens = { ...base, ...override };\n for (const key of [\"radius\", \"spacing\", \"container\", \"dark\"] as const) {\n if (base[key] && override[key]) {\n merged[key] = { ...base[key], ...override[key] } as never;\n } else if (base[key] && !override[key]) {\n merged[key] = base[key] as never;\n }\n }\n return merged;\n}\n\n/**\n * Afzender-instelling voor formulier-e-mail. Een provider mag alleen versturen vanaf een\n * geverifieerd domein, dus dit is per site instelbaar:\n * - mode \"xicms\": from = verifiedSender (XiCMS-domein), replyTo = inzender/klant. Werkt direct.\n * - mode \"client\": from = het geverifieerde eigen domein van de klant.\n */\nexport const FormsSenderSchema = z.object({\n mode: z._default(z.enum([\"xicms\", \"client\"]), \"xicms\"),\n /** Geverifieerd from-adres (verplicht ongeacht mode; bij \"client\" het klant-domein). */\n fromEmail: z.optional(z.email()),\n fromName: z.optional(z.string().check(z.maxLength(120))),\n /** Waar notificaties heen gaan (meestal het klant-mailadres). */\n notifyTo: z.optional(z.email()),\n});\nexport type FormsSender = z.infer<typeof FormsSenderSchema>;\n\n/** Eén social-link (platform + url). */\nexport const SocialLinkSchema = z.object({\n platform: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n});\nexport type SocialLink = z.infer<typeof SocialLinkSchema>;\n\n/** Eén footer-kolom: kop + links. */\nexport const FooterColumnSchema = z.object({\n heading: z.optional(z.string().check(z.maxLength(120))),\n links: z._default(z.array(NavItemSchema).check(z.maxLength(20)), []),\n});\n\n/** Bewerkbare footer (klant past dit aan in /beheer; core levert de unstyled `SiteFooter`). */\nexport const FooterSettingsSchema = z.object({\n columns: z.optional(z.array(FooterColumnSchema).check(z.maxLength(6))),\n social: z.optional(z.array(SocialLinkSchema).check(z.maxLength(12))),\n copyright: z.optional(z.string().check(z.maxLength(300))),\n /** Toon de \"Beheer\"-link in de footer (default: aan). */\n showAdminLink: z.optional(z.boolean()),\n});\nexport type FooterSettings = z.infer<typeof FooterSettingsSchema>;\n\n/** Per-module activatie/instellingen (spiegelt ModulesSiteConfig; permissief gehouden). */\nexport const ModulesSettingsSchema = z.record(\n z.string(),\n z.union([\n z.boolean(),\n z.object({ enabled: z.optional(z.boolean()), config: z.optional(z.record(z.string(), z.unknown())) }),\n ]),\n);\n\n/** Het `sites/{siteId}/settings/site`-document: alle bewerkbare site-instellingen. */\nexport const SiteSettingsSchema = z.object({\n name: z.optional(z.string().check(z.minLength(1)).check(z.maxLength(160))),\n // Zelfde hostname-regel als SiteConfigSchema.domain (geen protocol/pad).\n domain: z.union([z.optional(z.string().check(z.maxLength(255)).check(z.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i, \"alleen een hostname, bv. 'www.klant.nl' (zonder https:// of pad)\"))), z.literal(\"\")]),\n contactEmail: z.optional(z.email()),\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n theme: z.optional(ThemeSchema),\n seoDefaults: z.optional(SeoSchema),\n forms: z.optional(FormsSenderSchema),\n footer: z.optional(FooterSettingsSchema),\n modules: z.optional(ModulesSettingsSchema),\n /**\n * Snelkoppelingen op de beheer-startpagina (7.16). Beheer-intern: bewust NIET in de publieke\n * subset. Opslaan loopt via de bestaande saveSiteSettings-callable — die is passthrough met\n * merge, dus dit veld vergt geen functions-wijziging.\n */\n dashboardLinks: z.optional(z.array(z.object({\n label: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n })).check(z.maxLength(12))),\n /** Doorverwijzingen van oude naar nieuwe paden (7.24). Publiek: de catch-all leest ze. */\n redirects: z.optional(z.array(RedirectSchema).check(z.maxLength(200))),\n});\nexport type SiteSettings = z.infer<typeof SiteSettingsSchema>;\n\n/**\n * Publiek-veilige presentatie-instellingen (`sites/{siteId}/settings/public`): wordt door de live\n * site gelezen (footer, thema, nav, modules) zónder de gevoelige velden (e-mailafzender, contact)\n * uit `settings/site` bloot te geven.\n */\nexport const PublicSiteSettingsSchema = z.object({\n name: z.optional(z.string().check(z.maxLength(160))),\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n theme: z.optional(ThemeSchema),\n seoDefaults: z.optional(SeoSchema),\n footer: z.optional(FooterSettingsSchema),\n modules: z.optional(ModulesSettingsSchema),\n redirects: z.optional(z.array(RedirectSchema).check(z.maxLength(200))),\n});\nexport type PublicSiteSettings = z.infer<typeof PublicSiteSettingsSchema>;\n\n/** Haalt de publiek-veilige subset uit de volledige settings (voor het `settings/public`-doc). */\nexport function toPublicSettings(s: SiteSettings): PublicSiteSettings {\n return {\n name: s.name,\n nav: s.nav,\n theme: s.theme,\n seoDefaults: s.seoDefaults,\n footer: s.footer,\n modules: s.modules,\n redirects: s.redirects,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/schema/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\nimport { SeoSchema } from \"./seo\";\nimport { BusinessSchema } from \"./business\";\n\n/**\n * Eén navigatie-item.\n *\n * `target` is OPTIONEEL en dat is opzet: elk bestaand menu in Git en in Firestore mist dit veld, en\n * moet blijven valideren. Ontbreekt het, dan opent de link in hetzelfde venster — precies wat een\n * gewone `<a href>` altijd al deed.\n *\n * Er staat bewust geen `type: \"page\" | \"extern\"` in. Dat onderscheid is uit de href zelf af te\n * lezen (begint hij met `/` of met `http`), en een apart veld zou een tweede waarheid introduceren\n * die uit de pas kan lopen met de href. Het beheerscherm mag de gebruiker wél die keuze voorleggen;\n * wat er wordt opgeslagen is één ondubbelzinnig adres.\n */\nconst NavLeafSchema = z.object({\n label: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n /**\n * `_embed` toont een externe pagina in een kader BINNEN de site, onder de logo/menubalk, alsof\n * hij erbij hoort. Alleen zinvol bij een externe href.\n */\n target: z.optional(z.enum([\"_self\", \"_blank\", \"_embed\"])),\n});\nexport const NavItemSchema = z.object({\n ...NavLeafSchema.shape,\n /**\n * Submenu (7.24): één niveau diep, bewust niet recursief. \"Diensten ▾ Tuinaanleg / Onderhoud\"\n * dekt vrijwel elke bedrijfssite; een tweede niveau is op mobiel niet meer te bedienen en op\n * desktop een hover-doolhof. Een item mét kinderen blijft zelf klikbaar (href = de\n * overzichtspagina), zodat het menu ook zonder JavaScript en met het toetsenbord werkt.\n */\n children: z.optional(z.array(NavLeafSchema).check(z.maxLength(20))),\n});\nexport type NavItem = z.infer<typeof NavItemSchema>;\nexport type NavLeaf = z.infer<typeof NavLeafSchema>;\n\n/** Verwijst dit item naar buiten? Afgeleid uit de href, zodat er geen tweede waarheid ontstaat. */\nexport function isExterneLink(href: string): boolean {\n return /^https?:\\/\\//i.test(href);\n}\n\n/**\n * Eén doorverwijzing (7.24): een oud pad dat permanent naar een nieuw pad wijst.\n *\n * Ontstaat vanzelf wanneer een klant het pad van een pagina wijzigt — de oude URL staat in\n * zoekmachines, in mails en op visitekaartjes, en zonder redirect wordt dat een 404. Alleen\n * interne paden (beginnen met `/`): een open redirect naar buiten is een phishing-hulpmiddel.\n */\nexport const RedirectSchema = z.object({\n from: z.string().check(z.minLength(1)).check(z.maxLength(400)).check(z.regex(/^\\/[^\\s?#]*$/, \"een pad begint met / en bevat geen spaties\")),\n to: z.string().check(z.minLength(1)).check(z.maxLength(400)).check(z.regex(/^\\/[^\\s]*$/, \"een pad begint met /\")),\n});\nexport type Redirect = z.infer<typeof RedirectSchema>;\n\n/**\n * Normaliseert een pad zoals de catch-all dat doet (\"/over-ons/\" → \"/over-ons\", \"\" → \"/\"), zodat\n * een redirect matcht ongeacht een afsluitende slash.\n */\nexport function normaliseerPad(pad: string): string {\n const p = pad.split(\"?\")[0].split(\"#\")[0].replace(/\\/+$/, \"\");\n return p === \"\" ? \"/\" : p.startsWith(\"/\") ? p : `/${p}`;\n}\n\n/**\n * Zoekt de bestemming voor een pad in de redirect-lijst. Volgt ketens (a→b, b→c) tot een diepte\n * van vijf en weigert lussen: een klant die eerst /a naar /b hernoemt en later terug, mag daar\n * geen eindeloze redirect aan overhouden. `null` = geen doorverwijzing.\n */\nexport function zoekRedirect(pad: string, redirects: Redirect[] | undefined): string | null {\n if (!redirects?.length) return null;\n const kaart = new Map(redirects.map((r) => [normaliseerPad(r.from), normaliseerPad(r.to)]));\n let huidig = normaliseerPad(pad);\n const gezien = new Set<string>([huidig]);\n let doel: string | null = null;\n for (let i = 0; i < 5; i++) {\n const volgende = kaart.get(huidig);\n if (!volgende || gezien.has(volgende)) break;\n gezien.add(volgende);\n doel = volgende;\n huidig = volgende;\n }\n return doel;\n}\n\n/** Het pad waarop een ingekaderde externe pagina wordt getoond. */\nexport const EMBED_PAD = \"/extern\";\n\n/**\n * De href waar dit menu-item feitelijk heen linkt.\n *\n * Bij `_embed` is dat niet de externe URL zelf maar de eigen `/extern`-route, die hem in een kader\n * binnen de site toont. De externe URL gaat als parameter mee; de route controleert vervolgens of\n * dat adres écht in het menu staat vóór hij het inlaadt. Zonder die controle zou iedereen een\n * willekeurige pagina in jouw huisstijl kunnen laten verschijnen door de URL te bewerken.\n */\nexport function navHref(item: NavItem): string {\n if (item.target === \"_embed\" && isExterneLink(item.href)) {\n return `${EMBED_PAD}?url=${encodeURIComponent(item.href)}`;\n }\n return item.href;\n}\n\n/** Staat dit adres als ingekaderd menu-item in de navigatie? Zo niet, dan niet tonen. */\nexport function isToegestaneEmbed(url: string, nav: NavItem[] | undefined): boolean {\n return (nav ?? []).some((i) => i.target === \"_embed\" && i.href === url);\n}\n\n/** Huisstijl-tokens (worden CSS custom properties). Alle uitbreidingen zijn optioneel/update-veilig. */\nexport const ThemeSchema = z.object({\n primary: z.string().check(z.maxLength(40)),\n accent: z.optional(z.string().check(z.maxLength(40))),\n /** Logo-URL (absoluut, https) — gebruikt in de mail-header en op de factuur-PDF. */\n logo: z.optional(z.string().check(z.maxLength(500))),\n background: z.optional(z.string().check(z.maxLength(40))),\n foreground: z.optional(z.string().check(z.maxLength(40))),\n fontFamily: z.optional(z.string().check(z.maxLength(200))),\n /** Optioneel apart lettertype voor koppen (display/serif), voor een elegantere typografie. */\n headingFont: z.optional(z.string().check(z.maxLength(200))),\n /** Optionele stylesheet-URL voor het lettertype (bv. een Google Fonts CSS-link). */\n fontUrl: z.optional(z.string().check(z.maxLength(500))),\n /** Afrondingsschaal (sm/md/lg). */\n radius: z.optional(z.object({ sm: z.optional(z.string().check(z.maxLength(20))), md: z.optional(z.string().check(z.maxLength(20))), lg: z.optional(z.string().check(z.maxLength(20))) })),\n /** Ruimteschaal voor block-padding (xs..xl). */\n spacing: z.optional(z.object({\n xs: z.optional(z.string().check(z.maxLength(20))),\n sm: z.optional(z.string().check(z.maxLength(20))),\n md: z.optional(z.string().check(z.maxLength(20))),\n lg: z.optional(z.string().check(z.maxLength(20))),\n xl: z.optional(z.string().check(z.maxLength(20))),\n })),\n /** Maximale container-breedte + horizontale padding. */\n container: z.optional(z.object({ maxWidth: z.optional(z.string().check(z.maxLength(20))), padding: z.optional(z.string().check(z.maxLength(20))) })),\n /** Donkere modus: uit, altijd aan, of meebewegen met het systeem van de bezoeker. */\n dark: z.optional(z.object({\n /**\n * \"auto\" — volgt het besturingssysteem van de bezoeker (light-dark()).\n * \"dark\" — de site is altijd donker, ongeacht de bezoeker.\n * \"light\" — de site is altijd licht (gelijk aan geen donkere modus).\n *\n * Vervangt de oude `auto`-boolean, die alleen \"volg het systeem\" of \"niets\" kon zeggen —\n * \"deze site is gewoon donker\" was daarmee niet uit te drukken. `auto` blijft gelezen worden\n * zodat bestaande site-configs blijven werken (zie themeMode in XiCMSProvider).\n */\n mode: z.optional(z.enum([\"light\", \"dark\", \"auto\"])),\n /**\n * @deprecated Gebruik `mode`. Blijft werken: true → \"auto\", afwezig/false → \"light\".\n * OPTIONEEL (niet `_default(false)`): met een verplichte default draagt elk gemerged\n * dark-object een `auto`, en dan botst een partiële update uit /beheer op het type.\n */\n auto: z.optional(z.boolean()),\n background: z.optional(z.string().check(z.maxLength(40))),\n foreground: z.optional(z.string().check(z.maxLength(40))),\n primary: z.optional(z.string().check(z.maxLength(40))),\n })),\n});\nexport type ThemeTokens = z.infer<typeof ThemeSchema>;\n\n/**\n * Voegt live thema-instellingen (uit `settings/public.theme`, /beheer) per token samen met het\n * statische SiteConfig-thema. Firestore wint per veld waar gezet; geneste schalen (radius/spacing/\n * container/dark) mergen per subveld, zodat een klant die alleen kleuren wijzigt de fonts/radius\n * uit de repo behoudt. Puur (geen React) — gedeeld door provider en `useMergedSiteConfig`.\n */\nexport function mergeThemeTokens(base: ThemeTokens, override?: ThemeTokens): ThemeTokens {\n if (!override) return base;\n const merged: ThemeTokens = { ...base, ...override };\n for (const key of [\"radius\", \"spacing\", \"container\", \"dark\"] as const) {\n if (base[key] && override[key]) {\n merged[key] = { ...base[key], ...override[key] } as never;\n } else if (base[key] && !override[key]) {\n merged[key] = base[key] as never;\n }\n }\n return merged;\n}\n\n/**\n * Afzender-instelling voor formulier-e-mail. Een provider mag alleen versturen vanaf een\n * geverifieerd domein, dus dit is per site instelbaar:\n * - mode \"xicms\": from = verifiedSender (XiCMS-domein), replyTo = inzender/klant. Werkt direct.\n * - mode \"client\": from = het geverifieerde eigen domein van de klant.\n */\nexport const FormsSenderSchema = z.object({\n mode: z._default(z.enum([\"xicms\", \"client\"]), \"xicms\"),\n /** Geverifieerd from-adres (verplicht ongeacht mode; bij \"client\" het klant-domein). */\n fromEmail: z.optional(z.email()),\n fromName: z.optional(z.string().check(z.maxLength(120))),\n /** Waar notificaties heen gaan (meestal het klant-mailadres). */\n notifyTo: z.optional(z.email()),\n});\nexport type FormsSender = z.infer<typeof FormsSenderSchema>;\n\n/** Eén social-link (platform + url). */\nexport const SocialLinkSchema = z.object({\n platform: z.string().check(z.minLength(1)).check(z.maxLength(40)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n});\nexport type SocialLink = z.infer<typeof SocialLinkSchema>;\n\n/** Eén footer-kolom: kop + links. */\nexport const FooterColumnSchema = z.object({\n heading: z.optional(z.string().check(z.maxLength(120))),\n links: z._default(z.array(NavItemSchema).check(z.maxLength(20)), []),\n});\n\n/** Bewerkbare footer (klant past dit aan in /beheer; core levert de unstyled `SiteFooter`). */\nexport const FooterSettingsSchema = z.object({\n columns: z.optional(z.array(FooterColumnSchema).check(z.maxLength(6))),\n social: z.optional(z.array(SocialLinkSchema).check(z.maxLength(12))),\n copyright: z.optional(z.string().check(z.maxLength(300))),\n /** Toon de \"Beheer\"-link in de footer (default: aan). */\n showAdminLink: z.optional(z.boolean()),\n});\nexport type FooterSettings = z.infer<typeof FooterSettingsSchema>;\n\n/**\n * De kop van de site (8.13), voor `SiteHeader`: logo, één actieknop, en op een telefoon een vaste\n * balk onderaan met bellen en de actie. Sites met een eigen header negeren dit gewoon.\n */\nexport const HeaderSettingsSchema = z.object({\n /** Logo-afbeelding; leeg = de sitenaam als tekst. */\n logo: z.optional(z.string().check(z.maxLength(2000))),\n /** Hoogte van het logo in px (desktop). */\n logoHoogte: z.optional(z.number().check(z.minimum(20)).check(z.maximum(120))),\n /** De actieknop rechts (\"Afspraak maken\", \"Offerte aanvragen\"). */\n cta: z.optional(z.object({ label: z.string().check(z.maxLength(40)), href: z.string().check(z.maxLength(2000)) })),\n /** Blijft bovenaan staan bij scrollen (standaard aan). */\n sticky: z.optional(z.boolean()),\n /** Op een telefoon een balk onderaan met \"Bel\" en de actieknop. */\n mobielBalk: z.optional(z.boolean()),\n});\nexport type HeaderSettings = z.infer<typeof HeaderSettingsSchema>;\n\n/** Per-module activatie/instellingen (spiegelt ModulesSiteConfig; permissief gehouden). */\nexport const ModulesSettingsSchema = z.record(\n z.string(),\n z.union([\n z.boolean(),\n z.object({ enabled: z.optional(z.boolean()), config: z.optional(z.record(z.string(), z.unknown())) }),\n ]),\n);\n\n/** Het `sites/{siteId}/settings/site`-document: alle bewerkbare site-instellingen. */\nexport const SiteSettingsSchema = z.object({\n name: z.optional(z.string().check(z.minLength(1)).check(z.maxLength(160))),\n // Zelfde hostname-regel als SiteConfigSchema.domain (geen protocol/pad).\n domain: z.union([z.optional(z.string().check(z.maxLength(255)).check(z.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i, \"alleen een hostname, bv. 'www.klant.nl' (zonder https:// of pad)\"))), z.literal(\"\")]),\n contactEmail: z.optional(z.email()),\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n theme: z.optional(ThemeSchema),\n seoDefaults: z.optional(SeoSchema),\n forms: z.optional(FormsSenderSchema),\n footer: z.optional(FooterSettingsSchema),\n header: z.optional(HeaderSettingsSchema),\n modules: z.optional(ModulesSettingsSchema),\n /**\n * Snelkoppelingen op de beheer-startpagina (7.16). Beheer-intern: bewust NIET in de publieke\n * subset. Opslaan loopt via de bestaande saveSiteSettings-callable — die is passthrough met\n * merge, dus dit veld vergt geen functions-wijziging.\n */\n dashboardLinks: z.optional(z.array(z.object({\n label: z.string().check(z.minLength(1)).check(z.maxLength(80)),\n href: z.string().check(z.minLength(1)).check(z.maxLength(2000)),\n })).check(z.maxLength(12))),\n /** Doorverwijzingen van oude naar nieuwe paden (7.24). Publiek: de catch-all leest ze. */\n redirects: z.optional(z.array(RedirectSchema).check(z.maxLength(200))),\n /** Bedrijfsprofiel (8.13). Publiek: de site toont het en zet het in de JSON-LD. */\n business: z.optional(BusinessSchema),\n});\nexport type SiteSettings = z.infer<typeof SiteSettingsSchema>;\n\n/**\n * Publiek-veilige presentatie-instellingen (`sites/{siteId}/settings/public`): wordt door de live\n * site gelezen (footer, thema, nav, modules) zónder de gevoelige velden (e-mailafzender, contact)\n * uit `settings/site` bloot te geven.\n */\nexport const PublicSiteSettingsSchema = z.object({\n name: z.optional(z.string().check(z.maxLength(160))),\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n theme: z.optional(ThemeSchema),\n seoDefaults: z.optional(SeoSchema),\n footer: z.optional(FooterSettingsSchema),\n header: z.optional(HeaderSettingsSchema),\n modules: z.optional(ModulesSettingsSchema),\n redirects: z.optional(z.array(RedirectSchema).check(z.maxLength(200))),\n business: z.optional(BusinessSchema),\n});\nexport type PublicSiteSettings = z.infer<typeof PublicSiteSettingsSchema>;\n\n/** Haalt de publiek-veilige subset uit de volledige settings (voor het `settings/public`-doc). */\nexport function toPublicSettings(s: SiteSettings): PublicSiteSettings {\n return {\n name: s.name,\n nav: s.nav,\n theme: s.theme,\n seoDefaults: s.seoDefaults,\n footer: s.footer,\n header: s.header,\n modules: s.modules,\n redirects: s.redirects,\n business: s.business,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/schema/shop.d.ts
CHANGED
|
@@ -258,6 +258,7 @@ export declare const OrderSchema: z.ZodMiniObject<{
|
|
|
258
258
|
city: z.ZodMiniString<string>;
|
|
259
259
|
country: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
260
260
|
}, z.core.$strip>>;
|
|
261
|
+
pickup: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
261
262
|
billing: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
262
263
|
address: z.ZodMiniString<string>;
|
|
263
264
|
zip: z.ZodMiniString<string>;
|
|
@@ -329,6 +330,7 @@ export declare const CreateOrderInputSchema: z.ZodMiniObject<{
|
|
|
329
330
|
city: z.ZodMiniString<string>;
|
|
330
331
|
country: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
331
332
|
}, z.core.$strip>>;
|
|
333
|
+
pickup: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
332
334
|
billing: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
333
335
|
address: z.ZodMiniString<string>;
|
|
334
336
|
zip: z.ZodMiniString<string>;
|
package/dist/schema/shop.js
CHANGED
|
@@ -214,6 +214,8 @@ const OrderSchema = z.object({
|
|
|
214
214
|
})),
|
|
215
215
|
customer: OrderCustomerSchema,
|
|
216
216
|
shipping: z.optional(OrderAddressSchema),
|
|
217
|
+
/** 7.33: de klant haalt de bestelling af; `shipping` ontbreekt dan en de verzendkosten zijn 0. */
|
|
218
|
+
pickup: z.optional(z.boolean()),
|
|
217
219
|
/**
|
|
218
220
|
* 7.27: factuuradres, alleen aanwezig als het AFWIJKT van het verzendadres — afwezig betekent
|
|
219
221
|
* "hetzelfde als hierboven" (bestaande orders blijven zo correct zonder migratie).
|
|
@@ -278,6 +280,8 @@ const CreateOrderInputSchema = z.object({
|
|
|
278
280
|
items: z.array(CreateOrderItemInputSchema).check(z.minLength(1)).check(z.maxLength(50)),
|
|
279
281
|
customer: OrderCustomerSchema,
|
|
280
282
|
shipping: z.optional(OrderAddressSchema),
|
|
283
|
+
/** 7.33: afhalen i.p.v. verzenden — dan geen `shipping`; de server controleert of de winkel het aanbiedt. */
|
|
284
|
+
pickup: z.optional(z.boolean()),
|
|
281
285
|
/** 7.27: alleen meesturen als het factuuradres afwijkt van het verzendadres. */
|
|
282
286
|
billing: z.optional(OrderAddressSchema),
|
|
283
287
|
note: z.optional(z.string().check(z.maxLength(2e3))),
|
package/dist/schema/shop.js.map
CHANGED
|
@@ -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\", \"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":[]}
|
|
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 /** 7.33: de klant haalt de bestelling af; `shipping` ontbreekt dan en de verzendkosten zijn 0. */\n pickup: z.optional(z.boolean()),\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.33: afhalen i.p.v. verzenden — dan geen `shipping`; de server controleert of de winkel het aanbiedt. */\n pickup: z.optional(z.boolean()),\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":[]}
|
|
@@ -40,6 +40,7 @@ export declare function verzendLanden(cfg: VerzendConfig): string[];
|
|
|
40
40
|
export declare function shippingCentsFor(itemsCents: number, cfg: VerzendConfig, hasShippableItems: boolean, opties?: {
|
|
41
41
|
land?: string;
|
|
42
42
|
freeShipping?: boolean;
|
|
43
|
+
pickup?: boolean;
|
|
43
44
|
}): number;
|
|
44
45
|
/** Centen → "€ 13,95" (nl-NL). */
|
|
45
46
|
export declare function formatCents(cents: number, currency?: string): string;
|
package/dist/schema/shopGeld.js
CHANGED
|
@@ -21,6 +21,7 @@ function verzendLanden(cfg) {
|
|
|
21
21
|
}
|
|
22
22
|
function shippingCentsFor(itemsCents, cfg, hasShippableItems, opties) {
|
|
23
23
|
if (!hasShippableItems) return 0;
|
|
24
|
+
if (opties?.pickup) return 0;
|
|
24
25
|
if (opties?.freeShipping) return 0;
|
|
25
26
|
const zone = zoneVoorLand(cfg, opties?.land);
|
|
26
27
|
const flat = zone ? zone.flatCents : cfg.shippingFlatCents ?? 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schema/shopGeld.ts"],"sourcesContent":["/**\n * Geld- en variant-helpers van de shop — in een eigen, zod-VRIJE module (7.14). Ze stonden in\n * schema/shop.ts, en omdat de shop-blokken ze in hun Render nodig hebben trok élke shop-pagina\n * daarmee alle shop-schema's plus de zod-runtime de bezoekersbundel in. Pure rekenfuncties;\n * schema/shop.ts her-exporteert ze ongewijzigd.\n */\nimport type { Product } from \"./shop\";\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/**\n * Verzendtarief per land (7.20). `landen` is een lijst ISO-landcodes; leeg = \"alle overige\".\n * Zo dekt één rij \"NL\", een tweede \"BE, DE\" en een laatste zonder landen de rest van de wereld.\n */\nexport interface Verzendzone {\n naam: string;\n landen?: string[];\n flatCents: number;\n /** Gratis vanaf dit orderbedrag (0/leeg = nooit gratis in deze zone). */\n freeFromCents?: number;\n}\n\nexport interface VerzendConfig {\n shippingFlatCents?: number;\n shippingFreeFromCents?: number;\n /** Zones hebben voorrang; zonder zones geldt het enkele tarief hierboven (gedrag vóór 7.20). */\n shippingZones?: Verzendzone[];\n}\n\n/** De zone die bij een land hoort: eerst een expliciete match, anders de zone zónder landenlijst. */\nexport function zoneVoorLand(cfg: VerzendConfig, land: string | undefined): Verzendzone | undefined {\n const zones = cfg.shippingZones ?? [];\n if (zones.length === 0) return undefined;\n const code = (land ?? \"NL\").trim().toUpperCase();\n return zones.find((z) => (z.landen ?? []).some((l) => l.trim().toUpperCase() === code)) ?? zones.find((z) => (z.landen ?? []).length === 0);\n}\n\n/** Landen waarheen deze winkel verzendt; leeg = geen beperking (er is een \"overige\"-zone). */\nexport function verzendLanden(cfg: VerzendConfig): string[] {\n const zones = cfg.shippingZones ?? [];\n if (zones.length === 0 || zones.some((z) => (z.landen ?? []).length === 0)) return [];\n return [...new Set(zones.flatMap((z) => (z.landen ?? []).map((l) => l.trim().toUpperCase())))];\n}\n\n/**\n * Verzendkosten. Donatie-only = gratis; een kortingscode met gratis verzending maakt het 0.\n *\n * Eén functie voor winkelwagen, afrekenen én server. Er waren drie implementaties: de winkelwagen\n * kende de kortingscode niet (toonde dus altijd de volle verzendkosten), de afrekenpagina lapte\n * `freeShipping` er los omheen, en de server rekende het nog eens over. Nu telt alleen deze.\n */\nexport function shippingCentsFor(\n itemsCents: number,\n cfg: VerzendConfig,\n hasShippableItems: boolean,\n opties?: { land?: string; freeShipping?: boolean },\n): number {\n if (!hasShippableItems) return 0;\n if (opties?.freeShipping) return 0;\n const zone = zoneVoorLand(cfg, opties?.land);\n const flat = zone ? zone.flatCents : (cfg.shippingFlatCents ?? 0);\n const freeFrom = zone ? zone.freeFromCents : 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":"AASO,SAAS,cAAc,QAA0B;AACtD,SAAO,OAAO,KAAK,GAAG;AACxB;AAGO,SAAS,kBAAkB,SAAmD,YAA6B;AAChH,MAAI,YAAY;AACd,UAAM,IAAI,QAAQ,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,UAAU;AAC5D,QAAI,GAAG,eAAe,OAAW,QAAO,EAAE;AAAA,EAC5C;AACA,SAAO,QAAQ;AACjB;AAsBO,SAAS,aAAa,KAAoB,MAAmD;AAClG,QAAM,QAAQ,IAAI,iBAAiB,CAAC;AACpC,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE,YAAY;AAC/C,SAAO,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,MAAM,IAAI,CAAC,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC;AAC5I;AAGO,SAAS,cAAc,KAA8B;AAC1D,QAAM,QAAQ,IAAI,iBAAiB,CAAC;AACpC,MAAI,MAAM,WAAW,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC,EAAG,QAAO,CAAC;AACpF,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AAC/F;AASO,SAAS,iBACd,YACA,KACA,mBACA,QACQ;AACR,MAAI,CAAC,kBAAmB,QAAO;
|
|
1
|
+
{"version":3,"sources":["../../src/schema/shopGeld.ts"],"sourcesContent":["/**\n * Geld- en variant-helpers van de shop — in een eigen, zod-VRIJE module (7.14). Ze stonden in\n * schema/shop.ts, en omdat de shop-blokken ze in hun Render nodig hebben trok élke shop-pagina\n * daarmee alle shop-schema's plus de zod-runtime de bezoekersbundel in. Pure rekenfuncties;\n * schema/shop.ts her-exporteert ze ongewijzigd.\n */\nimport type { Product } from \"./shop\";\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/**\n * Verzendtarief per land (7.20). `landen` is een lijst ISO-landcodes; leeg = \"alle overige\".\n * Zo dekt één rij \"NL\", een tweede \"BE, DE\" en een laatste zonder landen de rest van de wereld.\n */\nexport interface Verzendzone {\n naam: string;\n landen?: string[];\n flatCents: number;\n /** Gratis vanaf dit orderbedrag (0/leeg = nooit gratis in deze zone). */\n freeFromCents?: number;\n}\n\nexport interface VerzendConfig {\n shippingFlatCents?: number;\n shippingFreeFromCents?: number;\n /** Zones hebben voorrang; zonder zones geldt het enkele tarief hierboven (gedrag vóór 7.20). */\n shippingZones?: Verzendzone[];\n}\n\n/** De zone die bij een land hoort: eerst een expliciete match, anders de zone zónder landenlijst. */\nexport function zoneVoorLand(cfg: VerzendConfig, land: string | undefined): Verzendzone | undefined {\n const zones = cfg.shippingZones ?? [];\n if (zones.length === 0) return undefined;\n const code = (land ?? \"NL\").trim().toUpperCase();\n return zones.find((z) => (z.landen ?? []).some((l) => l.trim().toUpperCase() === code)) ?? zones.find((z) => (z.landen ?? []).length === 0);\n}\n\n/** Landen waarheen deze winkel verzendt; leeg = geen beperking (er is een \"overige\"-zone). */\nexport function verzendLanden(cfg: VerzendConfig): string[] {\n const zones = cfg.shippingZones ?? [];\n if (zones.length === 0 || zones.some((z) => (z.landen ?? []).length === 0)) return [];\n return [...new Set(zones.flatMap((z) => (z.landen ?? []).map((l) => l.trim().toUpperCase())))];\n}\n\n/**\n * Verzendkosten. Donatie-only = gratis; een kortingscode met gratis verzending maakt het 0.\n *\n * Eén functie voor winkelwagen, afrekenen én server. Er waren drie implementaties: de winkelwagen\n * kende de kortingscode niet (toonde dus altijd de volle verzendkosten), de afrekenpagina lapte\n * `freeShipping` er los omheen, en de server rekende het nog eens over. Nu telt alleen deze.\n */\nexport function shippingCentsFor(\n itemsCents: number,\n cfg: VerzendConfig,\n hasShippableItems: boolean,\n opties?: { land?: string; freeShipping?: boolean; pickup?: boolean },\n): number {\n if (!hasShippableItems) return 0;\n // Afhalen (7.33): er gaat niets op transport, dus geen verzendkosten.\n if (opties?.pickup) return 0;\n if (opties?.freeShipping) return 0;\n const zone = zoneVoorLand(cfg, opties?.land);\n const flat = zone ? zone.flatCents : (cfg.shippingFlatCents ?? 0);\n const freeFrom = zone ? zone.freeFromCents : 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":"AASO,SAAS,cAAc,QAA0B;AACtD,SAAO,OAAO,KAAK,GAAG;AACxB;AAGO,SAAS,kBAAkB,SAAmD,YAA6B;AAChH,MAAI,YAAY;AACd,UAAM,IAAI,QAAQ,UAAU,KAAK,CAAC,MAAM,EAAE,QAAQ,UAAU;AAC5D,QAAI,GAAG,eAAe,OAAW,QAAO,EAAE;AAAA,EAC5C;AACA,SAAO,QAAQ;AACjB;AAsBO,SAAS,aAAa,KAAoB,MAAmD;AAClG,QAAM,QAAQ,IAAI,iBAAiB,CAAC;AACpC,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE,YAAY;AAC/C,SAAO,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,MAAM,IAAI,CAAC,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC;AAC5I;AAGO,SAAS,cAAc,KAA8B;AAC1D,QAAM,QAAQ,IAAI,iBAAiB,CAAC;AACpC,MAAI,MAAM,WAAW,KAAK,MAAM,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,WAAW,CAAC,EAAG,QAAO,CAAC;AACpF,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;AAC/F;AASO,SAAS,iBACd,YACA,KACA,mBACA,QACQ;AACR,MAAI,CAAC,kBAAmB,QAAO;AAE/B,MAAI,QAAQ,OAAQ,QAAO;AAC3B,MAAI,QAAQ,aAAc,QAAO;AACjC,QAAM,OAAO,aAAa,KAAK,QAAQ,IAAI;AAC3C,QAAM,OAAO,OAAO,KAAK,YAAa,IAAI,qBAAqB;AAC/D,QAAM,WAAW,OAAO,KAAK,gBAAgB,IAAI;AACjD,MAAI,aAAa,UAAa,WAAW,KAAK,cAAc,SAAU,QAAO;AAC7E,SAAO;AACT;AAGO,SAAS,YAAY,OAAe,WAAW,OAAe;AACnE,SAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,QAAQ,GAAG;AAC3F;","names":[]}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* `@xiwebdesign/xicms-core` bevat hier nooit klantgegevens — die staan in de klantrepo.
|
|
7
7
|
*/
|
|
8
8
|
import * as z from "zod/mini";
|
|
9
|
-
import { type NavItem, type ThemeTokens, type FormsSender } from "./settings.js";
|
|
9
|
+
import { type NavItem, type ThemeTokens, type FormsSender, type HeaderSettings } from "./settings.js";
|
|
10
10
|
import { type Seo } from "./seo.js";
|
|
11
|
+
import { type Business } from "./business.js";
|
|
11
12
|
import type { ModulesSiteConfig } from "../modules/types.js";
|
|
12
13
|
export type SiteMode = "demo" | "live";
|
|
13
14
|
export interface SiteConfig {
|
|
@@ -25,6 +26,17 @@ export interface SiteConfig {
|
|
|
25
26
|
* niets naar Firebase. Alleen bedoeld voor een demo-site; laat dit `false`/weg op echte klantsites.
|
|
26
27
|
*/
|
|
27
28
|
demoEditing?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* 8.3: Google-lettertypen via de eigen site laden (`/api/fonts`), zodat bezoekers geen verbinding
|
|
31
|
+
* met Google maken. Vereist de route `app/api/fonts/route.ts` (`export { fontsGET as GET }`).
|
|
32
|
+
*/
|
|
33
|
+
selfHostFonts?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 8.8: rustige overgang tussen pagina's (View Transitions API, via React `<ViewTransition>`).
|
|
36
|
+
* "vervagen" = korte crossfade, "schuiven" = fade met een kleine verschuiving. Leeg = geen.
|
|
37
|
+
* Browsers zonder ondersteuning wisselen gewoon direct; `prefers-reduced-motion` zet hem uit.
|
|
38
|
+
*/
|
|
39
|
+
paginaOvergang?: "vervagen" | "schuiven";
|
|
28
40
|
/** Taalcode voor `<html lang>` en a11y (default "nl"). */
|
|
29
41
|
lang?: string;
|
|
30
42
|
/**
|
|
@@ -58,6 +70,13 @@ export interface SiteConfig {
|
|
|
58
70
|
* Afwezig = de standaard van de module (`defaultEnabled`, doorgaans aan).
|
|
59
71
|
*/
|
|
60
72
|
modules?: ModulesSiteConfig;
|
|
73
|
+
/**
|
|
74
|
+
* 8.13: het bedrijfsprofiel als startwaarde (adres, telefoon, openingstijden). Wat de klant in
|
|
75
|
+
* /beheer → Instellingen → Bedrijf opslaat, wint. Zie `schema/business.ts`.
|
|
76
|
+
*/
|
|
77
|
+
business?: Business;
|
|
78
|
+
/** 8.13: startwaarde voor de kop (`SiteHeader`): logo, actieknop, mobiele balk. */
|
|
79
|
+
header?: HeaderSettings;
|
|
61
80
|
}
|
|
62
81
|
/** Helper met type-inferentie voor `site.config.ts`. */
|
|
63
82
|
export declare function defineSiteConfig(config: SiteConfig): SiteConfig;
|
|
@@ -75,6 +94,11 @@ export declare const SiteConfigSchema: z.ZodMiniObject<{
|
|
|
75
94
|
live: "live";
|
|
76
95
|
}>;
|
|
77
96
|
demoEditing: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
97
|
+
selfHostFonts: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
98
|
+
paginaOvergang: z.ZodMiniOptional<z.ZodMiniEnum<{
|
|
99
|
+
schuiven: "schuiven";
|
|
100
|
+
vervagen: "vervagen";
|
|
101
|
+
}>>;
|
|
78
102
|
lang: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
79
103
|
locales: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
80
104
|
defaultLocale: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
@@ -155,6 +179,49 @@ export declare const SiteConfigSchema: z.ZodMiniObject<{
|
|
|
155
179
|
enabled: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
156
180
|
config: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniUnknown>>;
|
|
157
181
|
}, z.core.$strip>]>>>;
|
|
182
|
+
business: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
183
|
+
type: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
184
|
+
name: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
185
|
+
description: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
186
|
+
phone: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
187
|
+
email: z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniEmail, z.ZodMiniLiteral<"">]>>;
|
|
188
|
+
whatsapp: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
189
|
+
address: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
190
|
+
street: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
191
|
+
postalCode: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
192
|
+
city: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
193
|
+
country: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
194
|
+
}, z.core.$strip>>;
|
|
195
|
+
geo: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
196
|
+
lat: z.ZodMiniNumber<number>;
|
|
197
|
+
lng: z.ZodMiniNumber<number>;
|
|
198
|
+
}, z.core.$strip>>;
|
|
199
|
+
hours: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniObject<{
|
|
200
|
+
day: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
201
|
+
hours: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
202
|
+
}, z.core.$strip>>>;
|
|
203
|
+
hoursNote: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
204
|
+
exceptions: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniObject<{
|
|
205
|
+
date: z.ZodMiniString<string>;
|
|
206
|
+
until: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
207
|
+
hours: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
208
|
+
label: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
209
|
+
}, z.core.$strip>>>;
|
|
210
|
+
priceRange: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
211
|
+
kvk: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
212
|
+
reviewUrl: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
213
|
+
sameAs: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
214
|
+
}, z.core.$strip>>;
|
|
215
|
+
header: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
216
|
+
logo: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
217
|
+
logoHoogte: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
218
|
+
cta: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
219
|
+
label: z.ZodMiniString<string>;
|
|
220
|
+
href: z.ZodMiniString<string>;
|
|
221
|
+
}, z.core.$strip>>;
|
|
222
|
+
sticky: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
223
|
+
mobielBalk: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
224
|
+
}, z.core.$strip>>;
|
|
158
225
|
}, z.core.$loose>;
|
|
159
226
|
/**
|
|
160
227
|
* Valideert een SiteConfig en geeft leesbare issues terug (leeg = geldig). Wordt in development
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod/mini";
|
|
2
|
-
import { NavItemSchema, ThemeSchema, FormsSenderSchema, ModulesSettingsSchema } from "./settings.js";
|
|
2
|
+
import { NavItemSchema, ThemeSchema, FormsSenderSchema, ModulesSettingsSchema, HeaderSettingsSchema } from "./settings.js";
|
|
3
3
|
import { SeoSchema } from "./seo.js";
|
|
4
|
+
import { BusinessSchema } from "./business.js";
|
|
4
5
|
function defineSiteConfig(config) {
|
|
5
6
|
return config;
|
|
6
7
|
}
|
|
@@ -12,6 +13,8 @@ const SiteConfigSchema = z.looseObject({
|
|
|
12
13
|
domain: z.union([z.optional(z.string().check(z.maxLength(255)).check(z.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i, "alleen een hostname, bv. 'www.klant.nl' (zonder https:// of pad)"))), z.literal("")]),
|
|
13
14
|
mode: z.enum(["demo", "live"]),
|
|
14
15
|
demoEditing: z.optional(z.boolean()),
|
|
16
|
+
selfHostFonts: z.optional(z.boolean()),
|
|
17
|
+
paginaOvergang: z.optional(z.enum(["vervagen", "schuiven"])),
|
|
15
18
|
lang: z.optional(z.string().check(z.maxLength(10))),
|
|
16
19
|
locales: z.optional(z.array(z.string().check(z.minLength(2)).check(z.maxLength(10))).check(z.maxLength(10))),
|
|
17
20
|
defaultLocale: z.optional(z.string().check(z.minLength(2)).check(z.maxLength(10))),
|
|
@@ -20,7 +23,9 @@ const SiteConfigSchema = z.looseObject({
|
|
|
20
23
|
contactEmail: z.optional(z.email()),
|
|
21
24
|
seoDefaults: z.optional(SeoSchema),
|
|
22
25
|
forms: z.optional(FormsSenderSchema),
|
|
23
|
-
modules: z.optional(ModulesSettingsSchema)
|
|
26
|
+
modules: z.optional(ModulesSettingsSchema),
|
|
27
|
+
business: z.optional(BusinessSchema),
|
|
28
|
+
header: z.optional(HeaderSettingsSchema)
|
|
24
29
|
});
|
|
25
30
|
function validateSiteConfig(config) {
|
|
26
31
|
const res = SiteConfigSchema.safeParse(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schema/siteConfig.ts"],"sourcesContent":["/**\n * SiteConfig — de statische basisconfig in een klantrepo (`content/site.config.ts`).\n * Dit is de fallback/identiteit van de site; bewerkbare instellingen kunnen in Firebase\n * (`sites/{siteId}/settings/site`) staan en deze waarden overschrijven.\n *\n * `@xiwebdesign/xicms-core` bevat hier nooit klantgegevens — die staan in de klantrepo.\n */\nimport * as z from \"zod/mini\";\nimport { NavItemSchema, ThemeSchema, FormsSenderSchema, ModulesSettingsSchema, type NavItem, type ThemeTokens, type FormsSender } from \"./settings\";\nimport { SeoSchema, type Seo } from \"./seo\";\nimport type { ModulesSiteConfig } from \"../modules/types\";\n\nexport type SiteMode = \"demo\" | \"live\";\n\nexport interface SiteConfig {\n /** Uniek tenant-id; bepaalt het pad `sites/{siteId}/...` in Firebase. */\n siteId: string;\n /** Weergavenaam van het bedrijf. */\n name: string;\n /** Productiedomein, bv. \"www.bakkerijjansen.nl\". */\n domain?: string;\n /** \"demo\" toont de lock/CTA; \"live\" is de productiestand. */\n mode: SiteMode;\n /**\n * Demo-bewerkmodus: toont een pseudo-login zodat bezoekers het beheer (teksten + blokken) kunnen\n * uitproberen. Alle \"bewerkingen\" blijven UITSLUITEND lokaal in de browser (localStorage) — er gaat\n * niets naar Firebase. Alleen bedoeld voor een demo-site; laat dit `false`/weg op echte klantsites.\n */\n demoEditing?: boolean;\n /** Taalcode voor `<html lang>` en a11y (default \"nl\"). */\n lang?: string;\n /**\n * Extra talen naast de default (5.0), bv. `[\"de\", \"en\"]`. Vertalingen leven als overlay op\n * pagina's/symbolen; niet-default talen krijgen een URL-prefix (`/de/over-ons`). Weglaten =\n * ééntalige site (geen overhead).\n */\n locales?: string[];\n /** Default-taal van de canonieke content (default: `lang` ?? \"nl\"). */\n defaultLocale?: string;\n /** Huisstijl. */\n theme: ThemeTokens;\n /** Hoofdnavigatie. */\n nav?: NavItem[];\n /** Contact-e-mailadres voor de demo-CTA en formulieren. */\n contactEmail?: string;\n /** Standaard-SEO als een pagina niets opgeeft. */\n seoDefaults?: Seo;\n /** Afzender-instelling voor formulier-e-mail (fallback voor settings/site). */\n forms?: FormsSender;\n /**\n * Modules per site aan/uit zetten en configureren (XiCMS 3.0). Een uitgezette module verbergt\n * zowel zijn blocks als zijn beheer-paneel. Per module kun je ook `config` meegeven (gevalideerd\n * tegen het `settingsSchema` van de module) zodat de agent gedrag instelt zonder core te forken:\n *\n * modules: {\n * gallery: { enabled: true, config: { lightbox: true, columns: 3 } },\n * stats: false,\n * }\n *\n * Afwezig = de standaard van de module (`defaultEnabled`, doorgaans aan).\n */\n modules?: ModulesSiteConfig;\n}\n\n/** Helper met type-inferentie voor `site.config.ts`. */\nexport function defineSiteConfig(config: SiteConfig): SiteConfig {\n return config;\n}\n\n/**\n * Runtime-spiegel van de `SiteConfig`-interface. TypeScript vangt fouten bij compileren, maar een\n * (agent-)geschreven `site.config.ts` kan alsnog ongeldige waarden bevatten (verkeerd siteId-formaat,\n * te lange strings, kapotte nav-items). `.passthrough()` zodat extra klant-velden nooit een fout zijn.\n */\nexport const SiteConfigSchema = z.looseObject({\n siteId: z.string().check(z.minLength(1)).check(z.maxLength(64)).check(z.regex(/^[a-z0-9][a-z0-9-]*$/, \"gebruik kleine letters/cijfers/koppeltekens (bv. 'bakkerij-jansen')\")),\n name: z.string().check(z.minLength(1)).check(z.maxLength(160)),\n // Alleen een hostname (www.klant.nl) — géén protocol/pad: \"https://…/x\" glipte er eerst\n // doorheen en werd maar half genormaliseerd in siteOrigin/buildMetadata.\n domain: z.union([z.optional(z.string().check(z.maxLength(255)).check(z.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i, \"alleen een hostname, bv. 'www.klant.nl' (zonder https:// of pad)\"))), z.literal(\"\")]),\n mode: z.enum([\"demo\", \"live\"]),\n demoEditing: z.optional(z.boolean()),\n lang: z.optional(z.string().check(z.maxLength(10))),\n locales: z.optional(z.array(z.string().check(z.minLength(2)).check(z.maxLength(10))).check(z.maxLength(10))),\n defaultLocale: z.optional(z.string().check(z.minLength(2)).check(z.maxLength(10))),\n theme: ThemeSchema,\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n contactEmail: z.optional(z.email()),\n seoDefaults: z.optional(SeoSchema),\n forms: z.optional(FormsSenderSchema),\n modules: z.optional(ModulesSettingsSchema),\n });\n\n/**\n * Valideert een SiteConfig en geeft leesbare issues terug (leeg = geldig). Wordt in development\n * door de provider aangeroepen zodat een agent config-fouten direct in de console ziet, in plaats\n * van een subtiel kapotte site. Gooit bewust niet — een issue mag een site nooit platleggen.\n */\nexport function validateSiteConfig(config: unknown): string[] {\n const res = SiteConfigSchema.safeParse(config);\n if (res.success) return [];\n return res.error.issues.map((i) => `${i.path.join(\".\") || \"(root)\"}: ${i.message}`);\n}\n"],"mappings":"AAOA,YAAY,OAAO;AACnB,SAAS,eAAe,aAAa,mBAAmB,
|
|
1
|
+
{"version":3,"sources":["../../src/schema/siteConfig.ts"],"sourcesContent":["/**\n * SiteConfig — de statische basisconfig in een klantrepo (`content/site.config.ts`).\n * Dit is de fallback/identiteit van de site; bewerkbare instellingen kunnen in Firebase\n * (`sites/{siteId}/settings/site`) staan en deze waarden overschrijven.\n *\n * `@xiwebdesign/xicms-core` bevat hier nooit klantgegevens — die staan in de klantrepo.\n */\nimport * as z from \"zod/mini\";\nimport { NavItemSchema, ThemeSchema, FormsSenderSchema, ModulesSettingsSchema, HeaderSettingsSchema, type NavItem, type ThemeTokens, type FormsSender, type HeaderSettings } from \"./settings\";\nimport { SeoSchema, type Seo } from \"./seo\";\nimport { BusinessSchema, type Business } from \"./business\";\nimport type { ModulesSiteConfig } from \"../modules/types\";\n\nexport type SiteMode = \"demo\" | \"live\";\n\nexport interface SiteConfig {\n /** Uniek tenant-id; bepaalt het pad `sites/{siteId}/...` in Firebase. */\n siteId: string;\n /** Weergavenaam van het bedrijf. */\n name: string;\n /** Productiedomein, bv. \"www.bakkerijjansen.nl\". */\n domain?: string;\n /** \"demo\" toont de lock/CTA; \"live\" is de productiestand. */\n mode: SiteMode;\n /**\n * Demo-bewerkmodus: toont een pseudo-login zodat bezoekers het beheer (teksten + blokken) kunnen\n * uitproberen. Alle \"bewerkingen\" blijven UITSLUITEND lokaal in de browser (localStorage) — er gaat\n * niets naar Firebase. Alleen bedoeld voor een demo-site; laat dit `false`/weg op echte klantsites.\n */\n demoEditing?: boolean;\n /**\n * 8.3: Google-lettertypen via de eigen site laden (`/api/fonts`), zodat bezoekers geen verbinding\n * met Google maken. Vereist de route `app/api/fonts/route.ts` (`export { fontsGET as GET }`).\n */\n selfHostFonts?: boolean;\n /**\n * 8.8: rustige overgang tussen pagina's (View Transitions API, via React `<ViewTransition>`).\n * \"vervagen\" = korte crossfade, \"schuiven\" = fade met een kleine verschuiving. Leeg = geen.\n * Browsers zonder ondersteuning wisselen gewoon direct; `prefers-reduced-motion` zet hem uit.\n */\n paginaOvergang?: \"vervagen\" | \"schuiven\";\n /** Taalcode voor `<html lang>` en a11y (default \"nl\"). */\n lang?: string;\n /**\n * Extra talen naast de default (5.0), bv. `[\"de\", \"en\"]`. Vertalingen leven als overlay op\n * pagina's/symbolen; niet-default talen krijgen een URL-prefix (`/de/over-ons`). Weglaten =\n * ééntalige site (geen overhead).\n */\n locales?: string[];\n /** Default-taal van de canonieke content (default: `lang` ?? \"nl\"). */\n defaultLocale?: string;\n /** Huisstijl. */\n theme: ThemeTokens;\n /** Hoofdnavigatie. */\n nav?: NavItem[];\n /** Contact-e-mailadres voor de demo-CTA en formulieren. */\n contactEmail?: string;\n /** Standaard-SEO als een pagina niets opgeeft. */\n seoDefaults?: Seo;\n /** Afzender-instelling voor formulier-e-mail (fallback voor settings/site). */\n forms?: FormsSender;\n /**\n * Modules per site aan/uit zetten en configureren (XiCMS 3.0). Een uitgezette module verbergt\n * zowel zijn blocks als zijn beheer-paneel. Per module kun je ook `config` meegeven (gevalideerd\n * tegen het `settingsSchema` van de module) zodat de agent gedrag instelt zonder core te forken:\n *\n * modules: {\n * gallery: { enabled: true, config: { lightbox: true, columns: 3 } },\n * stats: false,\n * }\n *\n * Afwezig = de standaard van de module (`defaultEnabled`, doorgaans aan).\n */\n modules?: ModulesSiteConfig;\n /**\n * 8.13: het bedrijfsprofiel als startwaarde (adres, telefoon, openingstijden). Wat de klant in\n * /beheer → Instellingen → Bedrijf opslaat, wint. Zie `schema/business.ts`.\n */\n business?: Business;\n /** 8.13: startwaarde voor de kop (`SiteHeader`): logo, actieknop, mobiele balk. */\n header?: HeaderSettings;\n}\n\n/** Helper met type-inferentie voor `site.config.ts`. */\nexport function defineSiteConfig(config: SiteConfig): SiteConfig {\n return config;\n}\n\n/**\n * Runtime-spiegel van de `SiteConfig`-interface. TypeScript vangt fouten bij compileren, maar een\n * (agent-)geschreven `site.config.ts` kan alsnog ongeldige waarden bevatten (verkeerd siteId-formaat,\n * te lange strings, kapotte nav-items). `.passthrough()` zodat extra klant-velden nooit een fout zijn.\n */\nexport const SiteConfigSchema = z.looseObject({\n siteId: z.string().check(z.minLength(1)).check(z.maxLength(64)).check(z.regex(/^[a-z0-9][a-z0-9-]*$/, \"gebruik kleine letters/cijfers/koppeltekens (bv. 'bakkerij-jansen')\")),\n name: z.string().check(z.minLength(1)).check(z.maxLength(160)),\n // Alleen een hostname (www.klant.nl) — géén protocol/pad: \"https://…/x\" glipte er eerst\n // doorheen en werd maar half genormaliseerd in siteOrigin/buildMetadata.\n domain: z.union([z.optional(z.string().check(z.maxLength(255)).check(z.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i, \"alleen een hostname, bv. 'www.klant.nl' (zonder https:// of pad)\"))), z.literal(\"\")]),\n mode: z.enum([\"demo\", \"live\"]),\n demoEditing: z.optional(z.boolean()),\n selfHostFonts: z.optional(z.boolean()),\n paginaOvergang: z.optional(z.enum([\"vervagen\", \"schuiven\"])),\n lang: z.optional(z.string().check(z.maxLength(10))),\n locales: z.optional(z.array(z.string().check(z.minLength(2)).check(z.maxLength(10))).check(z.maxLength(10))),\n defaultLocale: z.optional(z.string().check(z.minLength(2)).check(z.maxLength(10))),\n theme: ThemeSchema,\n nav: z.optional(z.array(NavItemSchema).check(z.maxLength(50))),\n contactEmail: z.optional(z.email()),\n seoDefaults: z.optional(SeoSchema),\n forms: z.optional(FormsSenderSchema),\n modules: z.optional(ModulesSettingsSchema),\n business: z.optional(BusinessSchema),\n header: z.optional(HeaderSettingsSchema),\n });\n\n/**\n * Valideert een SiteConfig en geeft leesbare issues terug (leeg = geldig). Wordt in development\n * door de provider aangeroepen zodat een agent config-fouten direct in de console ziet, in plaats\n * van een subtiel kapotte site. Gooit bewust niet — een issue mag een site nooit platleggen.\n */\nexport function validateSiteConfig(config: unknown): string[] {\n const res = SiteConfigSchema.safeParse(config);\n if (res.success) return [];\n return res.error.issues.map((i) => `${i.path.join(\".\") || \"(root)\"}: ${i.message}`);\n}\n"],"mappings":"AAOA,YAAY,OAAO;AACnB,SAAS,eAAe,aAAa,mBAAmB,uBAAuB,4BAAmG;AAClL,SAAS,iBAA2B;AACpC,SAAS,sBAAqC;AA0EvC,SAAS,iBAAiB,QAAgC;AAC/D,SAAO;AACT;AAOO,MAAM,mBAAmB,EAAE,YAAY;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,wBAAwB,qEAAqE,CAAC;AAAA,EAC5K,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC;AAAA;AAAA;AAAA,EAG7D,QAAQ,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,sEAAsE,kEAAkE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;AAAA,EACxO,MAAM,EAAE,KAAK,CAAC,QAAQ,MAAM,CAAC;AAAA,EAC7B,aAAa,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EACnC,eAAe,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EACrC,gBAAgB,EAAE,SAAS,EAAE,KAAK,CAAC,YAAY,UAAU,CAAC,CAAC;AAAA,EAC3D,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAAA,EAClD,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAAA,EAC3G,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAAA,EACjF,OAAO;AAAA,EACP,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAAA,EAC7D,cAAc,EAAE,SAAS,EAAE,MAAM,CAAC;AAAA,EAClC,aAAa,EAAE,SAAS,SAAS;AAAA,EACjC,OAAO,EAAE,SAAS,iBAAiB;AAAA,EACnC,SAAS,EAAE,SAAS,qBAAqB;AAAA,EACzC,UAAU,EAAE,SAAS,cAAc;AAAA,EACnC,QAAQ,EAAE,SAAS,oBAAoB;AACzC,CAAC;AAOI,SAAS,mBAAmB,QAA2B;AAC5D,QAAM,MAAM,iBAAiB,UAAU,MAAM;AAC7C,MAAI,IAAI,QAAS,QAAO,CAAC;AACzB,SAAO,IAAI,MAAM,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,KAAK,GAAG,KAAK,QAAQ,KAAK,EAAE,OAAO,EAAE;AACpF;","names":[]}
|
|
@@ -14,4 +14,4 @@ export interface PageBlockDataOptions {
|
|
|
14
14
|
* Geef het resultaat door als `<PublishedPage blockData={...}>`. `undefined`-namespaces blijven
|
|
15
15
|
* weg zodat de blokken hun eigen fallback houden waar deze functie niets voor verzamelde.
|
|
16
16
|
*/
|
|
17
|
-
export declare function getPageBlockData(siteId: string, page: Pick<Page, "blocks"
|
|
17
|
+
export declare function getPageBlockData(siteId: string, page: Pick<Page, "blocks"> & Partial<Pick<Page, "path">>, opts?: PageBlockDataOptions): Promise<Record<string, unknown> | undefined>;
|