@xiwebdesign/xicms-core 7.26.0 → 7.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/shop/ShopSettingsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { doc, getDoc } from \"firebase/firestore\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { callable } from \"../../firebase/functionsClient\";\nimport { Button, Card, Field, Input } from \"../ui/primitives\";\nimport { useToast } from \"../ui/toast\";\nimport { centsToEuroInput, eurosToCents } from \"./lib\";\n\n/**\n * Winkel-instellingen — leest/schrijft DEZELFDE module-config als Instellingen → Modules\n * (settings/public.modules.shop.config; geen tweede bron van waarheid), maar met winkel-\n * presentatie: bedragen in euro's en uitleg per veld. Siteadmin-only (rules).\n */\ninterface ShopCfg {\n shippingFlatCents?: number;\n shippingFreeFromCents?: number;\n orderPrefix?: string;\n currency?: string;\n businessName?: string;\n businessAddress?: string;\n businessZip?: string;\n businessCity?: string;\n businessKvk?: string;\n businessBtw?: string;\n [k: string]: unknown;\n}\n\nexport function ShopSettingsTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const [cfg, setCfg] = useState<ShopCfg | null>(null);\n const [shipInput, setShipInput] = useState(\"\");\n const [freeInput, setFreeInput] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [zones, setZones] = useState<{ naam: string; landen: string; flat: string; free: string }[]>([]);\n\n useEffect(() => {\n const db = getDb();\n if (!db) return;\n void getDoc(doc(db, \"sites\", siteId, \"settings\", \"public\")).then((snap) => {\n const modules = (snap.data()?.modules ?? {}) as Record<string, { config?: ShopCfg } | boolean>;\n const entry = modules.shop;\n const c = typeof entry === \"object\" && entry !== null ? (entry.config ?? {}) : {};\n setCfg(c);\n setShipInput(centsToEuroInput(c.shippingFlatCents ?? 495));\n setFreeInput(c.shippingFreeFromCents ? centsToEuroInput(c.shippingFreeFromCents) : \"\");\n setZones(\n ((c.shippingZones as { naam: string; landen?: string[]; flatCents: number; freeFromCents?: number }[] | undefined) ?? []).map((z) => ({\n naam: z.naam,\n landen: (z.landen ?? []).join(\", \"),\n flat: centsToEuroInput(z.flatCents),\n free: z.freeFromCents ? centsToEuroInput(z.freeFromCents) : \"\",\n })),\n );\n });\n }, [siteId]);\n\n async function save() {\n const app = getFirebaseApp();\n if (!app || !cfg) return;\n setBusy(true);\n try {\n const next: ShopCfg = {\n ...cfg,\n shippingFlatCents: eurosToCents(shipInput) ?? 495,\n shippingFreeFromCents: freeInput.trim() === \"\" ? 0 : (eurosToCents(freeInput) ?? 0),\n shippingZones: zones\n .filter((z) => z.naam.trim())\n .map((z) => ({\n naam: z.naam.trim(),\n // \"BE, DE\" → [\"BE\",\"DE\"]; leeg = de \"overige landen\"-zone.\n landen: z.landen.split(/[,;\\s]+/).map((l) => l.trim().toUpperCase()).filter(Boolean).slice(0, 60),\n flatCents: eurosToCents(z.flat) ?? 0,\n freeFromCents: z.free.trim() === \"\" ? 0 : (eurosToCents(z.free) ?? 0),\n })),\n };\n /**\n * Via de saveSiteSettings-callable, NIET rechtstreeks naar Firestore. Deze tab deed nog een\n * directe setDoc op settings/public, maar die deur zit sinds de settings-verstrakking in de\n * rules voor iederéén dicht (ook superadmin) — de klant kreeg letterlijk \"Missing or\n * insufficient permissions\" bij het opslaan van verzendkosten. De callable is bovendien de\n * enige route die site/public consistent houdt én de cache-tag pusht, zodat de nieuwe\n * verzendkosten binnen seconden op de live winkel staan i.p.v. na het ISR-vangnet.\n * set+merge in de callable merged diep: de enabled-vlag en andere modules blijven staan.\n */\n const fn = callable(app, \"saveSiteSettings\");\n await fn({ siteId, settings: { modules: { shop: { config: next } } } });\n setCfg(next);\n toast({ title: \"Instellingen opgeslagen\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Opslaan mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n if (!cfg) return <Card><p className=\"text-sm text-slate-500\">Laden…</p></Card>;\n\n const set = (k: string, v: string) => setCfg((p) => ({ ...p, [k]: v }));\n\n /** Wettelijk minimum op een factuur: wie ben je, waar zit je, en onder welke nummers. */\n const ontbrekend = (\n [\n [\"bedrijfsnaam\", cfg.businessName],\n [\"adres\", cfg.businessAddress],\n [\"postcode\", cfg.businessZip],\n [\"plaats\", cfg.businessCity],\n [\"KVK-nummer\", cfg.businessKvk],\n [\"btw-nummer\", cfg.businessBtw],\n ] as [string, unknown][]\n )\n .filter(([, v]) => !String(v ?? \"\").trim())\n .map(([label]) => label);\n\n return (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <Card>\n <h3 className=\"mb-3 text-sm font-semibold\">Verzending & bestellen</h3>\n <div className=\"grid gap-4\">\n <Field label=\"Verzendkosten (€)\" hint=\"Vast bedrag per bestelling binnen Nederland\">\n <Input value={shipInput} onChange={(e) => setShipInput(e.target.value)} placeholder=\"4,95\" className=\"w-32\" />\n </Field>\n <Field label=\"Gratis verzending vanaf (€)\" hint=\"Leeg = nooit gratis\">\n <Input value={freeInput} onChange={(e) => setFreeInput(e.target.value)} placeholder=\"50,00\" className=\"w-32\" />\n </Field>\n <Field label=\"Ordernummer-prefix\" hint=\"Bijv. CKC → CKC-2026-0001\">\n <Input value={String(cfg.orderPrefix ?? \"ORDER\")} onChange={(e) => set(\"orderPrefix\", e.target.value.toUpperCase().slice(0, 12))} className=\"w-32\" />\n </Field>\n\n {/* Zones: pas nodig zodra je buiten Nederland verzendt. Zonder zones geldt het tarief\n hierboven voor alles — precies zoals het altijd werkte. */}\n <div className=\"border-t border-slate-100 pt-4\">\n <p className=\"text-sm font-medium text-slate-800\">Verzenden naar het buitenland</p>\n <p className=\"mt-1 mb-3 text-xs text-slate-500\">\n Zonder zones geldt het tarief hierboven voor élke bestelling. Voeg een zone toe om per\n land een eigen tarief te rekenen. Een zone <strong>zonder landen</strong> is \"alle\n overige landen\"; laat je die weg, dan verzend je alléén naar de genoemde landen — de\n afrekenpagina toont dan precies die keuze.\n </p>\n <div className=\"grid gap-2\">\n {zones.map((z, i) => {\n const zet = (patch: Partial<(typeof zones)[number]>) =>\n setZones((p) => p.map((x, j) => (j === i ? { ...x, ...patch } : x)));\n return (\n <div key={i} className=\"grid grid-cols-[1fr_1fr_90px_90px_auto] items-center gap-2\">\n <Input value={z.naam} onChange={(e) => zet({ naam: e.target.value })} placeholder=\"Naam (bv. België)\" />\n <Input value={z.landen} onChange={(e) => zet({ landen: e.target.value })} placeholder=\"BE, DE (leeg = overige)\" />\n <Input value={z.flat} onChange={(e) => zet({ flat: e.target.value })} placeholder=\"Tarief €\" />\n <Input value={z.free} onChange={(e) => zet({ free: e.target.value })} placeholder=\"Gratis v.a. €\" />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setZones((p) => p.filter((_, j) => j !== i))}>✕</Button>\n </div>\n );\n })}\n <div>\n <Button size=\"sm\" variant=\"secondary\" disabled={zones.length >= 10} onClick={() => setZones((p) => [...p, { naam: \"\", landen: \"\", flat: \"\", free: \"\" }])}>\n + Zone\n </Button>\n </div>\n </div>\n </div>\n </div>\n </Card>\n\n <Card>\n <h3 className=\"mb-1 text-sm font-semibold\">Bedrijfsgegevens (factuur)</h3>\n <p className=\"mb-3 text-xs text-slate-500\">Deze gegevens komen op de factuur-PDF die klanten bij hun bestelling krijgen.</p>\n {/* Zonder deze gegevens gaat er wél een factuur uit, maar zonder afzender — en een factuur\n zonder bedrijfsnaam, adres en KVK/btw is fiscaal niet geldig. Dat gebeurde stil. */}\n {ontbrekend.length > 0 && (\n <p className=\"mb-3 rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-800\">\n <strong>Nog invullen:</strong> {ontbrekend.join(\", \")}. Zonder deze gegevens staat er geen\n afzender op je factuur, en dan is hij voor de Belastingdienst niet geldig.\n </p>\n )}\n <div className=\"grid gap-3\">\n <Field label=\"Bedrijfsnaam\"><Input value={String(cfg.businessName ?? \"\")} onChange={(e) => set(\"businessName\", e.target.value)} /></Field>\n <Field label=\"Adres\"><Input value={String(cfg.businessAddress ?? \"\")} onChange={(e) => set(\"businessAddress\", e.target.value)} /></Field>\n <div className=\"grid grid-cols-[120px_1fr] gap-3\">\n <Field label=\"Postcode\"><Input value={String(cfg.businessZip ?? \"\")} onChange={(e) => set(\"businessZip\", e.target.value)} /></Field>\n <Field label=\"Plaats\"><Input value={String(cfg.businessCity ?? \"\")} onChange={(e) => set(\"businessCity\", e.target.value)} /></Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"KVK-nummer\"><Input value={String(cfg.businessKvk ?? \"\")} onChange={(e) => set(\"businessKvk\", e.target.value)} /></Field>\n <Field label=\"Btw-nummer\"><Input value={String(cfg.businessBtw ?? \"\")} onChange={(e) => set(\"businessBtw\", e.target.value)} /></Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Contact-e-mail\" hint=\"Staat op de factuur en onderaan elke mail\">\n <Input value={String(cfg.businessEmail ?? \"\")} onChange={(e) => set(\"businessEmail\", e.target.value)} />\n </Field>\n <Field label=\"Telefoon (optioneel)\">\n <Input value={String(cfg.businessPhone ?? \"\")} onChange={(e) => set(\"businessPhone\", e.target.value)} />\n </Field>\n </div>\n </div>\n </Card>\n\n <div className=\"lg:col-span-2\">\n <Button onClick={save} disabled={busy}>Opslaan</Button>\n <p className=\"mt-2 text-xs text-slate-500\">\n Paden en valuta van de winkel staan onder Instellingen → Modules → Webwinkel.\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/admin/shop/ShopSettingsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { doc, getDoc } from \"firebase/firestore\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { callable } from \"../../firebase/functionsClient\";\nimport { Button, Card, Field, Input } from \"../ui/primitives\";\nimport { Switch } from \"../ui/switch\";\nimport { useToast } from \"../ui/toast\";\nimport { centsToEuroInput, eurosToCents } from \"./lib\";\n\n/**\n * Winkel-instellingen — leest/schrijft DEZELFDE module-config als Instellingen → Modules\n * (settings/public.modules.shop.config; geen tweede bron van waarheid), maar met winkel-\n * presentatie: bedragen in euro's en uitleg per veld. Siteadmin-only (rules).\n */\ninterface ShopCfg {\n shippingFlatCents?: number;\n shippingFreeFromCents?: number;\n orderPrefix?: string;\n currency?: string;\n businessName?: string;\n businessAddress?: string;\n businessZip?: string;\n businessCity?: string;\n businessKvk?: string;\n businessBtw?: string;\n giftWrapEnabled?: boolean;\n giftWrapPriceCents?: number;\n [k: string]: unknown;\n}\n\nexport function ShopSettingsTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const [cfg, setCfg] = useState<ShopCfg | null>(null);\n const [shipInput, setShipInput] = useState(\"\");\n const [freeInput, setFreeInput] = useState(\"\");\n const [giftWrapInput, setGiftWrapInput] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [zones, setZones] = useState<{ naam: string; landen: string; flat: string; free: string }[]>([]);\n\n useEffect(() => {\n const db = getDb();\n if (!db) return;\n void getDoc(doc(db, \"sites\", siteId, \"settings\", \"public\")).then((snap) => {\n const modules = (snap.data()?.modules ?? {}) as Record<string, { config?: ShopCfg } | boolean>;\n const entry = modules.shop;\n const c = typeof entry === \"object\" && entry !== null ? (entry.config ?? {}) : {};\n setCfg(c);\n setShipInput(centsToEuroInput(c.shippingFlatCents ?? 495));\n setFreeInput(c.shippingFreeFromCents ? centsToEuroInput(c.shippingFreeFromCents) : \"\");\n setGiftWrapInput(centsToEuroInput(c.giftWrapPriceCents ?? 0));\n setZones(\n ((c.shippingZones as { naam: string; landen?: string[]; flatCents: number; freeFromCents?: number }[] | undefined) ?? []).map((z) => ({\n naam: z.naam,\n landen: (z.landen ?? []).join(\", \"),\n flat: centsToEuroInput(z.flatCents),\n free: z.freeFromCents ? centsToEuroInput(z.freeFromCents) : \"\",\n })),\n );\n });\n }, [siteId]);\n\n async function save() {\n const app = getFirebaseApp();\n if (!app || !cfg) return;\n setBusy(true);\n try {\n const next: ShopCfg = {\n ...cfg,\n shippingFlatCents: eurosToCents(shipInput) ?? 495,\n shippingFreeFromCents: freeInput.trim() === \"\" ? 0 : (eurosToCents(freeInput) ?? 0),\n giftWrapPriceCents: eurosToCents(giftWrapInput) ?? 0,\n shippingZones: zones\n .filter((z) => z.naam.trim())\n .map((z) => ({\n naam: z.naam.trim(),\n // \"BE, DE\" → [\"BE\",\"DE\"]; leeg = de \"overige landen\"-zone.\n landen: z.landen.split(/[,;\\s]+/).map((l) => l.trim().toUpperCase()).filter(Boolean).slice(0, 60),\n flatCents: eurosToCents(z.flat) ?? 0,\n freeFromCents: z.free.trim() === \"\" ? 0 : (eurosToCents(z.free) ?? 0),\n })),\n };\n /**\n * Via de saveSiteSettings-callable, NIET rechtstreeks naar Firestore. Deze tab deed nog een\n * directe setDoc op settings/public, maar die deur zit sinds de settings-verstrakking in de\n * rules voor iederéén dicht (ook superadmin) — de klant kreeg letterlijk \"Missing or\n * insufficient permissions\" bij het opslaan van verzendkosten. De callable is bovendien de\n * enige route die site/public consistent houdt én de cache-tag pusht, zodat de nieuwe\n * verzendkosten binnen seconden op de live winkel staan i.p.v. na het ISR-vangnet.\n * set+merge in de callable merged diep: de enabled-vlag en andere modules blijven staan.\n */\n const fn = callable(app, \"saveSiteSettings\");\n await fn({ siteId, settings: { modules: { shop: { config: next } } } });\n setCfg(next);\n toast({ title: \"Instellingen opgeslagen\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Opslaan mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n if (!cfg) return <Card><p className=\"text-sm text-slate-500\">Laden…</p></Card>;\n\n const set = (k: string, v: string) => setCfg((p) => ({ ...p, [k]: v }));\n\n /** Wettelijk minimum op een factuur: wie ben je, waar zit je, en onder welke nummers. */\n const ontbrekend = (\n [\n [\"bedrijfsnaam\", cfg.businessName],\n [\"adres\", cfg.businessAddress],\n [\"postcode\", cfg.businessZip],\n [\"plaats\", cfg.businessCity],\n [\"KVK-nummer\", cfg.businessKvk],\n [\"btw-nummer\", cfg.businessBtw],\n ] as [string, unknown][]\n )\n .filter(([, v]) => !String(v ?? \"\").trim())\n .map(([label]) => label);\n\n return (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <Card>\n <h3 className=\"mb-3 text-sm font-semibold\">Verzending & bestellen</h3>\n <div className=\"grid gap-4\">\n <Field label=\"Verzendkosten (€)\" hint=\"Vast bedrag per bestelling binnen Nederland\">\n <Input value={shipInput} onChange={(e) => setShipInput(e.target.value)} placeholder=\"4,95\" className=\"w-32\" />\n </Field>\n <Field label=\"Gratis verzending vanaf (€)\" hint=\"Leeg = nooit gratis\">\n <Input value={freeInput} onChange={(e) => setFreeInput(e.target.value)} placeholder=\"50,00\" className=\"w-32\" />\n </Field>\n <Field label=\"Ordernummer-prefix\" hint=\"Bijv. CKC → CKC-2026-0001\">\n <Input value={String(cfg.orderPrefix ?? \"ORDER\")} onChange={(e) => set(\"orderPrefix\", e.target.value.toUpperCase().slice(0, 12))} className=\"w-32\" />\n </Field>\n\n {/* Zones: pas nodig zodra je buiten Nederland verzendt. Zonder zones geldt het tarief\n hierboven voor alles — precies zoals het altijd werkte. */}\n <div className=\"border-t border-slate-100 pt-4\">\n <p className=\"text-sm font-medium text-slate-800\">Verzenden naar het buitenland</p>\n <p className=\"mt-1 mb-3 text-xs text-slate-500\">\n Zonder zones geldt het tarief hierboven voor élke bestelling. Voeg een zone toe om per\n land een eigen tarief te rekenen. Een zone <strong>zonder landen</strong> is \"alle\n overige landen\"; laat je die weg, dan verzend je alléén naar de genoemde landen — de\n afrekenpagina toont dan precies die keuze.\n </p>\n <div className=\"grid gap-2\">\n {zones.map((z, i) => {\n const zet = (patch: Partial<(typeof zones)[number]>) =>\n setZones((p) => p.map((x, j) => (j === i ? { ...x, ...patch } : x)));\n return (\n <div key={i} className=\"grid grid-cols-[1fr_1fr_90px_90px_auto] items-center gap-2\">\n <Input value={z.naam} onChange={(e) => zet({ naam: e.target.value })} placeholder=\"Naam (bv. België)\" />\n <Input value={z.landen} onChange={(e) => zet({ landen: e.target.value })} placeholder=\"BE, DE (leeg = overige)\" />\n <Input value={z.flat} onChange={(e) => zet({ flat: e.target.value })} placeholder=\"Tarief €\" />\n <Input value={z.free} onChange={(e) => zet({ free: e.target.value })} placeholder=\"Gratis v.a. €\" />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setZones((p) => p.filter((_, j) => j !== i))}>✕</Button>\n </div>\n );\n })}\n <div>\n <Button size=\"sm\" variant=\"secondary\" disabled={zones.length >= 10} onClick={() => setZones((p) => [...p, { naam: \"\", landen: \"\", flat: \"\", free: \"\" }])}>\n + Zone\n </Button>\n </div>\n </div>\n </div>\n </div>\n </Card>\n\n <Card>\n <h3 className=\"mb-3 text-sm font-semibold\">Cadeauverpakking</h3>\n <div className=\"grid gap-4\">\n <Switch\n checked={cfg.giftWrapEnabled ?? false}\n onCheckedChange={(v) => setCfg((p) => ({ ...p, giftWrapEnabled: v }))}\n label=\"Cadeauverpakking aanbieden bij het afrekenen\"\n />\n {cfg.giftWrapEnabled && (\n <Field label=\"Meerprijs (€)\" hint=\"Komt als aparte regel op de bestelling en de factuur; de klant kan een kaartjestekst + opmerking meegeven\">\n <Input value={giftWrapInput} onChange={(e) => setGiftWrapInput(e.target.value)} placeholder=\"3,95\" className=\"w-32\" />\n </Field>\n )}\n </div>\n </Card>\n\n <Card>\n <h3 className=\"mb-1 text-sm font-semibold\">Bedrijfsgegevens (factuur)</h3>\n <p className=\"mb-3 text-xs text-slate-500\">Deze gegevens komen op de factuur-PDF die klanten bij hun bestelling krijgen.</p>\n {/* Zonder deze gegevens gaat er wél een factuur uit, maar zonder afzender — en een factuur\n zonder bedrijfsnaam, adres en KVK/btw is fiscaal niet geldig. Dat gebeurde stil. */}\n {ontbrekend.length > 0 && (\n <p className=\"mb-3 rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-800\">\n <strong>Nog invullen:</strong> {ontbrekend.join(\", \")}. Zonder deze gegevens staat er geen\n afzender op je factuur, en dan is hij voor de Belastingdienst niet geldig.\n </p>\n )}\n <div className=\"grid gap-3\">\n <Field label=\"Bedrijfsnaam\"><Input value={String(cfg.businessName ?? \"\")} onChange={(e) => set(\"businessName\", e.target.value)} /></Field>\n <Field label=\"Adres\"><Input value={String(cfg.businessAddress ?? \"\")} onChange={(e) => set(\"businessAddress\", e.target.value)} /></Field>\n <div className=\"grid grid-cols-[120px_1fr] gap-3\">\n <Field label=\"Postcode\"><Input value={String(cfg.businessZip ?? \"\")} onChange={(e) => set(\"businessZip\", e.target.value)} /></Field>\n <Field label=\"Plaats\"><Input value={String(cfg.businessCity ?? \"\")} onChange={(e) => set(\"businessCity\", e.target.value)} /></Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"KVK-nummer\"><Input value={String(cfg.businessKvk ?? \"\")} onChange={(e) => set(\"businessKvk\", e.target.value)} /></Field>\n <Field label=\"Btw-nummer\"><Input value={String(cfg.businessBtw ?? \"\")} onChange={(e) => set(\"businessBtw\", e.target.value)} /></Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Contact-e-mail\" hint=\"Staat op de factuur en onderaan elke mail\">\n <Input value={String(cfg.businessEmail ?? \"\")} onChange={(e) => set(\"businessEmail\", e.target.value)} />\n </Field>\n <Field label=\"Telefoon (optioneel)\">\n <Input value={String(cfg.businessPhone ?? \"\")} onChange={(e) => set(\"businessPhone\", e.target.value)} />\n </Field>\n </div>\n </div>\n </Card>\n\n <div className=\"lg:col-span-2\">\n <Button onClick={save} disabled={busy}>Opslaan</Button>\n <p className=\"mt-2 text-xs text-slate-500\">\n Paden en valuta van de winkel staan onder Instellingen → Modules → Webwinkel.\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -317,7 +317,7 @@ function VisualEditorInner({ onClose }) {
317
317
  [blocks, liveBlocks]
318
318
  );
319
319
  nietLiveRef.current = wijzigingen.iets;
320
- const { publishDraft, zetFotoVervanger } = useEditor();
320
+ const { publishDraft, bevestigPublicatie, zetFotoVervanger } = useEditor();
321
321
  const actieveModules = useModules();
322
322
  useEffect(() => {
323
323
  for (const m of actieveModules.defs) {
@@ -927,6 +927,7 @@ function VisualEditorInner({ onClose }) {
927
927
  await saveDraft(siteId, d.id, draftPayload(d));
928
928
  await publishPage(siteId, d.id);
929
929
  setLiveBlocks(structuredClone(d.blocks));
930
+ bevestigPublicatie(d.path, structuredClone(d.blocks));
930
931
  toast({
931
932
  title: "Gepubliceerd",
932
933
  description: demo ? "In deze demo blijft de wijziging in je browser staan." : "Binnen enkele seconden zichtbaar voor iedereen.",