@xiwebdesign/xicms-core 6.4.7 → 7.0.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/SiteChrome.d.ts +12 -0
- package/dist/SiteChrome.js +24 -0
- package/dist/SiteChrome.js.map +1 -0
- package/dist/XiCMSProvider.d.ts +16 -8
- package/dist/XiCMSProvider.js +83 -58
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.d.ts +1 -1
- package/dist/admin/AdminApp.js +79 -35
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +8 -1
- package/dist/admin/AdminHelp.js +2 -2
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/NewsEditor.js +9 -9
- package/dist/admin/SuperadminPanel.js +5 -5
- package/dist/admin/blockEditors/GenericEditor.d.ts +2 -2
- package/dist/admin/blockEditors/GenericEditor.js +12 -11
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.d.ts +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +2 -2
- package/dist/admin/blockEditors/SymbolRefEditor.d.ts +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +5 -5
- package/dist/admin/blockEditors/index.d.ts +1 -1
- package/dist/admin/blockEditors/index.js +10 -10
- package/dist/admin/customBlocks/CustomBlocksPanel.js +7 -7
- package/dist/admin/editors/RichTextEditor.js +8 -7
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +1 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/forms/FormsPanel.js +9 -9
- package/dist/admin/index.d.ts +16 -16
- package/dist/admin/index.js +16 -16
- package/dist/admin/lib/mediaUsage.js +1 -1
- package/dist/admin/lib/pagesClient.d.ts +1 -1
- package/dist/admin/lib/pagesClient.js +11 -7
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/sanitizeDraft.d.ts +9 -0
- package/dist/admin/lib/sanitizeDraft.js +28 -0
- package/dist/admin/lib/sanitizeDraft.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +1 -1
- package/dist/admin/lib/symbolsClient.js +3 -3
- package/dist/admin/lib/upload.js +3 -3
- package/dist/admin/lib/useNestedDialog.d.ts +15 -0
- package/dist/admin/lib/useNestedDialog.js +23 -0
- package/dist/admin/lib/useNestedDialog.js.map +1 -0
- package/dist/admin/lib/zodFields.d.ts +4 -18
- package/dist/admin/lib/zodFields.js +54 -35
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/media/MediaManager.js +7 -7
- package/dist/admin/media/MediaPicker.js +7 -7
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/pages/PageEditor.d.ts +1 -1
- package/dist/admin/pages/PageEditor.js +13 -13
- package/dist/admin/pages/PagesPanel.js +30 -30
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/panelRegistry.js +7 -7
- package/dist/admin/patterns/PatternInserter.d.ts +1 -1
- package/dist/admin/patterns/PatternInserter.js +5 -5
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/MailSettings.js +5 -5
- package/dist/admin/settings/MailTemplates.d.ts +1 -1
- package/dist/admin/settings/MailTemplates.js +5 -5
- package/dist/admin/settings/SettingsPanel.js +20 -20
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +5 -5
- package/dist/admin/settings/moduleSettingsForm.d.ts +1 -1
- package/dist/admin/settings/moduleSettingsForm.js +4 -4
- package/dist/admin/settings/moduleSettingsForm.js.map +1 -1
- package/dist/admin/shop/CategoriesTab.js +8 -8
- package/dist/admin/shop/ConnectionsTab.js +3 -3
- package/dist/admin/shop/DiscountsTab.js +8 -8
- package/dist/admin/shop/OrdersTab.js +10 -10
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +10 -10
- package/dist/admin/shop/ShopPanel.js +9 -9
- package/dist/admin/shop/ShopSettingsTab.js +4 -4
- package/dist/admin/shop/index.d.ts +2 -2
- package/dist/admin/shop/index.js +2 -2
- package/dist/admin/shop/lib.js +2 -2
- package/dist/admin/stats/StatsPanel.js +2 -2
- package/dist/admin/ui/ArrayEditor.js +1 -1
- package/dist/admin/ui/PanelIcon.d.ts +3 -0
- package/dist/admin/ui/PanelIcon.js +34 -0
- package/dist/admin/ui/PanelIcon.js.map +1 -0
- package/dist/admin/ui/dialog.d.ts +21 -6
- package/dist/admin/ui/dialog.js +55 -34
- package/dist/admin/ui/dialog.js.map +1 -1
- package/dist/admin/ui/index.d.ts +7 -7
- package/dist/admin/ui/index.js +7 -7
- package/dist/admin/ui/primitives.js +1 -1
- package/dist/admin/ui/tabs.js +1 -1
- package/dist/admin/visual/TranslationPanel.d.ts +1 -1
- package/dist/admin/visual/TranslationPanel.js +3 -3
- package/dist/admin/visual/VisualEditor.js +47 -25
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +2 -1
- package/dist/agentFiles/catalog.d.ts +2 -2
- package/dist/agentFiles/catalog.js +6 -5
- package/dist/agentFiles/catalog.js.map +1 -1
- package/dist/agentFiles/files.d.ts +5 -5
- package/dist/agentFiles/files.js +17 -17
- package/dist/agentFiles/files.js.map +1 -1
- package/dist/all.d.ts +4 -4
- package/dist/all.js +6 -6
- package/dist/auth/AuthProvider.d.ts +2 -2
- package/dist/auth/AuthProvider.js +51 -28
- package/dist/auth/AuthProvider.js.map +1 -1
- package/dist/auth/LoginForm.js +1 -1
- package/dist/auth/roles.js +4 -1
- package/dist/auth/roles.js.map +1 -1
- package/dist/blocks/BlockRenderer.d.ts +1 -1
- package/dist/blocks/BlockRenderer.js +3 -3
- package/dist/blocks/blockStyle.d.ts +1 -1
- package/dist/blocks/builtins/Accordion.d.ts +1 -1
- package/dist/blocks/builtins/Accordion.js +13 -6
- package/dist/blocks/builtins/Accordion.js.map +1 -1
- package/dist/blocks/builtins/Agenda.d.ts +1 -1
- package/dist/blocks/builtins/Agenda.js +5 -5
- package/dist/blocks/builtins/Banner.d.ts +1 -1
- package/dist/blocks/builtins/Banner.js +2 -2
- package/dist/blocks/builtins/BeforeAfter.d.ts +1 -1
- package/dist/blocks/builtins/BeforeAfter.js +4 -4
- package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
- package/dist/blocks/builtins/Booking.d.ts +1 -1
- package/dist/blocks/builtins/Booking.js +5 -5
- package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -1
- package/dist/blocks/builtins/Breadcrumbs.js +3 -3
- package/dist/blocks/builtins/Cards.d.ts +1 -1
- package/dist/blocks/builtins/Cards.js +5 -5
- package/dist/blocks/builtins/Cards.js.map +1 -1
- package/dist/blocks/builtins/Columns.d.ts +1 -1
- package/dist/blocks/builtins/Columns.js +4 -4
- package/dist/blocks/builtins/Contact.d.ts +3 -3
- package/dist/blocks/builtins/Contact.js +4 -4
- package/dist/blocks/builtins/Countdown.d.ts +1 -1
- package/dist/blocks/builtins/Countdown.js +4 -4
- package/dist/blocks/builtins/Countdown.js.map +1 -1
- package/dist/blocks/builtins/Cta.d.ts +1 -1
- package/dist/blocks/builtins/Cta.js +3 -3
- package/dist/blocks/builtins/Downloads.d.ts +1 -1
- package/dist/blocks/builtins/Downloads.js +4 -4
- package/dist/blocks/builtins/Elements.d.ts +3 -3
- package/dist/blocks/builtins/Elements.js +3 -3
- package/dist/blocks/builtins/Embed.d.ts +1 -1
- package/dist/blocks/builtins/Embed.js +3 -3
- package/dist/blocks/builtins/Faq.d.ts +1 -1
- package/dist/blocks/builtins/Faq.js +14 -6
- package/dist/blocks/builtins/Faq.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.d.ts +1 -1
- package/dist/blocks/builtins/FormBlock.js +28 -18
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/Gallery.d.ts +2 -2
- package/dist/blocks/builtins/Gallery.js +5 -5
- package/dist/blocks/builtins/Hero.d.ts +1 -1
- package/dist/blocks/builtins/Hero.js +4 -4
- package/dist/blocks/builtins/ImageBlock.d.ts +1 -1
- package/dist/blocks/builtins/ImageBlock.js +3 -3
- package/dist/blocks/builtins/Jobs.d.ts +2 -2
- package/dist/blocks/builtins/Jobs.js +5 -5
- package/dist/blocks/builtins/Layout.d.ts +2 -2
- package/dist/blocks/builtins/Layout.js +4 -4
- package/dist/blocks/builtins/MapBlock.d.ts +1 -1
- package/dist/blocks/builtins/MapBlock.js +3 -3
- package/dist/blocks/builtins/NewsListBlock.d.ts +1 -1
- package/dist/blocks/builtins/NewsListBlock.js +4 -4
- package/dist/blocks/builtins/Newsletter.d.ts +1 -1
- package/dist/blocks/builtins/Newsletter.js +7 -7
- package/dist/blocks/builtins/Newsletter.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +1 -1
- package/dist/blocks/builtins/OpenNowBadge.js +8 -3
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHours.d.ts +1 -1
- package/dist/blocks/builtins/OpeningHours.js +6 -6
- package/dist/blocks/builtins/PdfBlock.d.ts +1 -1
- package/dist/blocks/builtins/PdfBlock.js +3 -3
- package/dist/blocks/builtins/Portfolio.d.ts +1 -1
- package/dist/blocks/builtins/Portfolio.js +5 -5
- package/dist/blocks/builtins/Pricing.d.ts +2 -2
- package/dist/blocks/builtins/Pricing.js +5 -5
- package/dist/blocks/builtins/Pricing.js.map +1 -1
- package/dist/blocks/builtins/RichTextBlock.d.ts +1 -1
- package/dist/blocks/builtins/RichTextBlock.js +2 -2
- package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
- package/dist/blocks/builtins/Search.d.ts +1 -1
- package/dist/blocks/builtins/Search.js +9 -7
- package/dist/blocks/builtins/Search.js.map +1 -1
- package/dist/blocks/builtins/Sections.d.ts +4 -4
- package/dist/blocks/builtins/Sections.js +4 -4
- package/dist/blocks/builtins/Slider.d.ts +1 -1
- package/dist/blocks/builtins/Slider.js +3 -3
- package/dist/blocks/builtins/Spacer.d.ts +1 -1
- package/dist/blocks/builtins/Spacer.js +2 -2
- package/dist/blocks/builtins/SymbolRef.d.ts +1 -1
- package/dist/blocks/builtins/SymbolRef.js +31 -17
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/Team.d.ts +1 -1
- package/dist/blocks/builtins/Team.js +4 -4
- package/dist/blocks/builtins/Testimonials.d.ts +2 -2
- package/dist/blocks/builtins/Testimonials.js +4 -4
- package/dist/blocks/builtins/Video.d.ts +2 -2
- package/dist/blocks/builtins/Video.js +4 -4
- package/dist/blocks/builtins/Video.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChat.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChat.js +2 -2
- package/dist/blocks/builtins/Widgets.d.ts +12 -12
- package/dist/blocks/builtins/Widgets.js +19 -19
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/consentEmbed.js +2 -2
- package/dist/blocks/builtins/index.d.ts +40 -40
- package/dist/blocks/builtins/index.js +40 -40
- package/dist/blocks/builtins/lib/submitForm.js +5 -3
- package/dist/blocks/builtins/lib/submitForm.js.map +1 -1
- package/dist/blocks/context.d.ts +1 -1
- package/dist/blocks/customTemplate/definition.d.ts +3 -3
- package/dist/blocks/customTemplate/definition.js +6 -6
- package/dist/blocks/customTemplate/definition.js.map +1 -1
- package/dist/blocks/customTemplate/interpret.js +1 -1
- package/dist/blocks/index.d.ts +5 -5
- package/dist/blocks/index.js +5 -5
- package/dist/blocks/registry.d.ts +17 -7
- package/dist/blocks/registry.js +2 -1
- package/dist/blocks/registry.js.map +1 -1
- package/dist/components/EditBar.js +3 -3
- package/dist/components/FeedbackWidget.js +4 -4
- package/dist/components/News.d.ts +1 -1
- package/dist/components/News.js +50 -37
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.js +11 -8
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.d.ts +1 -1
- package/dist/components/site/SiteFooter.d.ts +1 -1
- package/dist/components/site/SiteFooter.js +2 -2
- package/dist/config.d.ts +1 -1
- package/dist/demo/DemoStudio.js +3 -3
- package/dist/demo/demoStore.d.ts +3 -3
- package/dist/demo/index.d.ts +2 -2
- package/dist/demo/index.js +2 -2
- package/dist/editor/EditorProvider.js +1 -1
- package/dist/firebase/admin.d.ts +0 -2
- package/dist/firebase/admin.js +0 -6
- package/dist/firebase/admin.js.map +1 -1
- package/dist/firebase/appcheck.d.ts +1 -1
- package/dist/firebase/appcheck.js +5 -3
- package/dist/firebase/appcheck.js.map +1 -1
- package/dist/firebase/client.d.ts +2 -1
- package/dist/firebase/client.js +2 -14
- package/dist/firebase/client.js.map +1 -1
- package/dist/firebase/config.d.ts +31 -0
- package/dist/firebase/config.js +39 -0
- package/dist/firebase/config.js.map +1 -0
- package/dist/firebase/feedback.js +5 -3
- package/dist/firebase/feedback.js.map +1 -1
- package/dist/i18n/overlay.d.ts +2 -2
- package/dist/i18n/overlay.js +6 -4
- package/dist/i18n/overlay.js.map +1 -1
- package/dist/index.d.ts +45 -44
- package/dist/index.js +35 -33
- package/dist/index.js.map +1 -1
- package/dist/lock/DemoLock.js +1 -1
- package/dist/modules/builtins.d.ts +1 -1
- package/dist/modules/builtins.js +53 -55
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/consent/ConsentBanner.js +1 -1
- package/dist/modules/consent/useConsent.js +1 -1
- package/dist/modules/context.d.ts +1 -1
- package/dist/modules/contract.d.ts +1 -1
- package/dist/modules/defineModule.d.ts +1 -1
- package/dist/modules/index.d.ts +9 -9
- package/dist/modules/index.js +8 -8
- package/dist/modules/overrides.d.ts +1 -1
- package/dist/modules/registry.d.ts +2 -7
- package/dist/modules/registry.js +2 -1
- package/dist/modules/registry.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.d.ts +1 -1
- package/dist/modules/shop/blocks/Cart.js +6 -6
- package/dist/modules/shop/blocks/Checkout.d.ts +1 -1
- package/dist/modules/shop/blocks/Checkout.js +6 -6
- package/dist/modules/shop/blocks/Donation.d.ts +1 -1
- package/dist/modules/shop/blocks/Donation.js +5 -5
- package/dist/modules/shop/blocks/OrderStatus.d.ts +1 -1
- package/dist/modules/shop/blocks/OrderStatus.js +5 -5
- package/dist/modules/shop/blocks/ProductDetail.d.ts +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +8 -8
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -3
- package/dist/modules/shop/blocks/ProductGrid.js +7 -7
- package/dist/modules/shop/blocks/ShopCategories.d.ts +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +6 -6
- package/dist/modules/shop/index.d.ts +5 -5
- package/dist/modules/shop/index.js +5 -5
- package/dist/modules/shop/lib.d.ts +2 -2
- package/dist/modules/shop/lib.js +18 -13
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/module.d.ts +1 -1
- package/dist/modules/shop/module.js +9 -9
- package/dist/modules/shop/settings.d.ts +18 -50
- package/dist/modules/shop/settings.js +16 -16
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.js +1 -1
- package/dist/modules/shop/types.d.ts +1 -1
- package/dist/modules/types.d.ts +2 -2
- package/dist/patterns/builtins.d.ts +1 -1
- package/dist/patterns/builtins.js +1 -1
- package/dist/patterns/index.d.ts +2 -2
- package/dist/patterns/index.js +2 -2
- package/dist/render/PageRenderer.d.ts +2 -2
- package/dist/render/PageRenderer.js +1 -1
- package/dist/render/PublishedPage.d.ts +1 -1
- package/dist/render/PublishedPage.js +2 -2
- package/dist/schema/blocks.d.ts +6793 -15095
- package/dist/schema/blocks.js +335 -355
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/customBlocks.d.ts +10 -29
- package/dist/schema/customBlocks.js +14 -13
- package/dist/schema/customBlocks.js.map +1 -1
- package/dist/schema/fields.d.ts +10 -16
- package/dist/schema/fields.js +37 -37
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +62 -111
- package/dist/schema/forms.js +17 -17
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/index.d.ts +7 -7
- package/dist/schema/index.js +7 -7
- package/dist/schema/mail.d.ts +39 -87
- package/dist/schema/mail.js +4 -4
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/pages.d.ts +152 -674
- package/dist/schema/pages.js +26 -15
- package/dist/schema/pages.js.map +1 -1
- package/dist/schema/seo.d.ts +9 -27
- package/dist/schema/seo.js +7 -7
- package/dist/schema/seo.js.map +1 -1
- package/dist/schema/settings.d.ts +218 -1074
- package/dist/schema/settings.js +55 -55
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +470 -1214
- package/dist/schema/shop.js +124 -124
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +73 -597
- package/dist/schema/siteConfig.js +17 -17
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/schema/symbols.d.ts +34 -191
- package/dist/schema/symbols.js +8 -8
- package/dist/schema/symbols.js.map +1 -1
- package/dist/server/auth.d.ts +17 -0
- package/dist/server/auth.js +11 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/bundle.d.ts +15 -6
- package/dist/server/bundle.js +5 -1
- package/dist/server/bundle.js.map +1 -1
- package/dist/server/draft.d.ts +16 -0
- package/dist/server/draft.js +12 -0
- package/dist/server/draft.js.map +1 -0
- package/dist/server/env.js +8 -8
- package/dist/server/env.js.map +1 -1
- package/dist/server/index.d.ts +10 -8
- package/dist/server/index.js +12 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/pages.d.ts +14 -7
- package/dist/server/pages.js +183 -17
- package/dist/server/pages.js.map +1 -1
- package/dist/server/revalidate.d.ts +6 -0
- package/dist/server/revalidate.js +40 -0
- package/dist/server/revalidate.js.map +1 -0
- package/dist/server/seo.d.ts +3 -3
- package/dist/server/seo.js +1 -1
- package/dist/server/shop.d.ts +3 -3
- package/dist/server/shop.js +6 -3
- package/dist/server/shop.js.map +1 -1
- package/dist/settings/useSiteSettings.d.ts +2 -2
- package/dist/settings/useSiteSettings.js +48 -28
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/styles.css +4 -1
- package/dist/theme/presets.d.ts +1 -1
- package/package.json +35 -34
|
@@ -3,11 +3,11 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { collection, limit, onSnapshot, orderBy, query } from "firebase/firestore";
|
|
5
5
|
import { getFunctions, httpsCallable } from "firebase/functions";
|
|
6
|
-
import { getDb, getFirebaseApp } from "../../firebase/client";
|
|
7
|
-
import { functionsRegion } from "../../firebase/region";
|
|
8
|
-
import { Button, Card, Input } from "../ui/primitives";
|
|
9
|
-
import { useToast } from "../ui/toast";
|
|
10
|
-
import { useConfirm } from "../ui/ConfirmDialog";
|
|
6
|
+
import { getDb, getFirebaseApp } from "../../firebase/client.js";
|
|
7
|
+
import { functionsRegion } from "../../firebase/region.js";
|
|
8
|
+
import { Button, Card, Input } from "../ui/primitives.js";
|
|
9
|
+
import { useToast } from "../ui/toast.js";
|
|
10
|
+
import { useConfirm } from "../ui/ConfirmDialog.js";
|
|
11
11
|
function formatDate(createdAt) {
|
|
12
12
|
const date = createdAt && typeof createdAt.toDate === "function" ? createdAt.toDate() : null;
|
|
13
13
|
return date ? date.toLocaleString("nl-NL", { dateStyle: "short", timeStyle: "short" }) : "";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ZodTypeAny } from "zod";
|
|
1
|
+
import type { $ZodType as ZodTypeAny } from "zod/v4/core";
|
|
2
2
|
/**
|
|
3
3
|
* Generiek instellingen-formulier voor een module op basis van zijn `settingsSchema`. Ondersteunt
|
|
4
4
|
* primitieve velden (getal/boolean/tekst/enum) met leesbare labels via `.describe("…")` op het
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Field, Input } from "../ui/primitives";
|
|
4
|
-
import { Select } from "../ui/select";
|
|
5
|
-
import { Switch } from "../ui/switch";
|
|
6
|
-
import { introspectObjectSchema } from "../lib/zodFields";
|
|
3
|
+
import { Field, Input } from "../ui/primitives.js";
|
|
4
|
+
import { Select } from "../ui/select.js";
|
|
5
|
+
import { Switch } from "../ui/switch.js";
|
|
6
|
+
import { introspectObjectSchema } from "../lib/zodFields.js";
|
|
7
7
|
function ModuleSettingsForm({
|
|
8
8
|
schema,
|
|
9
9
|
value,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/settings/moduleSettingsForm.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ZodTypeAny } from \"zod\";\nimport { Field, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { introspectObjectSchema } from \"../lib/zodFields\";\n\n/**\n * Generiek instellingen-formulier voor een module op basis van zijn `settingsSchema`. Ondersteunt\n * primitieve velden (getal/boolean/tekst/enum) met leesbare labels via `.describe(\"…\")` op het\n * schema. Complexe velden (arrays/objects) blijven via site.config/code beheerd — bewust foolproof\n * gehouden voor de klant (de GenericEditor voor blokken biedt daar wél een JSON-vangnet).\n */\nexport function ModuleSettingsForm({\n schema,\n value,\n onChange,\n}: {\n schema: ZodTypeAny;\n value: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n}) {\n const fields = introspectObjectSchema(schema).filter((f) => f.kind !== \"json\");\n if (fields.length === 0) return null;\n const set = (key: string, v: unknown) => onChange({ ...value, [key]: v });\n\n return (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {fields.map((f) => {\n if (f.kind === \"boolean\") {\n return (\n <label key={f.key} className=\"flex items-center gap-2 text-sm\">\n <Switch checked={Boolean(value[f.key])} onCheckedChange={(v) => set(f.key, v)} />\n {f.label}\n </label>\n );\n }\n if (f.kind === \"enum\") {\n return (\n <Field key={f.key} label={f.label}>\n <Select\n value={String(value[f.key] ?? f.options?.[0] ?? \"\")}\n onValueChange={(v) => set(f.key, v)}\n options={(f.options ?? []).map((o) => ({ value: o, label: o }))}\n />\n </Field>\n );\n }\n return (\n <Field key={f.key} label={f.label}>\n <Input\n type={f.kind === \"number\" ? \"number\" : \"text\"}\n value={String(value[f.key] ?? \"\")}\n onChange={(e) => set(f.key, f.kind === \"number\" ? Number(e.target.value) : e.target.value)}\n />\n </Field>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AAgCY,SACE,KADF;AA7BZ,SAAS,OAAO,aAAa;AAC7B,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,8BAA8B;AAQhC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,uBAAuB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAC7E,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,CAAC,KAAa,MAAe,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;AAExE,SACE,oBAAC,SAAI,WAAU,6BACZ,iBAAO,IAAI,CAAC,MAAM;AACjB,QAAI,EAAE,SAAS,WAAW;AACxB,aACE,qBAAC,WAAkB,WAAU,mCAC3B;AAAA,4BAAC,UAAO,SAAS,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,GAAG;AAAA,QAC9E,EAAE;AAAA,WAFO,EAAE,GAGd;AAAA,IAEJ;AACA,QAAI,EAAE,SAAS,QAAQ;AACrB,aACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE;AAAA,UAClD,eAAe,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,UAClC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE;AAAA;AAAA,MAChE,KALU,EAAE,GAMd;AAAA,IAEJ;AACA,WACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,EAAE,SAAS,WAAW,WAAW;AAAA,QACvC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE;AAAA,QAChC,UAAU,CAAC,MAAM,IAAI,EAAE,KAAK,EAAE,SAAS,WAAW,OAAO,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK;AAAA;AAAA,IAC3F,KALU,EAAE,GAMd;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/settings/moduleSettingsForm.tsx"],"sourcesContent":["\"use client\";\n\nimport type { $ZodType as ZodTypeAny } from \"zod/v4/core\";\nimport { Field, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { introspectObjectSchema } from \"../lib/zodFields\";\n\n/**\n * Generiek instellingen-formulier voor een module op basis van zijn `settingsSchema`. Ondersteunt\n * primitieve velden (getal/boolean/tekst/enum) met leesbare labels via `.describe(\"…\")` op het\n * schema. Complexe velden (arrays/objects) blijven via site.config/code beheerd — bewust foolproof\n * gehouden voor de klant (de GenericEditor voor blokken biedt daar wél een JSON-vangnet).\n */\nexport function ModuleSettingsForm({\n schema,\n value,\n onChange,\n}: {\n schema: ZodTypeAny;\n value: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n}) {\n const fields = introspectObjectSchema(schema).filter((f) => f.kind !== \"json\");\n if (fields.length === 0) return null;\n const set = (key: string, v: unknown) => onChange({ ...value, [key]: v });\n\n return (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {fields.map((f) => {\n if (f.kind === \"boolean\") {\n return (\n <label key={f.key} className=\"flex items-center gap-2 text-sm\">\n <Switch checked={Boolean(value[f.key])} onCheckedChange={(v) => set(f.key, v)} />\n {f.label}\n </label>\n );\n }\n if (f.kind === \"enum\") {\n return (\n <Field key={f.key} label={f.label}>\n <Select\n value={String(value[f.key] ?? f.options?.[0] ?? \"\")}\n onValueChange={(v) => set(f.key, v)}\n options={(f.options ?? []).map((o) => ({ value: o, label: o }))}\n />\n </Field>\n );\n }\n return (\n <Field key={f.key} label={f.label}>\n <Input\n type={f.kind === \"number\" ? \"number\" : \"text\"}\n value={String(value[f.key] ?? \"\")}\n onChange={(e) => set(f.key, f.kind === \"number\" ? Number(e.target.value) : e.target.value)}\n />\n </Field>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AAgCY,SACE,KADF;AA7BZ,SAAS,OAAO,aAAa;AAC7B,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,8BAA8B;AAQhC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,uBAAuB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAC7E,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,CAAC,KAAa,MAAe,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;AAExE,SACE,oBAAC,SAAI,WAAU,6BACZ,iBAAO,IAAI,CAAC,MAAM;AACjB,QAAI,EAAE,SAAS,WAAW;AACxB,aACE,qBAAC,WAAkB,WAAU,mCAC3B;AAAA,4BAAC,UAAO,SAAS,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,GAAG;AAAA,QAC9E,EAAE;AAAA,WAFO,EAAE,GAGd;AAAA,IAEJ;AACA,QAAI,EAAE,SAAS,QAAQ;AACrB,aACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE;AAAA,UAClD,eAAe,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,UAClC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE;AAAA;AAAA,MAChE,KALU,EAAE,GAMd;AAAA,IAEJ;AACA,WACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,EAAE,SAAS,WAAW,WAAW;AAAA,QACvC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE;AAAA,QAChC,UAAU,CAAC,MAAM,IAAI,EAAE,KAAK,EAAE,SAAS,WAAW,OAAO,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK;AAAA;AAAA,IAC3F,KALU,EAAE,GAMd;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { addDoc, collection, deleteDoc, doc, onSnapshot, setDoc } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
6
|
-
import { ShopCategorySchema } from "../../schema/shop";
|
|
7
|
-
import { Button, Card, Field, Input, Textarea } from "../ui/primitives";
|
|
8
|
-
import { Switch } from "../ui/switch";
|
|
9
|
-
import { useToast } from "../ui/toast";
|
|
10
|
-
import { useConfirm } from "../ui/ConfirmDialog";
|
|
11
|
-
import { MediaPickerButton } from "../media/MediaPicker";
|
|
12
|
-
import { slugify } from "../lib/slugify";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
|
+
import { ShopCategorySchema } from "../../schema/shop.js";
|
|
7
|
+
import { Button, Card, Field, Input, Textarea } from "../ui/primitives.js";
|
|
8
|
+
import { Switch } from "../ui/switch.js";
|
|
9
|
+
import { useToast } from "../ui/toast.js";
|
|
10
|
+
import { useConfirm } from "../ui/ConfirmDialog.js";
|
|
11
|
+
import { MediaPickerButton } from "../media/MediaPicker.js";
|
|
12
|
+
import { slugify } from "../lib/slugify.js";
|
|
13
13
|
function CategoriesTab({ siteId }) {
|
|
14
14
|
const { toast } = useToast();
|
|
15
15
|
const confirm = useConfirm();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
|
-
import { Badge, Button, Card, Field, Input } from "../ui/primitives";
|
|
5
|
-
import { useToast } from "../ui/toast";
|
|
6
|
-
import { shopCallable } from "./lib";
|
|
4
|
+
import { Badge, Button, Card, Field, Input } from "../ui/primitives.js";
|
|
5
|
+
import { useToast } from "../ui/toast.js";
|
|
6
|
+
import { shopCallable } from "./lib.js";
|
|
7
7
|
function Segmented({
|
|
8
8
|
value,
|
|
9
9
|
options,
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { collection, deleteDoc, doc, onSnapshot, setDoc } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
6
|
-
import { DiscountCodeSchema, formatCents } from "../../schema/shop";
|
|
7
|
-
import { Badge, Button, Card, Field, Input } from "../ui/primitives";
|
|
8
|
-
import { Select } from "../ui/select";
|
|
9
|
-
import { Switch } from "../ui/switch";
|
|
10
|
-
import { useToast } from "../ui/toast";
|
|
11
|
-
import { useConfirm } from "../ui/ConfirmDialog";
|
|
12
|
-
import { centsToEuroInput, eurosToCents } from "./lib";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
|
+
import { DiscountCodeSchema, formatCents } from "../../schema/shop.js";
|
|
7
|
+
import { Badge, Button, Card, Field, Input } from "../ui/primitives.js";
|
|
8
|
+
import { Select } from "../ui/select.js";
|
|
9
|
+
import { Switch } from "../ui/switch.js";
|
|
10
|
+
import { useToast } from "../ui/toast.js";
|
|
11
|
+
import { useConfirm } from "../ui/ConfirmDialog.js";
|
|
12
|
+
import { centsToEuroInput, eurosToCents } from "./lib.js";
|
|
13
13
|
function DiscountsTab({ siteId }) {
|
|
14
14
|
const { toast } = useToast();
|
|
15
15
|
const confirm = useConfirm();
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { collection, limit, onSnapshot, orderBy, query } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
6
|
-
import { formatCents } from "../../schema/shop";
|
|
7
|
-
import { Badge, Button, Card, Input } from "../ui/primitives";
|
|
8
|
-
import { Select } from "../ui/select";
|
|
9
|
-
import { Switch } from "../ui/switch";
|
|
10
|
-
import { useToast } from "../ui/toast";
|
|
11
|
-
import { useConfirm } from "../ui/ConfirmDialog";
|
|
12
|
-
import { Dialog, DialogContent, DialogClose } from "../ui/dialog";
|
|
13
|
-
import { ORDER_STATUS_LABELS, shopCallable } from "./lib";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
|
+
import { formatCents } from "../../schema/shop.js";
|
|
7
|
+
import { Badge, Button, Card, Input } from "../ui/primitives.js";
|
|
8
|
+
import { Select } from "../ui/select.js";
|
|
9
|
+
import { Switch } from "../ui/switch.js";
|
|
10
|
+
import { useToast } from "../ui/toast.js";
|
|
11
|
+
import { useConfirm } from "../ui/ConfirmDialog.js";
|
|
12
|
+
import { Dialog, DialogContent, DialogClose } from "../ui/dialog.js";
|
|
13
|
+
import { ORDER_STATUS_LABELS, shopCallable } from "./lib.js";
|
|
14
14
|
const FILTERS = [
|
|
15
15
|
{ value: "all", label: "Alles" },
|
|
16
16
|
{ value: "pending", label: "Wacht op betaling" },
|
|
@@ -372,7 +372,7 @@ function OrdersTab({ siteId }) {
|
|
|
372
372
|
] })
|
|
373
373
|
] }) }) : /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Selecteer een bestelling." }) })
|
|
374
374
|
] }),
|
|
375
|
-
/* @__PURE__ */ jsx(Dialog, { open: !!invoice, onOpenChange: (o) => !o && setInvoice(null), children: invoice && /* @__PURE__ */ jsxs(DialogContent, { title: `Factuur ${invoice.number}`,
|
|
375
|
+
/* @__PURE__ */ jsx(Dialog, { open: !!invoice, onOpenChange: (o) => !o && setInvoice(null), children: invoice && /* @__PURE__ */ jsxs(DialogContent, { title: `Factuur ${invoice.number}`, width: "min(92vw, 48rem)", children: [
|
|
376
376
|
/* @__PURE__ */ jsx(
|
|
377
377
|
"iframe",
|
|
378
378
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/shop/OrdersTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { collection, limit, onSnapshot, orderBy, query } from \"firebase/firestore\";\nimport type { Timestamp } from \"firebase/firestore\";\nimport { getDb } from \"../../firebase/client\";\nimport { formatCents, type Order } from \"../../schema/shop\";\nimport { Badge, Button, Card, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { useToast } from \"../ui/toast\";\nimport { useConfirm } from \"../ui/ConfirmDialog\";\nimport { Dialog, DialogContent, DialogClose } from \"../ui/dialog\";\nimport { ORDER_STATUS_LABELS, shopCallable } from \"./lib\";\n\ntype StoredOrder = Order & {\n id: string;\n createdAt?: Timestamp;\n paidAt?: Timestamp;\n shippedAt?: Timestamp;\n mail?: { confirmationSentAt?: Timestamp; error?: string };\n};\n\nconst FILTERS = [\n { value: \"all\", label: \"Alles\" },\n { value: \"pending\", label: \"Wacht op betaling\" },\n { value: \"paid\", label: \"Betaald\" },\n { value: \"shipped\", label: \"Verzonden\" },\n { value: \"cancelled\", label: \"Geannuleerd\" },\n { value: \"refunded\", label: \"Terugbetaald\" },\n { value: \"donation\", label: \"Donaties\" },\n];\n\nfunction fmtDate(t?: Timestamp): string {\n if (!t?.toDate) return \"—\";\n return t.toDate().toLocaleString(\"nl-NL\", { dateStyle: \"short\", timeStyle: \"short\" });\n}\n\n/** Btw-component uit een incl.-prijs: totaal × tarief / (100 + tarief). */\nfunction vatOf(cents: number, rate: number): number {\n return Math.round((cents * rate) / (100 + rate));\n}\n\nexport function OrdersTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const [orders, setOrders] = useState<StoredOrder[]>([]);\n const [selected, setSelected] = useState<string | null>(null);\n const [filter, setFilter] = useState(\"all\");\n const [search, setSearch] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [invoice, setInvoice] = useState<{ url: string; number: string } | null>(null);\n const [shipOpen, setShipOpen] = useState(false);\n const [trackingUrl, setTrackingUrl] = useState(\"\");\n const [notify, setNotify] = useState(true);\n\n useEffect(() => {\n const db = getDb();\n if (!db) return;\n return onSnapshot(\n query(collection(db, \"sites\", siteId, \"orders\"), orderBy(\"createdAt\", \"desc\"), limit(300)),\n (snap) => setOrders(snap.docs.map((d) => ({ id: d.id, ...(d.data() as Order) }) as StoredOrder)),\n );\n }, [siteId]);\n\n /** Dashboard-tegels: vandaag / deze week / omzet (betaald + verzonden). */\n const stats = useMemo(() => {\n const now = new Date();\n const startToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n const startWeek = startToday - ((now.getDay() + 6) % 7) * 86_400_000;\n const paidish = orders.filter((o) => [\"paid\", \"shipped\"].includes(o.status));\n return {\n today: paidish.filter((o) => (o.createdAt?.toMillis?.() ?? 0) >= startToday).length,\n week: paidish.filter((o) => (o.createdAt?.toMillis?.() ?? 0) >= startWeek).length,\n openPaid: orders.filter((o) => o.status === \"paid\").length,\n revenueCents: paidish.reduce((n, o) => n + o.amount.totalCents, 0),\n };\n }, [orders]);\n\n const visible = useMemo(() => {\n let list = orders;\n if (filter === \"donation\") list = list.filter((o) => o.items.some((i) => i.kind === \"donation\"));\n else if (filter !== \"all\") list = list.filter((o) => o.status === filter);\n const needle = search.trim().toLowerCase();\n if (needle) {\n list = list.filter(\n (o) =>\n o.number.toLowerCase().includes(needle) ||\n o.customer.name.toLowerCase().includes(needle) ||\n o.customer.email.toLowerCase().includes(needle),\n );\n }\n return list;\n }, [orders, filter, search]);\n\n const current = orders.find((o) => o.id === selected) ?? null;\n\n async function setStatus(order: StoredOrder, status: \"shipped\" | \"cancelled\") {\n setBusy(true);\n try {\n await shopCallable<Record<string, unknown>, { ok: boolean }>(\"updateOrderStatus\")({\n siteId,\n orderId: order.id,\n status,\n notify,\n trackingUrl: status === \"shipped\" && trackingUrl.trim() ? trackingUrl.trim() : undefined,\n });\n toast({\n title: status === \"shipped\" ? \"Gemarkeerd als verzonden\" : \"Bestelling geannuleerd\",\n description: notify ? \"De klant heeft een e-mail ontvangen.\" : undefined,\n tone: \"success\",\n });\n setShipOpen(false);\n setTrackingUrl(\"\");\n } catch (e) {\n toast({ title: \"Status wijzigen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function refund(order: StoredOrder) {\n const ok = await confirm({\n title: `Bestelling ${order.number} terugbetalen?`,\n description: `Het volledige bedrag (${formatCents(order.amount.totalCents)}) wordt via Stripe teruggestort; de klant krijgt een e-mail.`,\n tone: \"danger\",\n confirmLabel: \"Terugbetalen\",\n });\n if (!ok) return;\n setBusy(true);\n try {\n await shopCallable<{ siteId: string; orderId: string }, { ok: boolean }>(\"refundOrder\")({ siteId, orderId: order.id });\n toast({ title: \"Terugbetaling gestart\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Terugbetalen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function resendMail(order: StoredOrder) {\n setBusy(true);\n try {\n await shopCallable<{ siteId: string; orderId: string }, { ok: boolean }>(\"resendOrderMail\")({ siteId, orderId: order.id });\n toast({ title: \"Bevestigingsmail opnieuw verstuurd\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Mail versturen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function signedUrl(order: StoredOrder, path: string): Promise<string | null> {\n try {\n const res = await shopCallable<{ siteId: string; orderId: string; path: string }, { url: string }>(\"getOrderFileUrl\")({\n siteId,\n orderId: order.id,\n path,\n });\n return res.url;\n } catch (e) {\n toast({ title: \"Bestand ophalen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n return null;\n }\n }\n\n async function download(order: StoredOrder, path: string) {\n setBusy(true);\n const url = await signedUrl(order, path);\n setBusy(false);\n if (url) window.open(url, \"_blank\", \"noopener\");\n }\n\n /** Factuur inline tonen in een dialoog (met download/openen-in-tab erin). */\n async function viewInvoice(order: StoredOrder, path: string) {\n setBusy(true);\n const url = await signedUrl(order, path);\n setBusy(false);\n if (url) setInvoice({ url, number: order.number });\n }\n\n function exportCsv() {\n const rows = [\n [\"nummer\", \"datum\", \"status\", \"naam\", \"email\", \"items\", \"subtotaal\", \"korting\", \"verzendkosten\", \"totaal\", \"btw\"],\n ...orders.map((o) => {\n const vat =\n o.items.reduce((n, i) => n + vatOf(i.unitPriceCents * i.qty, i.vatRate ?? 21), 0) +\n (o.amount.shippingCents > 0 ? vatOf(o.amount.shippingCents, 21) : 0);\n return [\n o.number,\n fmtDate(o.createdAt),\n o.status,\n o.customer.name,\n o.customer.email,\n o.items.map((i) => `${i.qty}x ${i.name}${i.variantKey ? ` (${i.variantKey})` : \"\"}`).join(\" | \"),\n (o.amount.itemsCents / 100).toFixed(2),\n ((o.amount.discountCents ?? 0) / 100).toFixed(2),\n (o.amount.shippingCents / 100).toFixed(2),\n (o.amount.totalCents / 100).toFixed(2),\n (vat / 100).toFixed(2),\n ];\n }),\n ];\n const csv = rows.map((r) => r.map((c) => `\"${String(c).replaceAll('\"', '\"\"')}\"`).join(\";\")).join(\"\\n\");\n const blob = new Blob([\"\" + csv], { type: \"text/csv;charset=utf-8\" });\n const a = document.createElement(\"a\");\n a.href = URL.createObjectURL(blob);\n a.download = `bestellingen-${siteId}.csv`;\n a.click();\n URL.revokeObjectURL(a.href);\n }\n\n return (\n <div className=\"grid gap-4\">\n {/* Dashboard-tegels */}\n <div className=\"grid grid-cols-2 gap-3 md:grid-cols-4\">\n {[\n { label: \"Vandaag\", value: String(stats.today) },\n { label: \"Deze week\", value: String(stats.week) },\n { label: \"Te verzenden\", value: String(stats.openPaid) },\n { label: \"Omzet (betaald)\", value: formatCents(stats.revenueCents) },\n ].map((s) => (\n <Card key={s.label} className=\"py-3\">\n <p className=\"text-xs text-slate-500\">{s.label}</p>\n <p className=\"text-xl font-bold\">{s.value}</p>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-[340px_1fr]\">\n <Card className=\"h-fit\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">Bestellingen</h3>\n <Button size=\"sm\" variant=\"secondary\" onClick={exportCsv} disabled={orders.length === 0}>\n CSV\n </Button>\n </div>\n <Input placeholder=\"Zoek op nummer, naam of e-mail…\" value={search} onChange={(e) => setSearch(e.target.value)} className=\"mb-2\" />\n <Select value={filter} onValueChange={setFilter} options={FILTERS} className=\"mb-2\" />\n <ul className=\"grid max-h-[60vh] gap-1 overflow-y-auto\">\n {visible.map((o) => {\n const st = ORDER_STATUS_LABELS[o.status] ?? { label: o.status, tone: \"slate\" as const };\n return (\n <li key={o.id}>\n <button\n onClick={() => {\n setSelected(o.id);\n setShipOpen(false);\n }}\n className={`grid w-full gap-0.5 rounded-lg px-3 py-2 text-left text-sm ${\n o.id === selected ? \"bg-brand-50 text-brand-700\" : \"hover:bg-slate-100\"\n }`}\n >\n <span className=\"flex items-center justify-between gap-2\">\n <span className=\"font-medium\">{o.number}</span>\n <Badge tone={st.tone}>{st.label}</Badge>\n </span>\n <span className=\"flex items-center justify-between gap-2 text-xs text-slate-500\">\n <span className=\"truncate\">{o.customer.name}</span>\n <span>{formatCents(o.amount.totalCents)}</span>\n </span>\n <span className=\"text-xs text-slate-400\">{fmtDate(o.createdAt)}</span>\n </button>\n </li>\n );\n })}\n {visible.length === 0 && <li className=\"px-3 py-2 text-sm text-slate-500\">Geen bestellingen.</li>}\n </ul>\n </Card>\n\n {current ? (\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-base font-semibold\">\n {current.number}{\" \"}\n <Badge tone={(ORDER_STATUS_LABELS[current.status] ?? { tone: \"slate\" as const }).tone}>\n {(ORDER_STATUS_LABELS[current.status] ?? { label: current.status }).label}\n </Badge>\n </h3>\n <span className=\"text-sm text-slate-500\">Geplaatst: {fmtDate(current.createdAt)}</span>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Klant</h4>\n <p className=\"text-sm\">\n {current.customer.name}\n <br />\n <a className=\"text-brand-700 underline\" href={`mailto:${current.customer.email}`}>{current.customer.email}</a>\n {current.customer.phone && (\n <>\n <br />\n {current.customer.phone}\n </>\n )}\n </p>\n </div>\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Verzendadres</h4>\n {current.shipping ? (\n <p className=\"text-sm\">\n {current.shipping.address}\n <br />\n {current.shipping.zip} {current.shipping.city} ({current.shipping.country})\n </p>\n ) : (\n <p className=\"text-sm text-slate-500\">Geen verzending (donatie).</p>\n )}\n {current.trackingUrl && (\n <a className=\"text-sm text-brand-700 underline\" href={current.trackingUrl} target=\"_blank\" rel=\"noreferrer\">\n Track & trace ↗\n </a>\n )}\n </div>\n </div>\n\n {current.note && (\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Opmerking van de klant</h4>\n <p className=\"whitespace-pre-wrap text-sm\">{current.note}</p>\n </div>\n )}\n\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Regels</h4>\n <table className=\"w-full text-sm\">\n <tbody>\n {current.items.map((i, idx) => (\n <tr key={idx} className=\"border-t border-slate-100 align-top\">\n <td className=\"py-1 pr-2\">\n {i.qty}× {i.name}\n {i.variantKey && <span className=\"text-slate-500\"> ({i.variantKey.split(\"|\").join(\" · \")})</span>}\n {i.kind === \"donation\" && <Badge tone=\"amber\">donatie</Badge>}\n {i.personalization &&\n Object.entries(i.personalization).map(([k, v]) => (\n <span key={k} className=\"block text-xs text-slate-600\">\n ↳ {v.text ?? v.fileName ?? \"eigen ontwerp\"}\n {v.imagePath && (\n <button\n type=\"button\"\n className=\"ml-1 text-brand-700 underline\"\n disabled={busy}\n onClick={() => download(current, v.imagePath as string)}\n >\n download\n </button>\n )}\n </span>\n ))}\n </td>\n <td className=\"py-1 text-right\">{formatCents(i.unitPriceCents * i.qty)}</td>\n </tr>\n ))}\n {(current.amount.discountCents ?? 0) > 0 && (\n <tr className=\"border-t border-slate-100 text-slate-500\">\n <td className=\"py-1 pr-2\">Korting{current.discount?.code ? ` (${current.discount.code})` : \"\"}</td>\n <td className=\"py-1 text-right\">−{formatCents(current.amount.discountCents ?? 0)}</td>\n </tr>\n )}\n <tr className=\"border-t border-slate-100 text-slate-500\">\n <td className=\"py-1 pr-2\">Verzendkosten</td>\n <td className=\"py-1 text-right\">\n {current.amount.shippingCents === 0 ? \"gratis\" : formatCents(current.amount.shippingCents)}\n </td>\n </tr>\n <tr className=\"border-t border-slate-200 font-semibold\">\n <td className=\"py-1 pr-2\">Totaal</td>\n <td className=\"py-1 text-right\">{formatCents(current.amount.totalCents)}</td>\n </tr>\n </tbody>\n </table>\n </div>\n\n {current.mail?.error && (\n <p className=\"rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-700\">\n Bevestigingsmail mislukt: {current.mail.error}\n </p>\n )}\n\n {/* Verzenden: track & trace + klant informeren */}\n {shipOpen && current.status === \"paid\" && (\n <div className=\"grid gap-3 rounded-lg border border-slate-200 p-3\">\n <Input\n placeholder=\"Track & trace-link (optioneel, https://…)\"\n value={trackingUrl}\n onChange={(e) => setTrackingUrl(e.target.value)}\n />\n <div className=\"flex items-center gap-4\">\n <Switch checked={notify} onCheckedChange={setNotify} label=\"Klant per e-mail informeren\" />\n <Button size=\"sm\" disabled={busy} onClick={() => setStatus(current, \"shipped\")}>\n Bevestig verzending\n </Button>\n </div>\n </div>\n )}\n\n <div className=\"flex flex-wrap items-center gap-2 border-t border-slate-100 pt-4\">\n {current.status === \"paid\" && !shipOpen && (\n <Button size=\"sm\" onClick={() => setShipOpen(true)}>Markeer als verzonden</Button>\n )}\n {[\"pending\", \"paid\"].includes(current.status) && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n disabled={busy}\n onClick={async () => {\n const ok = await confirm({\n title: `Bestelling ${current.number} annuleren?`,\n description: notify ? \"De klant ontvangt een e-mail.\" : undefined,\n });\n if (ok) void setStatus(current, \"cancelled\");\n }}\n >\n Annuleer\n </Button>\n )}\n {(current.status === \"paid\" || current.status === \"shipped\") && (\n <>\n <Button size=\"sm\" variant=\"secondary\" disabled={busy} onClick={() => resendMail(current)}>\n Mail opnieuw versturen\n </Button>\n <Button size=\"sm\" variant=\"danger\" disabled={busy} onClick={() => refund(current)}>\n Terugbetalen\n </Button>\n </>\n )}\n {current.invoicePath && (\n <Button size=\"sm\" variant=\"secondary\" disabled={busy} onClick={() => viewInvoice(current, current.invoicePath as string)}>\n Factuur bekijken\n </Button>\n )}\n {current.stripe?.paymentIntentId && (\n <a\n className=\"ml-auto text-sm text-brand-700 underline\"\n href={`https://dashboard.stripe.com/payments/${current.stripe.paymentIntentId}`}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Bekijk in Stripe ↗\n </a>\n )}\n </div>\n </div>\n </Card>\n ) : (\n <Card>\n <p className=\"text-sm text-slate-500\">Selecteer een bestelling.</p>\n </Card>\n )}\n </div>\n\n <Dialog open={!!invoice} onOpenChange={(o) => !o && setInvoice(null)}>\n {invoice && (\n <DialogContent title={`Factuur ${invoice.number}`} className=\"max-w-3xl\">\n <iframe\n title={`Factuur ${invoice.number}`}\n src={invoice.url}\n className=\"h-[70vh] w-full rounded-lg border border-slate-200 bg-white\"\n />\n <div className=\"mt-3 flex items-center gap-2\">\n <a href={invoice.url} target=\"_blank\" rel=\"noreferrer\" download={`factuur-${invoice.number}.pdf`}>\n <Button size=\"sm\" variant=\"secondary\">Downloaden</Button>\n </a>\n <a href={invoice.url} target=\"_blank\" rel=\"noreferrer\" className=\"text-sm text-brand-700 underline\">\n Openen in nieuw tabblad ↗\n </a>\n <DialogClose asChild>\n <Button size=\"sm\" variant=\"ghost\" className=\"ml-auto\">Sluiten</Button>\n </DialogClose>\n </div>\n </DialogContent>\n )}\n </Dialog>\n </div>\n );\n}\n"],"mappings":";AA8NU,SAqEY,UApEV,KADF;AA5NV,SAAS,WAAW,SAAS,gBAAgB;AAC7C,SAAS,YAAY,OAAO,YAAY,SAAS,aAAa;AAE9D,SAAS,aAAa;AACtB,SAAS,mBAA+B;AACxC,SAAS,OAAO,QAAQ,MAAM,aAAa;AAC3C,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,QAAQ,eAAe,mBAAmB;AACnD,SAAS,qBAAqB,oBAAoB;AAUlD,MAAM,UAAU;AAAA,EACd,EAAE,OAAO,OAAO,OAAO,QAAQ;AAAA,EAC/B,EAAE,OAAO,WAAW,OAAO,oBAAoB;AAAA,EAC/C,EAAE,OAAO,QAAQ,OAAO,UAAU;AAAA,EAClC,EAAE,OAAO,WAAW,OAAO,YAAY;AAAA,EACvC,EAAE,OAAO,aAAa,OAAO,cAAc;AAAA,EAC3C,EAAE,OAAO,YAAY,OAAO,eAAe;AAAA,EAC3C,EAAE,OAAO,YAAY,OAAO,WAAW;AACzC;AAEA,SAAS,QAAQ,GAAuB;AACtC,MAAI,CAAC,GAAG,OAAQ,QAAO;AACvB,SAAO,EAAE,OAAO,EAAE,eAAe,SAAS,EAAE,WAAW,SAAS,WAAW,QAAQ,CAAC;AACtF;AAGA,SAAS,MAAM,OAAe,MAAsB;AAClD,SAAO,KAAK,MAAO,QAAQ,QAAS,MAAM,KAAK;AACjD;AAEO,SAAS,UAAU,EAAE,OAAO,GAAuB;AACxD,QAAM,EAAE,MAAM,IAAI,SAAS;AAC3B,QAAM,UAAU,WAAW;AAC3B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAwB,CAAC,CAAC;AACtD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AACvC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAiD,IAAI;AACnF,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,EAAE;AACjD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,IAAI;AAEzC,YAAU,MAAM;AACd,UAAM,KAAK,MAAM;AACjB,QAAI,CAAC,GAAI;AACT,WAAO;AAAA,MACL,MAAM,WAAW,IAAI,SAAS,QAAQ,QAAQ,GAAG,QAAQ,aAAa,MAAM,GAAG,MAAM,GAAG,CAAC;AAAA,MACzF,CAAC,SAAS,UAAU,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,KAAK,EAAY,EAAiB,CAAC;AAAA,IACjG;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,QAAQ,QAAQ,MAAM;AAC1B,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,aAAa,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,IAAI,QAAQ,CAAC,EAAE,QAAQ;AACtF,UAAM,YAAY,cAAe,IAAI,OAAO,IAAI,KAAK,IAAK;AAC1D,UAAM,UAAU,OAAO,OAAO,CAAC,MAAM,CAAC,QAAQ,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC;AAC3E,WAAO;AAAA,MACL,OAAO,QAAQ,OAAO,CAAC,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,UAAU,EAAE;AAAA,MAC7E,MAAM,QAAQ,OAAO,CAAC,OAAO,EAAE,WAAW,WAAW,KAAK,MAAM,SAAS,EAAE;AAAA,MAC3E,UAAU,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAAA,MACpD,cAAc,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,YAAY,CAAC;AAAA,IACnE;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,OAAO;AACX,QAAI,WAAW,WAAY,QAAO,KAAK,OAAO,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,CAAC;AAAA,aACtF,WAAW,MAAO,QAAO,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AACxE,UAAM,SAAS,OAAO,KAAK,EAAE,YAAY;AACzC,QAAI,QAAQ;AACV,aAAO,KAAK;AAAA,QACV,CAAC,MACC,EAAE,OAAO,YAAY,EAAE,SAAS,MAAM,KACtC,EAAE,SAAS,KAAK,YAAY,EAAE,SAAS,MAAM,KAC7C,EAAE,SAAS,MAAM,YAAY,EAAE,SAAS,MAAM;AAAA,MAClD;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,QAAQ,MAAM,CAAC;AAE3B,QAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ,KAAK;AAEzD,iBAAe,UAAU,OAAoB,QAAiC;AAC5E,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,aAAuD,mBAAmB,EAAE;AAAA,QAChF;AAAA,QACA,SAAS,MAAM;AAAA,QACf;AAAA,QACA;AAAA,QACA,aAAa,WAAW,aAAa,YAAY,KAAK,IAAI,YAAY,KAAK,IAAI;AAAA,MACjF,CAAC;AACD,YAAM;AAAA,QACJ,OAAO,WAAW,YAAY,6BAA6B;AAAA,QAC3D,aAAa,SAAS,yCAAyC;AAAA,QAC/D,MAAM;AAAA,MACR,CAAC;AACD,kBAAY,KAAK;AACjB,qBAAe,EAAE;AAAA,IACnB,SAAS,GAAG;AACV,YAAM,EAAE,OAAO,2BAA2B,aAAa,aAAa,QAAQ,EAAE,UAAU,QAAW,MAAM,QAAQ,CAAC;AAAA,IACpH,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,OAAO,OAAoB;AACxC,UAAM,KAAK,MAAM,QAAQ;AAAA,MACvB,OAAO,cAAc,MAAM,MAAM;AAAA,MACjC,aAAa,yBAAyB,YAAY,MAAM,OAAO,UAAU,CAAC;AAAA,MAC1E,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AACD,QAAI,CAAC,GAAI;AACT,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,aAAmE,aAAa,EAAE,EAAE,QAAQ,SAAS,MAAM,GAAG,CAAC;AACrH,YAAM,EAAE,OAAO,yBAAyB,MAAM,UAAU,CAAC;AAAA,IAC3D,SAAS,GAAG;AACV,YAAM,EAAE,OAAO,wBAAwB,aAAa,aAAa,QAAQ,EAAE,UAAU,QAAW,MAAM,QAAQ,CAAC;AAAA,IACjH,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,WAAW,OAAoB;AAC5C,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,aAAmE,iBAAiB,EAAE,EAAE,QAAQ,SAAS,MAAM,GAAG,CAAC;AACzH,YAAM,EAAE,OAAO,sCAAsC,MAAM,UAAU,CAAC;AAAA,IACxE,SAAS,GAAG;AACV,YAAM,EAAE,OAAO,0BAA0B,aAAa,aAAa,QAAQ,EAAE,UAAU,QAAW,MAAM,QAAQ,CAAC;AAAA,IACnH,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,UAAU,OAAoB,MAAsC;AACjF,QAAI;AACF,YAAM,MAAM,MAAM,aAAiF,iBAAiB,EAAE;AAAA,QACpH;AAAA,QACA,SAAS,MAAM;AAAA,QACf;AAAA,MACF,CAAC;AACD,aAAO,IAAI;AAAA,IACb,SAAS,GAAG;AACV,YAAM,EAAE,OAAO,2BAA2B,aAAa,aAAa,QAAQ,EAAE,UAAU,QAAW,MAAM,QAAQ,CAAC;AAClH,aAAO;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,SAAS,OAAoB,MAAc;AACxD,YAAQ,IAAI;AACZ,UAAM,MAAM,MAAM,UAAU,OAAO,IAAI;AACvC,YAAQ,KAAK;AACb,QAAI,IAAK,QAAO,KAAK,KAAK,UAAU,UAAU;AAAA,EAChD;AAGA,iBAAe,YAAY,OAAoB,MAAc;AAC3D,YAAQ,IAAI;AACZ,UAAM,MAAM,MAAM,UAAU,OAAO,IAAI;AACvC,YAAQ,KAAK;AACb,QAAI,IAAK,YAAW,EAAE,KAAK,QAAQ,MAAM,OAAO,CAAC;AAAA,EACnD;AAEA,WAAS,YAAY;AACnB,UAAM,OAAO;AAAA,MACX,CAAC,UAAU,SAAS,UAAU,QAAQ,SAAS,SAAS,aAAa,WAAW,iBAAiB,UAAU,KAAK;AAAA,MAChH,GAAG,OAAO,IAAI,CAAC,MAAM;AACnB,cAAM,MACJ,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,KAC/E,EAAE,OAAO,gBAAgB,IAAI,MAAM,EAAE,OAAO,eAAe,EAAE,IAAI;AACpE,eAAO;AAAA,UACL,EAAE;AAAA,UACF,QAAQ,EAAE,SAAS;AAAA,UACnB,EAAE;AAAA,UACF,EAAE,SAAS;AAAA,UACX,EAAE,SAAS;AAAA,UACX,EAAE,MAAM,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,GAAG,EAAE,aAAa,KAAK,EAAE,UAAU,MAAM,EAAE,EAAE,EAAE,KAAK,KAAK;AAAA,WAC9F,EAAE,OAAO,aAAa,KAAK,QAAQ,CAAC;AAAA,YACnC,EAAE,OAAO,iBAAiB,KAAK,KAAK,QAAQ,CAAC;AAAA,WAC9C,EAAE,OAAO,gBAAgB,KAAK,QAAQ,CAAC;AAAA,WACvC,EAAE,OAAO,aAAa,KAAK,QAAQ,CAAC;AAAA,WACpC,MAAM,KAAK,QAAQ,CAAC;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI;AACrG,UAAM,OAAO,IAAI,KAAK,CAAC,WAAM,GAAG,GAAG,EAAE,MAAM,yBAAyB,CAAC;AACrE,UAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAE,OAAO,IAAI,gBAAgB,IAAI;AACjC,MAAE,WAAW,gBAAgB,MAAM;AACnC,MAAE,MAAM;AACR,QAAI,gBAAgB,EAAE,IAAI;AAAA,EAC5B;AAEA,SACE,qBAAC,SAAI,WAAU,cAEb;AAAA,wBAAC,SAAI,WAAU,yCACZ;AAAA,MACC,EAAE,OAAO,WAAW,OAAO,OAAO,MAAM,KAAK,EAAE;AAAA,MAC/C,EAAE,OAAO,aAAa,OAAO,OAAO,MAAM,IAAI,EAAE;AAAA,MAChD,EAAE,OAAO,gBAAgB,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,MACvD,EAAE,OAAO,mBAAmB,OAAO,YAAY,MAAM,YAAY,EAAE;AAAA,IACrE,EAAE,IAAI,CAAC,MACL,qBAAC,QAAmB,WAAU,QAC5B;AAAA,0BAAC,OAAE,WAAU,0BAA0B,YAAE,OAAM;AAAA,MAC/C,oBAAC,OAAE,WAAU,qBAAqB,YAAE,OAAM;AAAA,SAFjC,EAAE,KAGb,CACD,GACH;AAAA,IAEA,qBAAC,SAAI,WAAU,uCACb;AAAA,2BAAC,QAAK,WAAU,SACd;AAAA,6BAAC,SAAI,WAAU,gDACb;AAAA,8BAAC,QAAG,WAAU,yBAAwB,0BAAY;AAAA,UAClD,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,WAAW,UAAU,OAAO,WAAW,GAAG,iBAEzF;AAAA,WACF;AAAA,QACA,oBAAC,SAAM,aAAY,wCAAkC,OAAO,QAAQ,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK,GAAG,WAAU,QAAO;AAAA,QACjI,oBAAC,UAAO,OAAO,QAAQ,eAAe,WAAW,SAAS,SAAS,WAAU,QAAO;AAAA,QACpF,qBAAC,QAAG,WAAU,2CACX;AAAA,kBAAQ,IAAI,CAAC,MAAM;AAClB,kBAAM,KAAK,oBAAoB,EAAE,MAAM,KAAK,EAAE,OAAO,EAAE,QAAQ,MAAM,QAAiB;AACtF,mBACE,oBAAC,QACC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,MAAM;AACb,8BAAY,EAAE,EAAE;AAChB,8BAAY,KAAK;AAAA,gBACnB;AAAA,gBACA,WAAW,8DACT,EAAE,OAAO,WAAW,+BAA+B,oBACrD;AAAA,gBAEA;AAAA,uCAAC,UAAK,WAAU,2CACd;AAAA,wCAAC,UAAK,WAAU,eAAe,YAAE,QAAO;AAAA,oBACxC,oBAAC,SAAM,MAAM,GAAG,MAAO,aAAG,OAAM;AAAA,qBAClC;AAAA,kBACA,qBAAC,UAAK,WAAU,kEACd;AAAA,wCAAC,UAAK,WAAU,YAAY,YAAE,SAAS,MAAK;AAAA,oBAC5C,oBAAC,UAAM,sBAAY,EAAE,OAAO,UAAU,GAAE;AAAA,qBAC1C;AAAA,kBACA,oBAAC,UAAK,WAAU,0BAA0B,kBAAQ,EAAE,SAAS,GAAE;AAAA;AAAA;AAAA,YACjE,KAnBO,EAAE,EAoBX;AAAA,UAEJ,CAAC;AAAA,UACA,QAAQ,WAAW,KAAK,oBAAC,QAAG,WAAU,oCAAmC,gCAAkB;AAAA,WAC9F;AAAA,SACF;AAAA,MAEC,UACC,oBAAC,QACC,+BAAC,SAAI,WAAU,cACb;AAAA,6BAAC,SAAI,WAAU,qDACb;AAAA,+BAAC,QAAG,WAAU,2BACX;AAAA,oBAAQ;AAAA,YAAQ;AAAA,YACjB,oBAAC,SAAM,OAAO,oBAAoB,QAAQ,MAAM,KAAK,EAAE,MAAM,QAAiB,GAAG,MAC7E,+BAAoB,QAAQ,MAAM,KAAK,EAAE,OAAO,QAAQ,OAAO,GAAG,OACtE;AAAA,aACF;AAAA,UACA,qBAAC,UAAK,WAAU,0BAAyB;AAAA;AAAA,YAAY,QAAQ,QAAQ,SAAS;AAAA,aAAE;AAAA,WAClF;AAAA,QAEA,qBAAC,SAAI,WAAU,6BACb;AAAA,+BAAC,SACC;AAAA,gCAAC,QAAG,WAAU,8BAA6B,mBAAK;AAAA,YAChD,qBAAC,OAAE,WAAU,WACV;AAAA,sBAAQ,SAAS;AAAA,cAClB,oBAAC,QAAG;AAAA,cACJ,oBAAC,OAAE,WAAU,4BAA2B,MAAM,UAAU,QAAQ,SAAS,KAAK,IAAK,kBAAQ,SAAS,OAAM;AAAA,cACzG,QAAQ,SAAS,SAChB,iCACE;AAAA,oCAAC,QAAG;AAAA,gBACH,QAAQ,SAAS;AAAA,iBACpB;AAAA,eAEJ;AAAA,aACF;AAAA,UACA,qBAAC,SACC;AAAA,gCAAC,QAAG,WAAU,8BAA6B,0BAAY;AAAA,YACtD,QAAQ,WACP,qBAAC,OAAE,WAAU,WACV;AAAA,sBAAQ,SAAS;AAAA,cAClB,oBAAC,QAAG;AAAA,cACH,QAAQ,SAAS;AAAA,cAAI;AAAA,cAAE,QAAQ,SAAS;AAAA,cAAK;AAAA,cAAG,QAAQ,SAAS;AAAA,cAAQ;AAAA,eAC5E,IAEA,oBAAC,OAAE,WAAU,0BAAyB,wCAA0B;AAAA,YAEjE,QAAQ,eACP,oBAAC,OAAE,WAAU,oCAAmC,MAAM,QAAQ,aAAa,QAAO,UAAS,KAAI,cAAa,kCAE5G;AAAA,aAEJ;AAAA,WACF;AAAA,QAEC,QAAQ,QACP,qBAAC,SACC;AAAA,8BAAC,QAAG,WAAU,8BAA6B,oCAAsB;AAAA,UACjE,oBAAC,OAAE,WAAU,+BAA+B,kBAAQ,MAAK;AAAA,WAC3D;AAAA,QAGF,qBAAC,SACC;AAAA,8BAAC,QAAG,WAAU,8BAA6B,oBAAM;AAAA,UACjD,oBAAC,WAAM,WAAU,kBACf,+BAAC,WACE;AAAA,oBAAQ,MAAM,IAAI,CAAC,GAAG,QACrB,qBAAC,QAAa,WAAU,uCACtB;AAAA,mCAAC,QAAG,WAAU,aACX;AAAA,kBAAE;AAAA,gBAAI;AAAA,gBAAG,EAAE;AAAA,gBACX,EAAE,cAAc,qBAAC,UAAK,WAAU,kBAAiB;AAAA;AAAA,kBAAG,EAAE,WAAW,MAAM,GAAG,EAAE,KAAK,QAAK;AAAA,kBAAE;AAAA,mBAAC;AAAA,gBACzF,EAAE,SAAS,cAAc,oBAAC,SAAM,MAAK,SAAQ,qBAAO;AAAA,gBACpD,EAAE,mBACD,OAAO,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAC1C,qBAAC,UAAa,WAAU,gCAA+B;AAAA;AAAA,kBAClD,EAAE,QAAQ,EAAE,YAAY;AAAA,kBAC1B,EAAE,aACD;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,UAAU;AAAA,sBACV,SAAS,MAAM,SAAS,SAAS,EAAE,SAAmB;AAAA,sBACvD;AAAA;AAAA,kBAED;AAAA,qBAVO,CAYX,CACD;AAAA,iBACL;AAAA,cACA,oBAAC,QAAG,WAAU,mBAAmB,sBAAY,EAAE,iBAAiB,EAAE,GAAG,GAAE;AAAA,iBAtBhE,GAuBT,CACD;AAAA,aACC,QAAQ,OAAO,iBAAiB,KAAK,KACrC,qBAAC,QAAG,WAAU,4CACZ;AAAA,mCAAC,QAAG,WAAU,aAAY;AAAA;AAAA,gBAAQ,QAAQ,UAAU,OAAO,KAAK,QAAQ,SAAS,IAAI,MAAM;AAAA,iBAAG;AAAA,cAC9F,qBAAC,QAAG,WAAU,mBAAkB;AAAA;AAAA,gBAAE,YAAY,QAAQ,OAAO,iBAAiB,CAAC;AAAA,iBAAE;AAAA,eACnF;AAAA,YAEF,qBAAC,QAAG,WAAU,4CACZ;AAAA,kCAAC,QAAG,WAAU,aAAY,2BAAa;AAAA,cACvC,oBAAC,QAAG,WAAU,mBACX,kBAAQ,OAAO,kBAAkB,IAAI,WAAW,YAAY,QAAQ,OAAO,aAAa,GAC3F;AAAA,eACF;AAAA,YACA,qBAAC,QAAG,WAAU,2CACZ;AAAA,kCAAC,QAAG,WAAU,aAAY,oBAAM;AAAA,cAChC,oBAAC,QAAG,WAAU,mBAAmB,sBAAY,QAAQ,OAAO,UAAU,GAAE;AAAA,eAC1E;AAAA,aACF,GACF;AAAA,WACF;AAAA,QAEC,QAAQ,MAAM,SACb,qBAAC,OAAE,WAAU,2DAA0D;AAAA;AAAA,UAC1C,QAAQ,KAAK;AAAA,WAC1C;AAAA,QAID,YAAY,QAAQ,WAAW,UAC9B,qBAAC,SAAI,WAAU,qDACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,aAAY;AAAA,cACZ,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,eAAe,EAAE,OAAO,KAAK;AAAA;AAAA,UAChD;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,UAAO,SAAS,QAAQ,iBAAiB,WAAW,OAAM,+BAA8B;AAAA,YACzF,oBAAC,UAAO,MAAK,MAAK,UAAU,MAAM,SAAS,MAAM,UAAU,SAAS,SAAS,GAAG,iCAEhF;AAAA,aACF;AAAA,WACF;AAAA,QAGF,qBAAC,SAAI,WAAU,oEACZ;AAAA,kBAAQ,WAAW,UAAU,CAAC,YAC7B,oBAAC,UAAO,MAAK,MAAK,SAAS,MAAM,YAAY,IAAI,GAAG,mCAAqB;AAAA,UAE1E,CAAC,WAAW,MAAM,EAAE,SAAS,QAAQ,MAAM,KAC1C;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,UAAU;AAAA,cACV,SAAS,YAAY;AACnB,sBAAM,KAAK,MAAM,QAAQ;AAAA,kBACvB,OAAO,cAAc,QAAQ,MAAM;AAAA,kBACnC,aAAa,SAAS,kCAAkC;AAAA,gBAC1D,CAAC;AACD,oBAAI,GAAI,MAAK,UAAU,SAAS,WAAW;AAAA,cAC7C;AAAA,cACD;AAAA;AAAA,UAED;AAAA,WAEA,QAAQ,WAAW,UAAU,QAAQ,WAAW,cAChD,iCACE;AAAA,gCAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,UAAU,MAAM,SAAS,MAAM,WAAW,OAAO,GAAG,oCAE1F;AAAA,YACA,oBAAC,UAAO,MAAK,MAAK,SAAQ,UAAS,UAAU,MAAM,SAAS,MAAM,OAAO,OAAO,GAAG,0BAEnF;AAAA,aACF;AAAA,UAED,QAAQ,eACP,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,UAAU,MAAM,SAAS,MAAM,YAAY,SAAS,QAAQ,WAAqB,GAAG,8BAE1H;AAAA,UAED,QAAQ,QAAQ,mBACf;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAM,yCAAyC,QAAQ,OAAO,eAAe;AAAA,cAC7E,QAAO;AAAA,cACP,KAAI;AAAA,cACL;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,SACF,GACF,IAEA,oBAAC,QACC,8BAAC,OAAE,WAAU,0BAAyB,uCAAyB,GACjE;AAAA,OAEJ;AAAA,IAEA,oBAAC,UAAO,MAAM,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,KAAK,WAAW,IAAI,GAChE,qBACC,qBAAC,iBAAc,OAAO,WAAW,QAAQ,MAAM,IAAI,WAAU,aAC3D;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW,QAAQ,MAAM;AAAA,UAChC,KAAK,QAAQ;AAAA,UACb,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,qBAAC,SAAI,WAAU,gCACb;AAAA,4BAAC,OAAE,MAAM,QAAQ,KAAK,QAAO,UAAS,KAAI,cAAa,UAAU,WAAW,QAAQ,MAAM,QACxF,8BAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,wBAAU,GAClD;AAAA,QACA,oBAAC,OAAE,MAAM,QAAQ,KAAK,QAAO,UAAS,KAAI,cAAa,WAAU,oCAAmC,4CAEpG;AAAA,QACA,oBAAC,eAAY,SAAO,MAClB,8BAAC,UAAO,MAAK,MAAK,SAAQ,SAAQ,WAAU,WAAU,qBAAO,GAC/D;AAAA,SACF;AAAA,OACF,GAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/shop/OrdersTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { collection, limit, onSnapshot, orderBy, query } from \"firebase/firestore\";\nimport type { Timestamp } from \"firebase/firestore\";\nimport { getDb } from \"../../firebase/client\";\nimport { formatCents, type Order } from \"../../schema/shop\";\nimport { Badge, Button, Card, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { useToast } from \"../ui/toast\";\nimport { useConfirm } from \"../ui/ConfirmDialog\";\nimport { Dialog, DialogContent, DialogClose } from \"../ui/dialog\";\nimport { ORDER_STATUS_LABELS, shopCallable } from \"./lib\";\n\ntype StoredOrder = Order & {\n id: string;\n createdAt?: Timestamp;\n paidAt?: Timestamp;\n shippedAt?: Timestamp;\n mail?: { confirmationSentAt?: Timestamp; error?: string };\n};\n\nconst FILTERS = [\n { value: \"all\", label: \"Alles\" },\n { value: \"pending\", label: \"Wacht op betaling\" },\n { value: \"paid\", label: \"Betaald\" },\n { value: \"shipped\", label: \"Verzonden\" },\n { value: \"cancelled\", label: \"Geannuleerd\" },\n { value: \"refunded\", label: \"Terugbetaald\" },\n { value: \"donation\", label: \"Donaties\" },\n];\n\nfunction fmtDate(t?: Timestamp): string {\n if (!t?.toDate) return \"—\";\n return t.toDate().toLocaleString(\"nl-NL\", { dateStyle: \"short\", timeStyle: \"short\" });\n}\n\n/** Btw-component uit een incl.-prijs: totaal × tarief / (100 + tarief). */\nfunction vatOf(cents: number, rate: number): number {\n return Math.round((cents * rate) / (100 + rate));\n}\n\nexport function OrdersTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const [orders, setOrders] = useState<StoredOrder[]>([]);\n const [selected, setSelected] = useState<string | null>(null);\n const [filter, setFilter] = useState(\"all\");\n const [search, setSearch] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [invoice, setInvoice] = useState<{ url: string; number: string } | null>(null);\n const [shipOpen, setShipOpen] = useState(false);\n const [trackingUrl, setTrackingUrl] = useState(\"\");\n const [notify, setNotify] = useState(true);\n\n useEffect(() => {\n const db = getDb();\n if (!db) return;\n return onSnapshot(\n query(collection(db, \"sites\", siteId, \"orders\"), orderBy(\"createdAt\", \"desc\"), limit(300)),\n (snap) => setOrders(snap.docs.map((d) => ({ id: d.id, ...(d.data() as Order) }) as StoredOrder)),\n );\n }, [siteId]);\n\n /** Dashboard-tegels: vandaag / deze week / omzet (betaald + verzonden). */\n const stats = useMemo(() => {\n const now = new Date();\n const startToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n const startWeek = startToday - ((now.getDay() + 6) % 7) * 86_400_000;\n const paidish = orders.filter((o) => [\"paid\", \"shipped\"].includes(o.status));\n return {\n today: paidish.filter((o) => (o.createdAt?.toMillis?.() ?? 0) >= startToday).length,\n week: paidish.filter((o) => (o.createdAt?.toMillis?.() ?? 0) >= startWeek).length,\n openPaid: orders.filter((o) => o.status === \"paid\").length,\n revenueCents: paidish.reduce((n, o) => n + o.amount.totalCents, 0),\n };\n }, [orders]);\n\n const visible = useMemo(() => {\n let list = orders;\n if (filter === \"donation\") list = list.filter((o) => o.items.some((i) => i.kind === \"donation\"));\n else if (filter !== \"all\") list = list.filter((o) => o.status === filter);\n const needle = search.trim().toLowerCase();\n if (needle) {\n list = list.filter(\n (o) =>\n o.number.toLowerCase().includes(needle) ||\n o.customer.name.toLowerCase().includes(needle) ||\n o.customer.email.toLowerCase().includes(needle),\n );\n }\n return list;\n }, [orders, filter, search]);\n\n const current = orders.find((o) => o.id === selected) ?? null;\n\n async function setStatus(order: StoredOrder, status: \"shipped\" | \"cancelled\") {\n setBusy(true);\n try {\n await shopCallable<Record<string, unknown>, { ok: boolean }>(\"updateOrderStatus\")({\n siteId,\n orderId: order.id,\n status,\n notify,\n trackingUrl: status === \"shipped\" && trackingUrl.trim() ? trackingUrl.trim() : undefined,\n });\n toast({\n title: status === \"shipped\" ? \"Gemarkeerd als verzonden\" : \"Bestelling geannuleerd\",\n description: notify ? \"De klant heeft een e-mail ontvangen.\" : undefined,\n tone: \"success\",\n });\n setShipOpen(false);\n setTrackingUrl(\"\");\n } catch (e) {\n toast({ title: \"Status wijzigen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function refund(order: StoredOrder) {\n const ok = await confirm({\n title: `Bestelling ${order.number} terugbetalen?`,\n description: `Het volledige bedrag (${formatCents(order.amount.totalCents)}) wordt via Stripe teruggestort; de klant krijgt een e-mail.`,\n tone: \"danger\",\n confirmLabel: \"Terugbetalen\",\n });\n if (!ok) return;\n setBusy(true);\n try {\n await shopCallable<{ siteId: string; orderId: string }, { ok: boolean }>(\"refundOrder\")({ siteId, orderId: order.id });\n toast({ title: \"Terugbetaling gestart\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Terugbetalen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function resendMail(order: StoredOrder) {\n setBusy(true);\n try {\n await shopCallable<{ siteId: string; orderId: string }, { ok: boolean }>(\"resendOrderMail\")({ siteId, orderId: order.id });\n toast({ title: \"Bevestigingsmail opnieuw verstuurd\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Mail versturen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function signedUrl(order: StoredOrder, path: string): Promise<string | null> {\n try {\n const res = await shopCallable<{ siteId: string; orderId: string; path: string }, { url: string }>(\"getOrderFileUrl\")({\n siteId,\n orderId: order.id,\n path,\n });\n return res.url;\n } catch (e) {\n toast({ title: \"Bestand ophalen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n return null;\n }\n }\n\n async function download(order: StoredOrder, path: string) {\n setBusy(true);\n const url = await signedUrl(order, path);\n setBusy(false);\n if (url) window.open(url, \"_blank\", \"noopener\");\n }\n\n /** Factuur inline tonen in een dialoog (met download/openen-in-tab erin). */\n async function viewInvoice(order: StoredOrder, path: string) {\n setBusy(true);\n const url = await signedUrl(order, path);\n setBusy(false);\n if (url) setInvoice({ url, number: order.number });\n }\n\n function exportCsv() {\n const rows = [\n [\"nummer\", \"datum\", \"status\", \"naam\", \"email\", \"items\", \"subtotaal\", \"korting\", \"verzendkosten\", \"totaal\", \"btw\"],\n ...orders.map((o) => {\n const vat =\n o.items.reduce((n, i) => n + vatOf(i.unitPriceCents * i.qty, i.vatRate ?? 21), 0) +\n (o.amount.shippingCents > 0 ? vatOf(o.amount.shippingCents, 21) : 0);\n return [\n o.number,\n fmtDate(o.createdAt),\n o.status,\n o.customer.name,\n o.customer.email,\n o.items.map((i) => `${i.qty}x ${i.name}${i.variantKey ? ` (${i.variantKey})` : \"\"}`).join(\" | \"),\n (o.amount.itemsCents / 100).toFixed(2),\n ((o.amount.discountCents ?? 0) / 100).toFixed(2),\n (o.amount.shippingCents / 100).toFixed(2),\n (o.amount.totalCents / 100).toFixed(2),\n (vat / 100).toFixed(2),\n ];\n }),\n ];\n const csv = rows.map((r) => r.map((c) => `\"${String(c).replaceAll('\"', '\"\"')}\"`).join(\";\")).join(\"\\n\");\n const blob = new Blob([\"\" + csv], { type: \"text/csv;charset=utf-8\" });\n const a = document.createElement(\"a\");\n a.href = URL.createObjectURL(blob);\n a.download = `bestellingen-${siteId}.csv`;\n a.click();\n URL.revokeObjectURL(a.href);\n }\n\n return (\n <div className=\"grid gap-4\">\n {/* Dashboard-tegels */}\n <div className=\"grid grid-cols-2 gap-3 md:grid-cols-4\">\n {[\n { label: \"Vandaag\", value: String(stats.today) },\n { label: \"Deze week\", value: String(stats.week) },\n { label: \"Te verzenden\", value: String(stats.openPaid) },\n { label: \"Omzet (betaald)\", value: formatCents(stats.revenueCents) },\n ].map((s) => (\n <Card key={s.label} className=\"py-3\">\n <p className=\"text-xs text-slate-500\">{s.label}</p>\n <p className=\"text-xl font-bold\">{s.value}</p>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-[340px_1fr]\">\n <Card className=\"h-fit\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">Bestellingen</h3>\n <Button size=\"sm\" variant=\"secondary\" onClick={exportCsv} disabled={orders.length === 0}>\n CSV\n </Button>\n </div>\n <Input placeholder=\"Zoek op nummer, naam of e-mail…\" value={search} onChange={(e) => setSearch(e.target.value)} className=\"mb-2\" />\n <Select value={filter} onValueChange={setFilter} options={FILTERS} className=\"mb-2\" />\n <ul className=\"grid max-h-[60vh] gap-1 overflow-y-auto\">\n {visible.map((o) => {\n const st = ORDER_STATUS_LABELS[o.status] ?? { label: o.status, tone: \"slate\" as const };\n return (\n <li key={o.id}>\n <button\n onClick={() => {\n setSelected(o.id);\n setShipOpen(false);\n }}\n className={`grid w-full gap-0.5 rounded-lg px-3 py-2 text-left text-sm ${\n o.id === selected ? \"bg-brand-50 text-brand-700\" : \"hover:bg-slate-100\"\n }`}\n >\n <span className=\"flex items-center justify-between gap-2\">\n <span className=\"font-medium\">{o.number}</span>\n <Badge tone={st.tone}>{st.label}</Badge>\n </span>\n <span className=\"flex items-center justify-between gap-2 text-xs text-slate-500\">\n <span className=\"truncate\">{o.customer.name}</span>\n <span>{formatCents(o.amount.totalCents)}</span>\n </span>\n <span className=\"text-xs text-slate-400\">{fmtDate(o.createdAt)}</span>\n </button>\n </li>\n );\n })}\n {visible.length === 0 && <li className=\"px-3 py-2 text-sm text-slate-500\">Geen bestellingen.</li>}\n </ul>\n </Card>\n\n {current ? (\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-base font-semibold\">\n {current.number}{\" \"}\n <Badge tone={(ORDER_STATUS_LABELS[current.status] ?? { tone: \"slate\" as const }).tone}>\n {(ORDER_STATUS_LABELS[current.status] ?? { label: current.status }).label}\n </Badge>\n </h3>\n <span className=\"text-sm text-slate-500\">Geplaatst: {fmtDate(current.createdAt)}</span>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Klant</h4>\n <p className=\"text-sm\">\n {current.customer.name}\n <br />\n <a className=\"text-brand-700 underline\" href={`mailto:${current.customer.email}`}>{current.customer.email}</a>\n {current.customer.phone && (\n <>\n <br />\n {current.customer.phone}\n </>\n )}\n </p>\n </div>\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Verzendadres</h4>\n {current.shipping ? (\n <p className=\"text-sm\">\n {current.shipping.address}\n <br />\n {current.shipping.zip} {current.shipping.city} ({current.shipping.country})\n </p>\n ) : (\n <p className=\"text-sm text-slate-500\">Geen verzending (donatie).</p>\n )}\n {current.trackingUrl && (\n <a className=\"text-sm text-brand-700 underline\" href={current.trackingUrl} target=\"_blank\" rel=\"noreferrer\">\n Track & trace ↗\n </a>\n )}\n </div>\n </div>\n\n {current.note && (\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Opmerking van de klant</h4>\n <p className=\"whitespace-pre-wrap text-sm\">{current.note}</p>\n </div>\n )}\n\n <div>\n <h4 className=\"mb-1 text-sm font-semibold\">Regels</h4>\n <table className=\"w-full text-sm\">\n <tbody>\n {current.items.map((i, idx) => (\n <tr key={idx} className=\"border-t border-slate-100 align-top\">\n <td className=\"py-1 pr-2\">\n {i.qty}× {i.name}\n {i.variantKey && <span className=\"text-slate-500\"> ({i.variantKey.split(\"|\").join(\" · \")})</span>}\n {i.kind === \"donation\" && <Badge tone=\"amber\">donatie</Badge>}\n {i.personalization &&\n Object.entries(i.personalization).map(([k, v]) => (\n <span key={k} className=\"block text-xs text-slate-600\">\n ↳ {v.text ?? v.fileName ?? \"eigen ontwerp\"}\n {v.imagePath && (\n <button\n type=\"button\"\n className=\"ml-1 text-brand-700 underline\"\n disabled={busy}\n onClick={() => download(current, v.imagePath as string)}\n >\n download\n </button>\n )}\n </span>\n ))}\n </td>\n <td className=\"py-1 text-right\">{formatCents(i.unitPriceCents * i.qty)}</td>\n </tr>\n ))}\n {(current.amount.discountCents ?? 0) > 0 && (\n <tr className=\"border-t border-slate-100 text-slate-500\">\n <td className=\"py-1 pr-2\">Korting{current.discount?.code ? ` (${current.discount.code})` : \"\"}</td>\n <td className=\"py-1 text-right\">−{formatCents(current.amount.discountCents ?? 0)}</td>\n </tr>\n )}\n <tr className=\"border-t border-slate-100 text-slate-500\">\n <td className=\"py-1 pr-2\">Verzendkosten</td>\n <td className=\"py-1 text-right\">\n {current.amount.shippingCents === 0 ? \"gratis\" : formatCents(current.amount.shippingCents)}\n </td>\n </tr>\n <tr className=\"border-t border-slate-200 font-semibold\">\n <td className=\"py-1 pr-2\">Totaal</td>\n <td className=\"py-1 text-right\">{formatCents(current.amount.totalCents)}</td>\n </tr>\n </tbody>\n </table>\n </div>\n\n {current.mail?.error && (\n <p className=\"rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-700\">\n Bevestigingsmail mislukt: {current.mail.error}\n </p>\n )}\n\n {/* Verzenden: track & trace + klant informeren */}\n {shipOpen && current.status === \"paid\" && (\n <div className=\"grid gap-3 rounded-lg border border-slate-200 p-3\">\n <Input\n placeholder=\"Track & trace-link (optioneel, https://…)\"\n value={trackingUrl}\n onChange={(e) => setTrackingUrl(e.target.value)}\n />\n <div className=\"flex items-center gap-4\">\n <Switch checked={notify} onCheckedChange={setNotify} label=\"Klant per e-mail informeren\" />\n <Button size=\"sm\" disabled={busy} onClick={() => setStatus(current, \"shipped\")}>\n Bevestig verzending\n </Button>\n </div>\n </div>\n )}\n\n <div className=\"flex flex-wrap items-center gap-2 border-t border-slate-100 pt-4\">\n {current.status === \"paid\" && !shipOpen && (\n <Button size=\"sm\" onClick={() => setShipOpen(true)}>Markeer als verzonden</Button>\n )}\n {[\"pending\", \"paid\"].includes(current.status) && (\n <Button\n size=\"sm\"\n variant=\"secondary\"\n disabled={busy}\n onClick={async () => {\n const ok = await confirm({\n title: `Bestelling ${current.number} annuleren?`,\n description: notify ? \"De klant ontvangt een e-mail.\" : undefined,\n });\n if (ok) void setStatus(current, \"cancelled\");\n }}\n >\n Annuleer\n </Button>\n )}\n {(current.status === \"paid\" || current.status === \"shipped\") && (\n <>\n <Button size=\"sm\" variant=\"secondary\" disabled={busy} onClick={() => resendMail(current)}>\n Mail opnieuw versturen\n </Button>\n <Button size=\"sm\" variant=\"danger\" disabled={busy} onClick={() => refund(current)}>\n Terugbetalen\n </Button>\n </>\n )}\n {current.invoicePath && (\n <Button size=\"sm\" variant=\"secondary\" disabled={busy} onClick={() => viewInvoice(current, current.invoicePath as string)}>\n Factuur bekijken\n </Button>\n )}\n {current.stripe?.paymentIntentId && (\n <a\n className=\"ml-auto text-sm text-brand-700 underline\"\n href={`https://dashboard.stripe.com/payments/${current.stripe.paymentIntentId}`}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n Bekijk in Stripe ↗\n </a>\n )}\n </div>\n </div>\n </Card>\n ) : (\n <Card>\n <p className=\"text-sm text-slate-500\">Selecteer een bestelling.</p>\n </Card>\n )}\n </div>\n\n <Dialog open={!!invoice} onOpenChange={(o) => !o && setInvoice(null)}>\n {invoice && (\n <DialogContent title={`Factuur ${invoice.number}`} width=\"min(92vw, 48rem)\">\n <iframe\n title={`Factuur ${invoice.number}`}\n src={invoice.url}\n className=\"h-[70vh] w-full rounded-lg border border-slate-200 bg-white\"\n />\n <div className=\"mt-3 flex items-center gap-2\">\n <a href={invoice.url} target=\"_blank\" rel=\"noreferrer\" download={`factuur-${invoice.number}.pdf`}>\n <Button size=\"sm\" variant=\"secondary\">Downloaden</Button>\n </a>\n <a href={invoice.url} target=\"_blank\" rel=\"noreferrer\" className=\"text-sm text-brand-700 underline\">\n Openen in nieuw tabblad ↗\n </a>\n <DialogClose asChild>\n <Button size=\"sm\" variant=\"ghost\" className=\"ml-auto\">Sluiten</Button>\n </DialogClose>\n </div>\n </DialogContent>\n )}\n </Dialog>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { addDoc, collection, deleteDoc, doc, onSnapshot, setDoc } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
6
|
import {
|
|
7
7
|
ProductSchema,
|
|
8
8
|
formatCents
|
|
9
|
-
} from "../../schema/shop";
|
|
10
|
-
import { Badge, Button, Card, Field, Input, Textarea } from "../ui/primitives";
|
|
11
|
-
import { Select } from "../ui/select";
|
|
12
|
-
import { Switch } from "../ui/switch";
|
|
13
|
-
import { useToast } from "../ui/toast";
|
|
14
|
-
import { useConfirm } from "../ui/ConfirmDialog";
|
|
15
|
-
import { MediaPickerButton } from "../media/MediaPicker";
|
|
16
|
-
import { slugify } from "../lib/slugify";
|
|
17
|
-
import { allVariantKeys, centsToEuroInput, eurosToCents } from "./lib";
|
|
9
|
+
} from "../../schema/shop.js";
|
|
10
|
+
import { Badge, Button, Card, Field, Input, Textarea } from "../ui/primitives.js";
|
|
11
|
+
import { Select } from "../ui/select.js";
|
|
12
|
+
import { Switch } from "../ui/switch.js";
|
|
13
|
+
import { useToast } from "../ui/toast.js";
|
|
14
|
+
import { useConfirm } from "../ui/ConfirmDialog.js";
|
|
15
|
+
import { MediaPickerButton } from "../media/MediaPicker.js";
|
|
16
|
+
import { slugify } from "../lib/slugify.js";
|
|
17
|
+
import { allVariantKeys, centsToEuroInput, eurosToCents } from "./lib.js";
|
|
18
18
|
const STATUS_OPTIONS = [
|
|
19
19
|
{ value: "draft", label: "Concept" },
|
|
20
20
|
{ value: "active", label: "Actief" },
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs";
|
|
4
|
-
import { ProductsTab } from "./ProductsTab";
|
|
5
|
-
import { CategoriesTab } from "./CategoriesTab";
|
|
6
|
-
import { OrdersTab } from "./OrdersTab";
|
|
7
|
-
import { DiscountsTab } from "./DiscountsTab";
|
|
8
|
-
import { ShopSettingsTab } from "./ShopSettingsTab";
|
|
9
|
-
import { ConnectionsTab } from "./ConnectionsTab";
|
|
10
|
-
import { MailTemplates } from "../settings/MailTemplates";
|
|
11
|
-
import { SHOP_TEMPLATE_KEYS } from "../../schema/mail";
|
|
3
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs.js";
|
|
4
|
+
import { ProductsTab } from "./ProductsTab.js";
|
|
5
|
+
import { CategoriesTab } from "./CategoriesTab.js";
|
|
6
|
+
import { OrdersTab } from "./OrdersTab.js";
|
|
7
|
+
import { DiscountsTab } from "./DiscountsTab.js";
|
|
8
|
+
import { ShopSettingsTab } from "./ShopSettingsTab.js";
|
|
9
|
+
import { ConnectionsTab } from "./ConnectionsTab.js";
|
|
10
|
+
import { MailTemplates } from "../settings/MailTemplates.js";
|
|
11
|
+
import { SHOP_TEMPLATE_KEYS } from "../../schema/mail.js";
|
|
12
12
|
function ShopPanel({ siteId }) {
|
|
13
13
|
return /* @__PURE__ */ jsxs(Tabs, { defaultValue: "orders", children: [
|
|
14
14
|
/* @__PURE__ */ jsxs(TabsList, { children: [
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { doc, getDoc, setDoc } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
6
|
-
import { Button, Card, Field, Input } from "../ui/primitives";
|
|
7
|
-
import { useToast } from "../ui/toast";
|
|
8
|
-
import { centsToEuroInput, eurosToCents } from "./lib";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
|
+
import { Button, Card, Field, Input } from "../ui/primitives.js";
|
|
7
|
+
import { useToast } from "../ui/toast.js";
|
|
8
|
+
import { centsToEuroInput, eurosToCents } from "./lib.js";
|
|
9
9
|
function ShopSettingsTab({ siteId }) {
|
|
10
10
|
const { toast } = useToast();
|
|
11
11
|
const [cfg, setCfg] = useState(null);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Geef `shopPanel` mee aan `AdminApp extraPanels={[shopPanel]}` op sites met shop
|
|
4
4
|
* (of gebruik de gegenereerde `enabledPanels`, zie docs/MODULES.md).
|
|
5
5
|
*/
|
|
6
|
-
import type { PanelDefinition } from "../panelRegistry";
|
|
7
|
-
export { ShopPanel } from "./ShopPanel";
|
|
6
|
+
import type { PanelDefinition } from "../panelRegistry.js";
|
|
7
|
+
export { ShopPanel } from "./ShopPanel.js";
|
|
8
8
|
/** Paneldefinitie zoals die vroeger in builtinPanels stond (order 45, "Webwinkel"). */
|
|
9
9
|
export declare const shopPanel: PanelDefinition;
|
package/dist/admin/shop/index.js
CHANGED
package/dist/admin/shop/lib.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getFunctions, httpsCallable } from "firebase/functions";
|
|
3
|
-
import { getFirebaseApp } from "../../firebase/client";
|
|
4
|
-
import { functionsRegion } from "../../firebase/region";
|
|
3
|
+
import { getFirebaseApp } from "../../firebase/client.js";
|
|
4
|
+
import { functionsRegion } from "../../firebase/region.js";
|
|
5
5
|
function shopCallable(name) {
|
|
6
6
|
return async (data) => {
|
|
7
7
|
const app = getFirebaseApp();
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { collection, getDocs } from "firebase/firestore";
|
|
5
|
-
import { getDb } from "../../firebase/client";
|
|
6
|
-
import { Card } from "../ui/primitives";
|
|
5
|
+
import { getDb } from "../../firebase/client.js";
|
|
6
|
+
import { Card } from "../ui/primitives.js";
|
|
7
7
|
function StatsPanel({ siteId }) {
|
|
8
8
|
const [months, setMonths] = useState([]);
|
|
9
9
|
const [loading, setLoading] = useState(true);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useRef } from "react";
|
|
4
|
-
import { Button } from "./primitives";
|
|
4
|
+
import { Button } from "./primitives.js";
|
|
5
5
|
let keyCounter = 0;
|
|
6
6
|
const genKey = () => `row-${++keyCounter}`;
|
|
7
7
|
function ArrayEditor({
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
const PADEN = {
|
|
4
|
+
pages: "M4 3h9l4 4v14H4z M13 3v5h4",
|
|
5
|
+
news: "M4 5h16v14H4z M7 9h10 M7 13h10 M7 17h6",
|
|
6
|
+
media: "M3 5h18v14H3z M3 15l5-5 4 4 3-3 6 6",
|
|
7
|
+
forms: "M5 3h14v18H5z M9 8h6 M9 12h6 M9 16h3",
|
|
8
|
+
stats: "M4 20V10 M10 20V4 M16 20v-7 M22 20H2",
|
|
9
|
+
blocks: "M4 4h7v7H4z M13 4h7v7h-7z M4 13h7v7H4z M13 13h7v7h-7z",
|
|
10
|
+
settings: "M12 15a3 3 0 100-6 3 3 0 000 6z M19.4 15a1.6 1.6 0 00.3 1.8l.1.1a2 2 0 11-2.8 2.8l-.1-.1a1.6 1.6 0 00-2.7 1.1V21a2 2 0 11-4 0v-.1A1.6 1.6 0 007.5 19.4l-.1.1a2 2 0 11-2.8-2.8l.1-.1A1.6 1.6 0 003 14.6H3a2 2 0 110-4h.1A1.6 1.6 0 004.6 7.5l-.1-.1a2 2 0 112.8-2.8l.1.1a1.6 1.6 0 001.8.3H9.4a1.6 1.6 0 001-1.5V3a2 2 0 114 0v.1a1.6 1.6 0 001 1.5 1.6 1.6 0 001.8-.3l.1-.1a2 2 0 112.8 2.8l-.1.1a1.6 1.6 0 00-.3 1.8v.1a1.6 1.6 0 001.5 1H21a2 2 0 110 4h-.1a1.6 1.6 0 00-1.5 1z"
|
|
11
|
+
};
|
|
12
|
+
const FALLBACK = "M12 3l9 9-9 9-9-9z";
|
|
13
|
+
function PanelIcon({ id }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(
|
|
15
|
+
"svg",
|
|
16
|
+
{
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
viewBox: "0 0 24 24",
|
|
19
|
+
width: "18",
|
|
20
|
+
height: "18",
|
|
21
|
+
fill: "none",
|
|
22
|
+
stroke: "currentColor",
|
|
23
|
+
strokeWidth: "1.6",
|
|
24
|
+
strokeLinecap: "round",
|
|
25
|
+
strokeLinejoin: "round",
|
|
26
|
+
className: "shrink-0",
|
|
27
|
+
children: (PADEN[id] ?? FALLBACK).split(" M").map((d, i) => /* @__PURE__ */ jsx("path", { d: i === 0 ? d : `M${d}` }, i))
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
PanelIcon
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=PanelIcon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/ui/PanelIcon.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Kleine lijn-iconen voor de zijbalk. Bewust inline SVG en geen icoon-pakket: het zijn er zeven,\n * en een dependency voor zeven paden is niet te verdedigen in een bundel die élke klantsite laadt.\n *\n * Iconen zijn hier geen versiering maar herkenning: de beheerder van een hoveniersbedrijf logt een\n * keer per maand in en zoekt \"waar stond die tekst ook alweer\" — een vorm vindt hij sneller terug\n * dan een woord.\n */\nconst PADEN: Record<string, string> = {\n pages: \"M4 3h9l4 4v14H4z M13 3v5h4\",\n news: \"M4 5h16v14H4z M7 9h10 M7 13h10 M7 17h6\",\n media: \"M3 5h18v14H3z M3 15l5-5 4 4 3-3 6 6\",\n forms: \"M5 3h14v18H5z M9 8h6 M9 12h6 M9 16h3\",\n stats: \"M4 20V10 M10 20V4 M16 20v-7 M22 20H2\",\n blocks: \"M4 4h7v7H4z M13 4h7v7h-7z M4 13h7v7H4z M13 13h7v7h-7z\",\n settings: \"M12 15a3 3 0 100-6 3 3 0 000 6z M19.4 15a1.6 1.6 0 00.3 1.8l.1.1a2 2 0 11-2.8 2.8l-.1-.1a1.6 1.6 0 00-2.7 1.1V21a2 2 0 11-4 0v-.1A1.6 1.6 0 007.5 19.4l-.1.1a2 2 0 11-2.8-2.8l.1-.1A1.6 1.6 0 003 14.6H3a2 2 0 110-4h.1A1.6 1.6 0 004.6 7.5l-.1-.1a2 2 0 112.8-2.8l.1.1a1.6 1.6 0 001.8.3H9.4a1.6 1.6 0 001-1.5V3a2 2 0 114 0v.1a1.6 1.6 0 001 1.5 1.6 1.6 0 001.8-.3l.1-.1a2 2 0 112.8 2.8l-.1.1a1.6 1.6 0 00-.3 1.8v.1a1.6 1.6 0 001.5 1H21a2 2 0 110 4h-.1a1.6 1.6 0 00-1.5 1z\",\n};\n/** Onbekende module (klant-paneel): een neutrale ruit, zodat het rijtje visueel niet breekt. */\nconst FALLBACK = \"M12 3l9 9-9 9-9-9z\";\n\nexport function PanelIcon({ id }: { id: string }) {\n return (\n <svg\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n width=\"18\"\n height=\"18\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"shrink-0\"\n >\n {(PADEN[id] ?? FALLBACK).split(\" M\").map((d, i) => (\n <path key={i} d={i === 0 ? d : `M${d}`} />\n ))}\n </svg>\n );\n}\n"],"mappings":";AAqCQ;AA3BR,MAAM,QAAgC;AAAA,EACpC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AACZ;AAEA,MAAM,WAAW;AAEV,SAAS,UAAU,EAAE,GAAG,GAAmB;AAChD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,QAAO;AAAA,MACP,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,WAAU;AAAA,MAER,iBAAM,EAAE,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC,GAAG,MAC3C,oBAAC,UAAa,GAAG,MAAM,IAAI,IAAI,IAAI,CAAC,MAAzB,CAA6B,CACzC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export declare function Dialog({ open: controlled, onOpenChange, children, }: {
|
|
3
|
+
open?: boolean;
|
|
4
|
+
onOpenChange?: (v: boolean) => void;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
7
|
+
/** `asChild` blijft geaccepteerd voor een ongewijzigde aanroep-API; het kind wordt altijd gekloond. */
|
|
8
|
+
export declare function DialogTrigger({ children }: {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function DialogClose({ children }: {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
asChild?: boolean;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
export declare function DialogContent({ title, width, className, children, }: {
|
|
6
17
|
title: string;
|
|
18
|
+
/** Breedte van de dialoog. Verving de `max-w-*`-klassen: Astryx zet de breedte inline. */
|
|
19
|
+
width?: number | string;
|
|
20
|
+
className?: string;
|
|
21
|
+
children: ReactNode;
|
|
7
22
|
}): import("react").JSX.Element;
|
|
8
|
-
export declare function DialogDescription({ className, ...props }: React.ComponentProps<
|
|
23
|
+
export declare function DialogDescription({ className, ...props }: React.ComponentProps<"p">): import("react").JSX.Element;
|
|
9
24
|
export declare function DialogFooter({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
|