@xiwebdesign/xicms-core 5.8.0 → 5.8.1
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.
|
@@ -37,7 +37,13 @@ function ConnectionsTab({ siteId }) {
|
|
|
37
37
|
const [notifyTo, setNotifyTo] = useState("");
|
|
38
38
|
const refresh = useCallback(async () => {
|
|
39
39
|
try {
|
|
40
|
-
const
|
|
40
|
+
const raw = await shopCallable("getShopStatus")({ siteId });
|
|
41
|
+
const s = {
|
|
42
|
+
provider: raw.provider ?? "stripe",
|
|
43
|
+
stripe: raw.stripe ?? { configured: false, webhookConfigured: false },
|
|
44
|
+
mollie: raw.mollie ?? { configured: false },
|
|
45
|
+
mail: raw.mail ?? { configured: false }
|
|
46
|
+
};
|
|
41
47
|
setStatus(s);
|
|
42
48
|
setPayProvider(s.provider ?? "stripe");
|
|
43
49
|
const m = s.mail ?? {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/shop/ConnectionsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Badge, Button, Card, Field, Input } from \"../ui/primitives\";\nimport { Switch } from \"../ui/switch\";\nimport { useToast } from \"../ui/toast\";\nimport { shopCallable } from \"./lib\";\n\ntype PayProvider = \"stripe\" | \"mollie\";\ntype MailProvider = \"resend\" | \"postmark\" | \"smtp\";\n\ninterface ShopStatus {\n provider: PayProvider;\n stripe: { configured: boolean; account?: string; webhookConfigured: boolean };\n mollie: { configured: boolean; profile?: string };\n mail: {\n provider?: MailProvider;\n configured: boolean;\n host?: string;\n port?: number;\n secure?: boolean;\n user?: string;\n fromName?: string;\n fromEmail?: string;\n notifyTo?: string;\n hasResendKey?: boolean;\n hasPostmarkToken?: boolean;\n hasSmtpPass?: boolean;\n };\n}\n\n/** Segmented control voor providerkeuze. */\nfunction Segmented<T extends string>({\n value,\n options,\n onChange,\n}: {\n value: T;\n options: { value: T; label: string }[];\n onChange: (v: T) => void;\n}) {\n return (\n <div className=\"inline-flex rounded-lg border border-slate-200 bg-slate-50 p-0.5\">\n {options.map((o) => (\n <button\n key={o.value}\n type=\"button\"\n onClick={() => onChange(o.value)}\n className={`rounded-md px-3 py-1.5 text-sm font-medium transition ${\n value === o.value ? \"bg-white text-brand-700 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n }`}\n >\n {o.label}\n </button>\n ))}\n </div>\n );\n}\n\n/**\n * Koppelingen — betaalprovider (Stripe of Mollie) en mailprovider (Resend, Postmark of eigen SMTP).\n * Geheimen gaan uitsluitend via callables naar `sites/{siteId}/private/*` (deny-all rules); dit\n * paneel toont alleen gemaskeerde status. Alleen een siteadmin kan opslaan.\n */\nexport function ConnectionsTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const [status, setStatus] = useState<ShopStatus | null>(null);\n const [busy, setBusy] = useState(false);\n\n // Betaling\n const [payProvider, setPayProvider] = useState<PayProvider>(\"stripe\");\n const [stripeKey, setStripeKey] = useState(\"\");\n const [mollieKey, setMollieKey] = useState(\"\");\n\n // Mail\n const [mailProvider, setMailProvider] = useState<MailProvider>(\"smtp\");\n const [resendKey, setResendKey] = useState(\"\");\n const [postmarkToken, setPostmarkToken] = useState(\"\");\n const [smtp, setSmtp] = useState({ host: \"\", port: \"465\", secure: true, user: \"\", pass: \"\" });\n const [fromName, setFromName] = useState(\"\");\n const [fromEmail, setFromEmail] = useState(\"\");\n const [notifyTo, setNotifyTo] = useState(\"\");\n\n const refresh = useCallback(async () => {\n try {\n const s = await shopCallable<{ siteId: string }, ShopStatus>(\"getShopStatus\")({ siteId });\n setStatus(s);\n setPayProvider(s.provider ?? \"stripe\");\n const m = s.mail ?? {};\n setMailProvider(m.provider ?? (m.host ? \"smtp\" : m.hasPostmarkToken ? \"postmark\" : m.hasResendKey ? \"resend\" : \"smtp\"));\n setSmtp((p) => ({ ...p, host: m.host ?? p.host, port: String(m.port ?? 465), secure: m.secure !== false, user: m.user ?? p.user }));\n setFromName(m.fromName ?? \"\");\n setFromEmail(m.fromEmail ?? \"\");\n setNotifyTo(m.notifyTo ?? \"\");\n } catch {\n setStatus(null);\n }\n }, [siteId]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n async function savePayment() {\n setBusy(true);\n try {\n const payload: Record<string, unknown> = { siteId, provider: payProvider };\n if (payProvider === \"stripe\") {\n if (!stripeKey.trim().startsWith(\"sk_\") && !stripeKey.trim().startsWith(\"rk_\")) {\n toast({ title: \"Ongeldige sleutel\", description: \"Plak een Stripe geheime sleutel (sk_…) of restricted key (rk_…).\", tone: \"error\" });\n setBusy(false);\n return;\n }\n payload.stripe = { secretKey: stripeKey.trim() };\n } else {\n if (!/^(test|live)_/.test(mollieKey.trim())) {\n toast({ title: \"Ongeldige sleutel\", description: \"Plak een Mollie API-sleutel (test_… of live_…).\", tone: \"error\" });\n setBusy(false);\n return;\n }\n payload.mollie = { apiKey: mollieKey.trim() };\n }\n const res = await shopCallable<Record<string, unknown>, { account?: string }>(\"saveShopSecrets\")(payload);\n toast({ title: `${payProvider === \"stripe\" ? \"Stripe\" : \"Mollie\"} gekoppeld`, description: res.account ? `Account: ${res.account}` : undefined, tone: \"success\" });\n setStripeKey(\"\");\n setMollieKey(\"\");\n await refresh();\n } catch (e) {\n toast({ title: \"Koppelen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function switchActiveProvider(p: PayProvider) {\n setPayProvider(p);\n // Alleen de actieve provider wisselen als de andere al geconfigureerd is (anders vraagt het formulier eerst een sleutel).\n const otherConfigured = p === \"stripe\" ? status?.stripe.configured : status?.mollie.configured;\n if (otherConfigured) {\n try {\n await shopCallable<{ siteId: string; provider: PayProvider }, unknown>(\"saveShopSecrets\")({ siteId, provider: p });\n await refresh();\n } catch {\n /* stil — de gebruiker kan alsnog opslaan */\n }\n }\n }\n\n async function saveMail() {\n setBusy(true);\n try {\n const mail: Record<string, unknown> = { provider: mailProvider, fromName, fromEmail, notifyTo };\n if (mailProvider === \"resend\") mail.resendApiKey = resendKey.trim() || undefined;\n if (mailProvider === \"postmark\") mail.postmarkToken = postmarkToken.trim() || undefined;\n if (mailProvider === \"smtp\") {\n mail.host = smtp.host.trim();\n mail.port = Number(smtp.port) || 465;\n mail.secure = smtp.secure;\n mail.user = smtp.user.trim();\n if (smtp.pass) mail.pass = smtp.pass;\n }\n await shopCallable<{ siteId: string; mail: Record<string, unknown> }, { ok: boolean }>(\"saveMailSettings\")({ siteId, mail });\n toast({ title: \"E-mailinstellingen opgeslagen\", tone: \"success\" });\n setResendKey(\"\");\n setPostmarkToken(\"\");\n setSmtp((p) => ({ ...p, pass: \"\" }));\n await refresh();\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 async function sendTest() {\n setBusy(true);\n try {\n const res = await shopCallable<{ siteId: string }, { to: string }>(\"sendShopTestMail\")({ siteId });\n toast({ title: \"Testmail verstuurd\", description: `Naar ${res.to} — check de inbox (en spam).`, tone: \"success\" });\n } catch (e) {\n toast({ title: \"Testmail mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n const payConfigured = payProvider === \"stripe\" ? status?.stripe.configured : status?.mollie.configured;\n\n return (\n <div className=\"grid gap-4\">\n {/* ── Betalingen ─────────────────────────────────────────────── */}\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">Betalingen</h3>\n {status && (\n <Badge tone={payConfigured ? \"green\" : \"amber\"}>\n {payProvider === \"stripe\"\n ? status.stripe.configured\n ? `Stripe actief${status.stripe.account ? ` — ${status.stripe.account}` : \"\"}`\n : \"Stripe nog niet gekoppeld\"\n : status.mollie.configured\n ? `Mollie actief${status.mollie.profile ? ` — ${status.mollie.profile}` : \"\"}`\n : \"Mollie nog niet gekoppeld\"}\n </Badge>\n )}\n </div>\n\n <Segmented\n value={payProvider}\n onChange={(v) => void switchActiveProvider(v)}\n options={[\n { value: \"stripe\", label: \"Stripe\" },\n { value: \"mollie\", label: \"Mollie\" },\n ]}\n />\n\n {payProvider === \"stripe\" ? (\n <div className=\"grid gap-3\">\n <ol className=\"grid list-decimal gap-1 pl-5 text-sm text-slate-600\">\n <li>Maak een gratis account op <a className=\"underline\" href=\"https://dashboard.stripe.com/register\" target=\"_blank\" rel=\"noreferrer\">stripe.com</a> en activeer het (IBAN, KVK).</li>\n <li>Zet onder <em>Settings → Payment methods</em> iDEAL aan.</li>\n <li>Maak onder <em>Developers → API keys</em> een sleutel aan en plak hem hieronder — de webhook wordt automatisch aangemaakt.</li>\n </ol>\n <Field label=\"Stripe geheime sleutel (sk_live_… of rk_live_…)\" hint=\"Wordt veilig opgeslagen; nooit zichtbaar in de browser\">\n <Input type=\"password\" value={stripeKey} onChange={(e) => setStripeKey(e.target.value)} placeholder=\"sk_live_…\" />\n </Field>\n {status?.stripe.configured && !status.stripe.webhookConfigured && (\n <p className=\"rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-700\">\n Webhook nog niet geregistreerd — koppel opnieuw met een sleutel die webhook-rechten heeft.\n </p>\n )}\n <div><Button onClick={savePayment} disabled={busy || !stripeKey.trim()}>Koppel Stripe</Button></div>\n </div>\n ) : (\n <div className=\"grid gap-3\">\n <ol className=\"grid list-decimal gap-1 pl-5 text-sm text-slate-600\">\n <li>Maak een account op <a className=\"underline\" href=\"https://www.mollie.com/dashboard/signup\" target=\"_blank\" rel=\"noreferrer\">mollie.com</a> en doorloop de onboarding.</li>\n <li>Zet in het Mollie-dashboard de gewenste betaalmethoden (o.a. iDEAL) aan.</li>\n <li>Kopieer onder <em>Developers → API-keys</em> je live- of test-sleutel en plak hem hieronder. Mollie heeft geen aparte webhook-registratie nodig.</li>\n </ol>\n <Field label=\"Mollie API-sleutel (live_… of test_…)\" hint=\"Wordt veilig opgeslagen; nooit zichtbaar in de browser\">\n <Input type=\"password\" value={mollieKey} onChange={(e) => setMollieKey(e.target.value)} placeholder=\"live_…\" />\n </Field>\n <div><Button onClick={savePayment} disabled={busy || !mollieKey.trim()}>Koppel Mollie</Button></div>\n </div>\n )}\n </div>\n </Card>\n\n {/* ── E-mail ─────────────────────────────────────────────────── */}\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">E-mail (bestelbevestigingen & formulieren)</h3>\n {status && (\n <Badge tone={status.mail.configured ? \"green\" : \"amber\"}>\n {status.mail.configured ? `${mailProviderLabel(mailProvider)} actief` : \"Nog niet ingesteld\"}\n </Badge>\n )}\n </div>\n\n <Segmented\n value={mailProvider}\n onChange={setMailProvider}\n options={[\n { value: \"smtp\", label: \"Eigen SMTP\" },\n { value: \"resend\", label: \"Resend\" },\n { value: \"postmark\", label: \"Postmark\" },\n ]}\n />\n\n {mailProvider === \"smtp\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n Via je eigen mailbox: bv. het adres bij je hostingpartij, of Gmail (smtp.gmail.com, poort 465, met een{\" \"}\n <a className=\"underline\" href=\"https://myaccount.google.com/apppasswords\" target=\"_blank\" rel=\"noreferrer\">app-wachtwoord</a>).\n </p>\n <div className=\"grid gap-3 md:grid-cols-[1fr_110px]\">\n <Field label=\"SMTP-server\"><Input value={smtp.host} onChange={(e) => setSmtp((p) => ({ ...p, host: e.target.value }))} placeholder=\"smtp.gmail.com\" /></Field>\n <Field label=\"Poort\"><Input value={smtp.port} onChange={(e) => setSmtp((p) => ({ ...p, port: e.target.value }))} placeholder=\"465\" /></Field>\n </div>\n <Switch checked={smtp.secure} onCheckedChange={(v) => setSmtp((p) => ({ ...p, secure: v }))} label=\"SSL (poort 465). Uit = STARTTLS (poort 587)\" />\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Gebruikersnaam\"><Input value={smtp.user} onChange={(e) => setSmtp((p) => ({ ...p, user: e.target.value }))} placeholder=\"info@jouwdomein.nl\" /></Field>\n <Field label=\"Wachtwoord\" hint={status?.mail.hasSmtpPass ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={smtp.pass} onChange={(e) => setSmtp((p) => ({ ...p, pass: e.target.value }))} />\n </Field>\n </div>\n </div>\n )}\n\n {mailProvider === \"resend\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n <a className=\"underline\" href=\"https://resend.com\" target=\"_blank\" rel=\"noreferrer\">Resend</a> verstuurt vanaf een geverifieerd domein.\n Maak een API-sleutel (re_…) en verifieer je afzenderdomein in het Resend-dashboard.\n </p>\n <Field label=\"Resend API-sleutel (re_…)\" hint={status?.mail.hasResendKey ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={resendKey} onChange={(e) => setResendKey(e.target.value)} placeholder=\"re_…\" />\n </Field>\n </div>\n )}\n\n {mailProvider === \"postmark\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n <a className=\"underline\" href=\"https://postmarkapp.com\" target=\"_blank\" rel=\"noreferrer\">Postmark</a> verstuurt vanaf een geverifieerde afzender/domein (Sender Signature).\n Kopieer het Server-token.\n </p>\n <Field label=\"Postmark server-token\" hint={status?.mail.hasPostmarkToken ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={postmarkToken} onChange={(e) => setPostmarkToken(e.target.value)} placeholder=\"xxxxxxxx-xxxx-…\" />\n </Field>\n </div>\n )}\n\n {/* Gedeelde afzender-velden */}\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Afzendernaam\"><Input value={fromName} onChange={(e) => setFromName(e.target.value)} placeholder=\"Christelijk Kraamcadeau\" /></Field>\n <Field label=\"Afzenderadres\"><Input value={fromEmail} onChange={(e) => setFromEmail(e.target.value)} placeholder=\"info@jouwdomein.nl\" /></Field>\n </div>\n <Field label=\"Notificatie-adres\" hint=\"Hier ontvang je zelf een mail bij elke bestelling; ook het doel van de testmail\">\n <Input value={notifyTo} onChange={(e) => setNotifyTo(e.target.value)} placeholder=\"bestellingen@jouwdomein.nl\" />\n </Field>\n\n <div className=\"flex items-center gap-2\">\n <Button onClick={saveMail} disabled={busy}>Opslaan</Button>\n <Button variant=\"secondary\" onClick={sendTest} disabled={busy || !status?.mail.configured}>Stuur testmail</Button>\n </div>\n </div>\n </Card>\n\n <Card>\n <p className=\"text-sm text-slate-600\">\n Verzendkosten, valuta, ordernummer-prefix en bedrijfsgegevens (factuur) stel je in onder het tabblad\n <strong> Instellingen</strong>. Mailteksten pas je aan onder <strong>E-mails</strong>.\n </p>\n </Card>\n </div>\n );\n}\n\nfunction mailProviderLabel(p: MailProvider): string {\n return p === \"smtp\" ? \"Eigen SMTP\" : p === \"resend\" ? \"Resend\" : \"Postmark\";\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/shop/ConnectionsTab.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Badge, Button, Card, Field, Input } from \"../ui/primitives\";\nimport { Switch } from \"../ui/switch\";\nimport { useToast } from \"../ui/toast\";\nimport { shopCallable } from \"./lib\";\n\ntype PayProvider = \"stripe\" | \"mollie\";\ntype MailProvider = \"resend\" | \"postmark\" | \"smtp\";\n\ninterface ShopStatus {\n provider: PayProvider;\n stripe: { configured: boolean; account?: string; webhookConfigured: boolean };\n mollie: { configured: boolean; profile?: string };\n mail: {\n provider?: MailProvider;\n configured: boolean;\n host?: string;\n port?: number;\n secure?: boolean;\n user?: string;\n fromName?: string;\n fromEmail?: string;\n notifyTo?: string;\n hasResendKey?: boolean;\n hasPostmarkToken?: boolean;\n hasSmtpPass?: boolean;\n };\n}\n\n/** Segmented control voor providerkeuze. */\nfunction Segmented<T extends string>({\n value,\n options,\n onChange,\n}: {\n value: T;\n options: { value: T; label: string }[];\n onChange: (v: T) => void;\n}) {\n return (\n <div className=\"inline-flex rounded-lg border border-slate-200 bg-slate-50 p-0.5\">\n {options.map((o) => (\n <button\n key={o.value}\n type=\"button\"\n onClick={() => onChange(o.value)}\n className={`rounded-md px-3 py-1.5 text-sm font-medium transition ${\n value === o.value ? \"bg-white text-brand-700 shadow-sm\" : \"text-slate-500 hover:text-slate-700\"\n }`}\n >\n {o.label}\n </button>\n ))}\n </div>\n );\n}\n\n/**\n * Koppelingen — betaalprovider (Stripe of Mollie) en mailprovider (Resend, Postmark of eigen SMTP).\n * Geheimen gaan uitsluitend via callables naar `sites/{siteId}/private/*` (deny-all rules); dit\n * paneel toont alleen gemaskeerde status. Alleen een siteadmin kan opslaan.\n */\nexport function ConnectionsTab({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const [status, setStatus] = useState<ShopStatus | null>(null);\n const [busy, setBusy] = useState(false);\n\n // Betaling\n const [payProvider, setPayProvider] = useState<PayProvider>(\"stripe\");\n const [stripeKey, setStripeKey] = useState(\"\");\n const [mollieKey, setMollieKey] = useState(\"\");\n\n // Mail\n const [mailProvider, setMailProvider] = useState<MailProvider>(\"smtp\");\n const [resendKey, setResendKey] = useState(\"\");\n const [postmarkToken, setPostmarkToken] = useState(\"\");\n const [smtp, setSmtp] = useState({ host: \"\", port: \"465\", secure: true, user: \"\", pass: \"\" });\n const [fromName, setFromName] = useState(\"\");\n const [fromEmail, setFromEmail] = useState(\"\");\n const [notifyTo, setNotifyTo] = useState(\"\");\n\n const refresh = useCallback(async () => {\n try {\n const raw = await shopCallable<{ siteId: string }, Partial<ShopStatus>>(\"getShopStatus\")({ siteId });\n // Normaliseer naar de volledige vorm zodat de render nooit op een ontbrekend deel-object\n // (bv. een oudere functions-versie zonder mollie/mail) kan crashen.\n const s: ShopStatus = {\n provider: raw.provider ?? \"stripe\",\n stripe: raw.stripe ?? { configured: false, webhookConfigured: false },\n mollie: raw.mollie ?? { configured: false },\n mail: raw.mail ?? { configured: false },\n };\n setStatus(s);\n setPayProvider(s.provider ?? \"stripe\");\n const m = s.mail ?? {};\n setMailProvider(m.provider ?? (m.host ? \"smtp\" : m.hasPostmarkToken ? \"postmark\" : m.hasResendKey ? \"resend\" : \"smtp\"));\n setSmtp((p) => ({ ...p, host: m.host ?? p.host, port: String(m.port ?? 465), secure: m.secure !== false, user: m.user ?? p.user }));\n setFromName(m.fromName ?? \"\");\n setFromEmail(m.fromEmail ?? \"\");\n setNotifyTo(m.notifyTo ?? \"\");\n } catch {\n setStatus(null);\n }\n }, [siteId]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n async function savePayment() {\n setBusy(true);\n try {\n const payload: Record<string, unknown> = { siteId, provider: payProvider };\n if (payProvider === \"stripe\") {\n if (!stripeKey.trim().startsWith(\"sk_\") && !stripeKey.trim().startsWith(\"rk_\")) {\n toast({ title: \"Ongeldige sleutel\", description: \"Plak een Stripe geheime sleutel (sk_…) of restricted key (rk_…).\", tone: \"error\" });\n setBusy(false);\n return;\n }\n payload.stripe = { secretKey: stripeKey.trim() };\n } else {\n if (!/^(test|live)_/.test(mollieKey.trim())) {\n toast({ title: \"Ongeldige sleutel\", description: \"Plak een Mollie API-sleutel (test_… of live_…).\", tone: \"error\" });\n setBusy(false);\n return;\n }\n payload.mollie = { apiKey: mollieKey.trim() };\n }\n const res = await shopCallable<Record<string, unknown>, { account?: string }>(\"saveShopSecrets\")(payload);\n toast({ title: `${payProvider === \"stripe\" ? \"Stripe\" : \"Mollie\"} gekoppeld`, description: res.account ? `Account: ${res.account}` : undefined, tone: \"success\" });\n setStripeKey(\"\");\n setMollieKey(\"\");\n await refresh();\n } catch (e) {\n toast({ title: \"Koppelen mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n async function switchActiveProvider(p: PayProvider) {\n setPayProvider(p);\n // Alleen de actieve provider wisselen als de andere al geconfigureerd is (anders vraagt het formulier eerst een sleutel).\n const otherConfigured = p === \"stripe\" ? status?.stripe.configured : status?.mollie.configured;\n if (otherConfigured) {\n try {\n await shopCallable<{ siteId: string; provider: PayProvider }, unknown>(\"saveShopSecrets\")({ siteId, provider: p });\n await refresh();\n } catch {\n /* stil — de gebruiker kan alsnog opslaan */\n }\n }\n }\n\n async function saveMail() {\n setBusy(true);\n try {\n const mail: Record<string, unknown> = { provider: mailProvider, fromName, fromEmail, notifyTo };\n if (mailProvider === \"resend\") mail.resendApiKey = resendKey.trim() || undefined;\n if (mailProvider === \"postmark\") mail.postmarkToken = postmarkToken.trim() || undefined;\n if (mailProvider === \"smtp\") {\n mail.host = smtp.host.trim();\n mail.port = Number(smtp.port) || 465;\n mail.secure = smtp.secure;\n mail.user = smtp.user.trim();\n if (smtp.pass) mail.pass = smtp.pass;\n }\n await shopCallable<{ siteId: string; mail: Record<string, unknown> }, { ok: boolean }>(\"saveMailSettings\")({ siteId, mail });\n toast({ title: \"E-mailinstellingen opgeslagen\", tone: \"success\" });\n setResendKey(\"\");\n setPostmarkToken(\"\");\n setSmtp((p) => ({ ...p, pass: \"\" }));\n await refresh();\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 async function sendTest() {\n setBusy(true);\n try {\n const res = await shopCallable<{ siteId: string }, { to: string }>(\"sendShopTestMail\")({ siteId });\n toast({ title: \"Testmail verstuurd\", description: `Naar ${res.to} — check de inbox (en spam).`, tone: \"success\" });\n } catch (e) {\n toast({ title: \"Testmail mislukt\", description: e instanceof Error ? e.message : undefined, tone: \"error\" });\n } finally {\n setBusy(false);\n }\n }\n\n const payConfigured = payProvider === \"stripe\" ? status?.stripe.configured : status?.mollie.configured;\n\n return (\n <div className=\"grid gap-4\">\n {/* ── Betalingen ─────────────────────────────────────────────── */}\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">Betalingen</h3>\n {status && (\n <Badge tone={payConfigured ? \"green\" : \"amber\"}>\n {payProvider === \"stripe\"\n ? status.stripe.configured\n ? `Stripe actief${status.stripe.account ? ` — ${status.stripe.account}` : \"\"}`\n : \"Stripe nog niet gekoppeld\"\n : status.mollie.configured\n ? `Mollie actief${status.mollie.profile ? ` — ${status.mollie.profile}` : \"\"}`\n : \"Mollie nog niet gekoppeld\"}\n </Badge>\n )}\n </div>\n\n <Segmented\n value={payProvider}\n onChange={(v) => void switchActiveProvider(v)}\n options={[\n { value: \"stripe\", label: \"Stripe\" },\n { value: \"mollie\", label: \"Mollie\" },\n ]}\n />\n\n {payProvider === \"stripe\" ? (\n <div className=\"grid gap-3\">\n <ol className=\"grid list-decimal gap-1 pl-5 text-sm text-slate-600\">\n <li>Maak een gratis account op <a className=\"underline\" href=\"https://dashboard.stripe.com/register\" target=\"_blank\" rel=\"noreferrer\">stripe.com</a> en activeer het (IBAN, KVK).</li>\n <li>Zet onder <em>Settings → Payment methods</em> iDEAL aan.</li>\n <li>Maak onder <em>Developers → API keys</em> een sleutel aan en plak hem hieronder — de webhook wordt automatisch aangemaakt.</li>\n </ol>\n <Field label=\"Stripe geheime sleutel (sk_live_… of rk_live_…)\" hint=\"Wordt veilig opgeslagen; nooit zichtbaar in de browser\">\n <Input type=\"password\" value={stripeKey} onChange={(e) => setStripeKey(e.target.value)} placeholder=\"sk_live_…\" />\n </Field>\n {status?.stripe.configured && !status.stripe.webhookConfigured && (\n <p className=\"rounded-lg bg-amber-50 px-3 py-2 text-sm text-amber-700\">\n Webhook nog niet geregistreerd — koppel opnieuw met een sleutel die webhook-rechten heeft.\n </p>\n )}\n <div><Button onClick={savePayment} disabled={busy || !stripeKey.trim()}>Koppel Stripe</Button></div>\n </div>\n ) : (\n <div className=\"grid gap-3\">\n <ol className=\"grid list-decimal gap-1 pl-5 text-sm text-slate-600\">\n <li>Maak een account op <a className=\"underline\" href=\"https://www.mollie.com/dashboard/signup\" target=\"_blank\" rel=\"noreferrer\">mollie.com</a> en doorloop de onboarding.</li>\n <li>Zet in het Mollie-dashboard de gewenste betaalmethoden (o.a. iDEAL) aan.</li>\n <li>Kopieer onder <em>Developers → API-keys</em> je live- of test-sleutel en plak hem hieronder. Mollie heeft geen aparte webhook-registratie nodig.</li>\n </ol>\n <Field label=\"Mollie API-sleutel (live_… of test_…)\" hint=\"Wordt veilig opgeslagen; nooit zichtbaar in de browser\">\n <Input type=\"password\" value={mollieKey} onChange={(e) => setMollieKey(e.target.value)} placeholder=\"live_…\" />\n </Field>\n <div><Button onClick={savePayment} disabled={busy || !mollieKey.trim()}>Koppel Mollie</Button></div>\n </div>\n )}\n </div>\n </Card>\n\n {/* ── E-mail ─────────────────────────────────────────────────── */}\n <Card>\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"text-sm font-semibold\">E-mail (bestelbevestigingen & formulieren)</h3>\n {status && (\n <Badge tone={status.mail.configured ? \"green\" : \"amber\"}>\n {status.mail.configured ? `${mailProviderLabel(mailProvider)} actief` : \"Nog niet ingesteld\"}\n </Badge>\n )}\n </div>\n\n <Segmented\n value={mailProvider}\n onChange={setMailProvider}\n options={[\n { value: \"smtp\", label: \"Eigen SMTP\" },\n { value: \"resend\", label: \"Resend\" },\n { value: \"postmark\", label: \"Postmark\" },\n ]}\n />\n\n {mailProvider === \"smtp\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n Via je eigen mailbox: bv. het adres bij je hostingpartij, of Gmail (smtp.gmail.com, poort 465, met een{\" \"}\n <a className=\"underline\" href=\"https://myaccount.google.com/apppasswords\" target=\"_blank\" rel=\"noreferrer\">app-wachtwoord</a>).\n </p>\n <div className=\"grid gap-3 md:grid-cols-[1fr_110px]\">\n <Field label=\"SMTP-server\"><Input value={smtp.host} onChange={(e) => setSmtp((p) => ({ ...p, host: e.target.value }))} placeholder=\"smtp.gmail.com\" /></Field>\n <Field label=\"Poort\"><Input value={smtp.port} onChange={(e) => setSmtp((p) => ({ ...p, port: e.target.value }))} placeholder=\"465\" /></Field>\n </div>\n <Switch checked={smtp.secure} onCheckedChange={(v) => setSmtp((p) => ({ ...p, secure: v }))} label=\"SSL (poort 465). Uit = STARTTLS (poort 587)\" />\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Gebruikersnaam\"><Input value={smtp.user} onChange={(e) => setSmtp((p) => ({ ...p, user: e.target.value }))} placeholder=\"info@jouwdomein.nl\" /></Field>\n <Field label=\"Wachtwoord\" hint={status?.mail.hasSmtpPass ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={smtp.pass} onChange={(e) => setSmtp((p) => ({ ...p, pass: e.target.value }))} />\n </Field>\n </div>\n </div>\n )}\n\n {mailProvider === \"resend\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n <a className=\"underline\" href=\"https://resend.com\" target=\"_blank\" rel=\"noreferrer\">Resend</a> verstuurt vanaf een geverifieerd domein.\n Maak een API-sleutel (re_…) en verifieer je afzenderdomein in het Resend-dashboard.\n </p>\n <Field label=\"Resend API-sleutel (re_…)\" hint={status?.mail.hasResendKey ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={resendKey} onChange={(e) => setResendKey(e.target.value)} placeholder=\"re_…\" />\n </Field>\n </div>\n )}\n\n {mailProvider === \"postmark\" && (\n <div className=\"grid gap-3\">\n <p className=\"text-sm text-slate-600\">\n <a className=\"underline\" href=\"https://postmarkapp.com\" target=\"_blank\" rel=\"noreferrer\">Postmark</a> verstuurt vanaf een geverifieerde afzender/domein (Sender Signature).\n Kopieer het Server-token.\n </p>\n <Field label=\"Postmark server-token\" hint={status?.mail.hasPostmarkToken ? \"Leeg laten = ongewijzigd\" : undefined}>\n <Input type=\"password\" value={postmarkToken} onChange={(e) => setPostmarkToken(e.target.value)} placeholder=\"xxxxxxxx-xxxx-…\" />\n </Field>\n </div>\n )}\n\n {/* Gedeelde afzender-velden */}\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Afzendernaam\"><Input value={fromName} onChange={(e) => setFromName(e.target.value)} placeholder=\"Christelijk Kraamcadeau\" /></Field>\n <Field label=\"Afzenderadres\"><Input value={fromEmail} onChange={(e) => setFromEmail(e.target.value)} placeholder=\"info@jouwdomein.nl\" /></Field>\n </div>\n <Field label=\"Notificatie-adres\" hint=\"Hier ontvang je zelf een mail bij elke bestelling; ook het doel van de testmail\">\n <Input value={notifyTo} onChange={(e) => setNotifyTo(e.target.value)} placeholder=\"bestellingen@jouwdomein.nl\" />\n </Field>\n\n <div className=\"flex items-center gap-2\">\n <Button onClick={saveMail} disabled={busy}>Opslaan</Button>\n <Button variant=\"secondary\" onClick={sendTest} disabled={busy || !status?.mail.configured}>Stuur testmail</Button>\n </div>\n </div>\n </Card>\n\n <Card>\n <p className=\"text-sm text-slate-600\">\n Verzendkosten, valuta, ordernummer-prefix en bedrijfsgegevens (factuur) stel je in onder het tabblad\n <strong> Instellingen</strong>. Mailteksten pas je aan onder <strong>E-mails</strong>.\n </p>\n </Card>\n </div>\n );\n}\n\nfunction mailProviderLabel(p: MailProvider): string {\n return p === \"smtp\" ? \"Eigen SMTP\" : p === \"resend\" ? \"Resend\" : \"Postmark\";\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xiwebdesign/xicms-core",
|
|
3
|
-
"version": "5.8.
|
|
3
|
+
"version": "5.8.1",
|
|
4
4
|
"description": "XiCMS engine: gestructureerde content, pagina's, draft/publish, admin (TipTap+Radix), SEO en beveiliging voor klantsites.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|