UNPKG

medusa-payment-pesapal

Version:

Pesapal payment provider plugin for Medusa v2 - Accept payments via Pesapal gateway with support for M-Pesa, Airtel Money, and other East African payment methods

279 lines (278 loc) 12.8 kB
"use strict"; const jsxRuntime = require("react/jsx-runtime"); const adminSdk = require("@medusajs/admin-sdk"); const ui = require("@medusajs/ui"); const react = require("react"); const PesapalConfigurationWidget = () => { const [config2, setConfig] = react.useState({ consumer_key: "", consumer_secret: "", environment: "sandbox", currency: "KES", merchant_name: "", ipn_url: "", enabled: false }); const [loading, setLoading] = react.useState(false); const [saving, setSaving] = react.useState(false); react.useEffect(() => { const loadConfiguration = async () => { setLoading(true); try { const response = await fetch("/admin/custom/pesapal/config", { method: "GET", headers: { "Content-Type": "application/json" } }); if (response.ok) { const data = await response.json(); setConfig(data.config || config2); } } catch (error) { console.error("Failed to load Pesapal configuration:", error); ui.toast.error("Failed to load configuration"); } finally { setLoading(false); } }; loadConfiguration(); }, []); const handleSave = async () => { setSaving(true); try { const response = await fetch("/admin/custom/pesapal/config", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ config: config2 }) }); if (response.ok) { ui.toast.success("Pesapal configuration saved successfully"); } else { const error = await response.json(); ui.toast.error(error.message || "Failed to save configuration"); } } catch (error) { console.error("Failed to save Pesapal configuration:", error); ui.toast.error("Failed to save configuration"); } finally { setSaving(false); } }; const handleTestConnection = async () => { setLoading(true); try { const response = await fetch("/admin/custom/pesapal/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ config: config2 }) }); const result = await response.json(); if (response.ok && result.success) { ui.toast.success("Connection test successful!"); } else { ui.toast.error(result.message || "Connection test failed"); } } catch (error) { console.error("Failed to test Pesapal connection:", error); ui.toast.error("Failed to test connection"); } finally { setLoading(false); } }; if (loading && !config2.consumer_key) { return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading Pesapal configuration..." }) }) }); } return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-6", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Pesapal Configuration" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Configure your Pesapal payment gateway settings" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ jsxRuntime.jsx( ui.Switch, { checked: config2.enabled, onCheckedChange: (checked) => setConfig((prev) => ({ ...prev, enabled: checked })) } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Enable Pesapal" }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "environment", children: "Environment" }), /* @__PURE__ */ jsxRuntime.jsxs( ui.Select, { value: config2.environment, onValueChange: (value) => setConfig((prev) => ({ ...prev, environment: value })), children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "sandbox", children: "Sandbox (Testing)" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "live", children: "Live (Production)" }) ] }) ] } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-1", children: "Use sandbox for testing and live for production" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "consumer_key", children: "Consumer Key" }), /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { id: "consumer_key", type: "text", placeholder: "Enter your Pesapal consumer key", value: config2.consumer_key, onChange: (e) => setConfig((prev) => ({ ...prev, consumer_key: e.target.value })) } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-1", children: "Your Pesapal consumer key from the merchant dashboard" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "consumer_secret", children: "Consumer Secret" }), /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { id: "consumer_secret", type: "password", placeholder: "Enter your Pesapal consumer secret", value: config2.consumer_secret, onChange: (e) => setConfig((prev) => ({ ...prev, consumer_secret: e.target.value })) } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-1", children: "Your Pesapal consumer secret (keep this secure)" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "currency", children: "Default Currency" }), /* @__PURE__ */ jsxRuntime.jsxs( ui.Select, { value: config2.currency, onValueChange: (value) => setConfig((prev) => ({ ...prev, currency: value })), children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "KES", children: "KES - Kenyan Shilling" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "USD", children: "USD - US Dollar" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "EUR", children: "EUR - Euro" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "GBP", children: "GBP - British Pound" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "UGX", children: "UGX - Ugandan Shilling" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "TZS", children: "TZS - Tanzanian Shilling" }) ] }) ] } ) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "merchant_name", children: "Merchant Name" }), /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { id: "merchant_name", type: "text", placeholder: "Your business name", value: config2.merchant_name, onChange: (e) => setConfig((prev) => ({ ...prev, merchant_name: e.target.value })) } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-1", children: "Optional: Your business name for display purposes" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "ipn_url", children: "IPN Callback URL" }), /* @__PURE__ */ jsxRuntime.jsx( ui.Input, { id: "ipn_url", type: "url", placeholder: "https://yourdomain.com/pesapal/webhook", value: config2.ipn_url, onChange: (e) => setConfig((prev) => ({ ...prev, ipn_url: e.target.value })) } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-1", children: "URL where Pesapal will send payment notifications. Leave empty to use default." }) ] }) ] }), config2.environment === "sandbox" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 p-4 bg-ui-bg-subtle rounded-lg border", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "mb-3", children: "Sandbox Test Credentials" }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Consumer Key:" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-mono", children: "qkio1BGGYAXTu2JOfm7XSXNruoZsrqEW" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Consumer Secret:" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "font-mono", children: "osGQ364R49cXKeOYSpaOnT++rHs=" }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle mt-2", children: "You can use these test credentials for Kenyan merchant sandbox testing" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-8", children: [ /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { variant: "secondary", onClick: handleTestConnection, disabled: !config2.consumer_key || !config2.consumer_secret || loading, children: loading ? "Testing..." : "Test Connection" } ), /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { onClick: handleSave, disabled: !config2.consumer_key || !config2.consumer_secret || saving, children: saving ? "Saving..." : "Save Configuration" } ) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 p-4 bg-ui-bg-base border rounded-lg", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h3", className: "mb-2", children: "Status Information" }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4 text-sm", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Provider Status:" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: config2.enabled ? "text-green-600" : "text-red-600", children: config2.enabled ? "Enabled" : "Disabled" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Environment:" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: config2.environment === "live" ? "text-orange-600" : "text-blue-600", children: config2.environment === "live" ? "Production" : "Sandbox" }) ] }) ] }) ] }) ] }) }); }; adminSdk.defineWidgetConfig({ zone: "order.details.after" }); const widgetModule = { widgets: [ { Component: PesapalConfigurationWidget, zone: ["order.details.after"] } ] }; const routeModule = { routes: [] }; const menuItemModule = { menuItems: [] }; const formModule = { customFields: {} }; const displayModule = { displays: {} }; const plugin = { widgetModule, routeModule, menuItemModule, formModule, displayModule }; module.exports = plugin;