@verbb/formie-browser 1.0.11 → 1.0.12
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/CHANGELOG.md +8 -0
- package/dist/chunks/{api-BYe9YPko.js → api-DqpfkZWL.js} +15 -2
- package/dist/chunks/{bpoint-C0VOftX9.js → bpoint-Dlq34XH1.js} +1 -1
- package/dist/chunks/{eway-CS6Y1Yvo.js → eway-D9_m8ooj.js} +1 -1
- package/dist/chunks/{go-cardless-BTPD668l.js → go-cardless-DAT3ZaQf.js} +1 -1
- package/dist/chunks/{mollie-CXgBwvo6.js → mollie-Bibhl67p.js} +1 -1
- package/dist/chunks/{moneris-B6oLu7nj.js → moneris-H2wSqk9h.js} +1 -1
- package/dist/chunks/opayo-CR0DtsLa.js +179 -0
- package/dist/chunks/{paddle-GRlsm5mm.js → paddle-DkvIxQdG.js} +1 -1
- package/dist/chunks/{paypal-CdcZnf6r.js → paypal-CQpAF7Ua.js} +32 -31
- package/dist/chunks/{payway-CfmYOS__.js → payway-CwDkC7YZ.js} +1 -1
- package/dist/chunks/{square-BY--5M-X.js → square-DwdcOI1G.js} +1 -1
- package/dist/chunks/{stripe-uusYjWty.js → stripe-DaoG2FT1.js} +1 -1
- package/dist/css/theme/fields/_check-radio.css +3 -1
- package/dist/css/theme/integrations/_opayo.css +9 -0
- package/dist/index.js +12 -12
- package/dist/js/modules/payments/factories.d.ts +5 -1
- package/dist/js/modules/payments/factories.d.ts.map +1 -1
- package/dist/js/modules/payments/opayo.d.ts +17 -2
- package/dist/js/modules/payments/opayo.d.ts.map +1 -1
- package/dist/js/modules/payments/paypal.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/css/theme/fields/_check-radio.css +3 -1
- package/src/css/theme/integrations/_opayo.css +9 -0
- package/src/js/modules/payments/factories.ts +27 -2
- package/src/js/modules/payments/opayo.ts +256 -69
- package/src/js/modules/payments/paypal.ts +23 -3
- package/dist/chunks/opayo-DPUA5CKr.js +0 -113
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.0.12 - 2026-07-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Add Opayo **Drop-in Checkout** support to the `opayo` payment module via `sagepayCheckout`, including iframe mount on field init, `tokenise()` on authorize, and merchant session key refresh on tokenisation failure. **Own Form** mode continues to use `sagepayOwnForm`.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Hide PayPal buttons after successful authorization so users are not prompted to pay again before submitting the form. Buttons are restored automatically when authorization is cleared after a failed submit.
|
|
12
|
+
|
|
5
13
|
## 1.0.11 - 2026-06-26
|
|
6
14
|
|
|
7
15
|
### Added
|
|
@@ -810,13 +810,26 @@ function Ie(e) {
|
|
|
810
810
|
}), t.abort(o.transport.errorMessage));
|
|
811
811
|
},
|
|
812
812
|
onAfterStage: async (t, r) => {
|
|
813
|
-
t.stage !== "dispatch" || !e.onAfterSubmit
|
|
813
|
+
if (!(t.stage !== "dispatch" || !e.onAfterSubmit) && !(!(await e.onAfterSubmit({
|
|
814
814
|
field: n.target,
|
|
815
815
|
services: s,
|
|
816
816
|
options: o,
|
|
817
817
|
provider: o.provider,
|
|
818
818
|
result: r
|
|
819
|
-
})
|
|
819
|
+
}))?.remount || !e.mount)) {
|
|
820
|
+
if (d && e.unmount) {
|
|
821
|
+
let t = await m();
|
|
822
|
+
await e.unmount({
|
|
823
|
+
api: t,
|
|
824
|
+
widget: d,
|
|
825
|
+
field: n.target,
|
|
826
|
+
services: s,
|
|
827
|
+
options: o,
|
|
828
|
+
provider: o.provider
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
d = null, await h();
|
|
832
|
+
}
|
|
820
833
|
}
|
|
821
834
|
};
|
|
822
835
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { s as e } from "./event-names-BCI2FLD8.js";
|
|
2
|
+
import { t } from "./api-DqpfkZWL.js";
|
|
3
|
+
import { t as n } from "./debug-BV0DvdHx.js";
|
|
4
|
+
import { r } from "./scripts-CbQ7agX3.js";
|
|
5
|
+
import { t as i } from "./styles-BfoIZwJp.js";
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/js/modules/payments/opayo.ts
|
|
8
|
+
i("opayo", ["@layer formie-theme{.formie-opayo-drop-in{box-sizing:border-box;width:100%;min-height:10rem}}"]);
|
|
9
|
+
var a = "FORMIE_OPAYO_SCRIPT", o = "https://live.opayo.eu.elavon.com/api/v1/js/sagepay.js", s = "https://sandbox.opayo.eu.elavon.com/api/v1/js/sagepay.js", c = "[data-formie-opayo-drop-in]", l = n("payments", "opayo"), u = e("opayo", "challenge"), d = "formie:payment:opayo:challenge:response";
|
|
10
|
+
function f(e) {
|
|
11
|
+
return e.checkoutMode === "dropIn";
|
|
12
|
+
}
|
|
13
|
+
async function p(e) {
|
|
14
|
+
let { form: t, handle: n, sessionToken: r, services: i } = e, a = new FormData();
|
|
15
|
+
a.append("action", "formie/payment-webhooks/process-callback"), a.append("merchantSessionKey", "true"), a.append("handle", n), a.append("sessionToken", r);
|
|
16
|
+
try {
|
|
17
|
+
let e = await fetch(t.action, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
body: a
|
|
20
|
+
});
|
|
21
|
+
return e.status < 200 || e.status >= 300 ? (i.addError(`${e.status}: ${e.statusText}`), l.warn("Merchant session request failed.", {
|
|
22
|
+
status: e.status,
|
|
23
|
+
statusText: e.statusText
|
|
24
|
+
}), null) : (await e.json()).merchantSessionKey || (i.addError("Unable to get merchant session."), l.warn("merchantSessionKey missing in callback response."), null);
|
|
25
|
+
} catch {
|
|
26
|
+
return i.addError("Network error. Please try again."), l.warn("Network error requesting merchant session."), null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function m(e) {
|
|
30
|
+
return e.id ||= `formie-opayo-drop-in-${Math.random().toString(36).slice(2, 9)}`, e.id;
|
|
31
|
+
}
|
|
32
|
+
var h = t({
|
|
33
|
+
id: "opayo",
|
|
34
|
+
defaultRequiredInputSuffixes: ["opayoTokenId"],
|
|
35
|
+
load: async (e) => {
|
|
36
|
+
let { provider: t } = e.options, n = t.useSandbox ? s : o;
|
|
37
|
+
return await r(f(t) ? "sagepayCheckout" : "sagepayOwnForm", {
|
|
38
|
+
id: a,
|
|
39
|
+
src: n,
|
|
40
|
+
timeoutMs: 1e4
|
|
41
|
+
}), null;
|
|
42
|
+
},
|
|
43
|
+
mount: async ({ field: e, services: t, provider: n }) => {
|
|
44
|
+
if (!f(n)) return null;
|
|
45
|
+
let r = t.form, i = window.sagepayCheckout, a = e.querySelector(c);
|
|
46
|
+
if (!r?.action) return t.addError("Form action is missing."), l.warn("Missing form action before drop-in mount."), null;
|
|
47
|
+
if (!i) return t.addError("Opayo script failed to load."), l.warn("sagepayCheckout global not available."), null;
|
|
48
|
+
if (!a) return t.addError("Opayo drop-in container is missing."), l.warn("Drop-in container not found in payment field."), null;
|
|
49
|
+
let o = n.handle || "opayo", s = await p({
|
|
50
|
+
form: r,
|
|
51
|
+
handle: o,
|
|
52
|
+
sessionToken: n.sessionToken || "",
|
|
53
|
+
services: t
|
|
54
|
+
});
|
|
55
|
+
if (!s) return null;
|
|
56
|
+
let u = m(a), d = {
|
|
57
|
+
checkout: null,
|
|
58
|
+
merchantSessionKey: s,
|
|
59
|
+
pendingAuthorize: null,
|
|
60
|
+
retriedTokenise: !1
|
|
61
|
+
};
|
|
62
|
+
return d.checkout = i({
|
|
63
|
+
merchantSessionKey: s,
|
|
64
|
+
containerSelector: `#${u}`,
|
|
65
|
+
onTokenise: (e) => {
|
|
66
|
+
let i = d.pendingAuthorize;
|
|
67
|
+
if (d.pendingAuthorize = null, !i) {
|
|
68
|
+
l.warn("Drop-in tokenisation completed without a pending authorize step.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (e.success && e.cardIdentifier) {
|
|
72
|
+
t.updateInputs("opayoTokenId", e.cardIdentifier), t.updateInputs("opayoSessionKey", d.merchantSessionKey), l.log("Drop-in tokenization succeeded.", { hasCardIdentifier: !!e.cardIdentifier }), i(!0);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!d.retriedTokenise) {
|
|
76
|
+
d.retriedTokenise = !0, p({
|
|
77
|
+
form: r,
|
|
78
|
+
handle: o,
|
|
79
|
+
sessionToken: n.sessionToken || "",
|
|
80
|
+
services: t
|
|
81
|
+
}).then((n) => {
|
|
82
|
+
if (!n) {
|
|
83
|
+
t.addError(e.errors?.[0]?.message || "Tokenization failed."), l.warn("Drop-in tokenization failed after session refresh.", e), i(!1);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
d.merchantSessionKey = n, d.pendingAuthorize = i, d.checkout.tokenise({ newMerchantSessionKey: n });
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
t.addError(e.errors?.[0]?.message || "Tokenization failed."), l.warn("Drop-in tokenization failed.", e), i(!1);
|
|
91
|
+
}
|
|
92
|
+
}), l.log("Drop-in checkout mounted.", { containerId: u }), d;
|
|
93
|
+
},
|
|
94
|
+
unmount: async ({ widget: e }) => {
|
|
95
|
+
e?.checkout?.destroy?.();
|
|
96
|
+
},
|
|
97
|
+
onBeforeAuthorize: async (e) => {
|
|
98
|
+
let { field: t, services: n, options: r, provider: i, widget: a } = e, o = i.handle || "opayo", s = n.form;
|
|
99
|
+
if (!s?.action) return n.addError("Form action is missing."), l.warn("Missing form action before authorize."), !1;
|
|
100
|
+
if (f(i)) return a ? (a.retriedTokenise = !1, new Promise((e) => {
|
|
101
|
+
a.pendingAuthorize = e, a.checkout.tokenise();
|
|
102
|
+
})) : (n.addError("Opayo drop-in checkout is not ready."), l.warn("Drop-in authorize requested before widget mount."), !1);
|
|
103
|
+
let c = window.sagepayOwnForm;
|
|
104
|
+
if (!c) return n.addError("Opayo script failed to load."), l.warn("sagepayOwnForm global not available."), !1;
|
|
105
|
+
let u = t.querySelector("[data-opayo-card=\"cardholder-name\"]")?.value ?? "", d = t.querySelector("[data-opayo-card=\"card-number\"]")?.value ?? "", m = t.querySelector("[data-opayo-card=\"expiry-date\"]")?.value ?? "", h = t.querySelector("[data-opayo-card=\"security-code\"]")?.value ?? "";
|
|
106
|
+
d = d.replace(/[\s/]/g, ""), m = m.replace(/[\s/]/g, "");
|
|
107
|
+
let g = await p({
|
|
108
|
+
form: s,
|
|
109
|
+
handle: o,
|
|
110
|
+
sessionToken: i.sessionToken || "",
|
|
111
|
+
services: n
|
|
112
|
+
});
|
|
113
|
+
return g ? new Promise((e) => {
|
|
114
|
+
c({ merchantSessionKey: g }).tokeniseCardDetails({
|
|
115
|
+
cardDetails: {
|
|
116
|
+
cardholderName: u,
|
|
117
|
+
cardNumber: d,
|
|
118
|
+
expiryDate: m,
|
|
119
|
+
securityCode: h
|
|
120
|
+
},
|
|
121
|
+
onTokenised: (t) => {
|
|
122
|
+
t.success && t.cardIdentifier ? (n.updateInputs("opayoTokenId", t.cardIdentifier), n.updateInputs("opayoSessionKey", g), l.log("Tokenization succeeded.", { hasCardIdentifier: !!t.cardIdentifier }), e(!0)) : (n.addError(t.errors?.[0]?.message || "Tokenization failed."), l.warn("Tokenization failed.", t), e(!1));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}) : !1;
|
|
126
|
+
},
|
|
127
|
+
setup: async (e) => {
|
|
128
|
+
let { services: t } = e;
|
|
129
|
+
e.target;
|
|
130
|
+
let n = null, r = !1, i = () => {
|
|
131
|
+
n?.parentNode && n.parentNode.removeChild(n), n = null;
|
|
132
|
+
}, a = t.events.onForm(u, ((e) => {
|
|
133
|
+
let a = e.detail?.data;
|
|
134
|
+
if (!a?.acsUrl || !a?.creq) return;
|
|
135
|
+
r = !1, l.log("Received payment challenge event.", {
|
|
136
|
+
hasAcsUrl: !!a.acsUrl,
|
|
137
|
+
hasCreq: !!a.creq
|
|
138
|
+
});
|
|
139
|
+
let o = t.form?.querySelector("input[name*=\"opayoSessionKey\"]")?.value || "", s = document.createElement("div");
|
|
140
|
+
s.className = "formie-modal", s.id = `formie-opayo-dialog-${Math.random().toString(36).slice(2, 9)}`, s.innerHTML = "\n <div class=\"formie-modal-backdrop\" data-dialog-close></div>\n <div class=\"formie-modal-content\">\n <div class=\"formie-loading formie-loading-large\" style=\"--formie-loading-width: 3rem; --formie-loading-height: 3rem; top: 50%; margin-top: -1.5rem;\"></div>\n <iframe width=\"100%\" height=\"100%\" style=\"width: 100%; height: 100%; position: relative; z-index: 1;\"></iframe>\n </div>\n ";
|
|
141
|
+
let c = s.querySelector("iframe"), u = (e) => e.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<"), d = a.returnUrl || a.redirectUrl || "", f = `<form action="${u(a.acsUrl)}" method="post">
|
|
142
|
+
<input type="hidden" name="creq" value="${u(a.creq || "")}" />
|
|
143
|
+
<input type="hidden" name="threeDSSessionData" value="${u(a.threeDSSessionData || "")}" />
|
|
144
|
+
<input type="hidden" name="MD" value="${u(o)}" />
|
|
145
|
+
<input type="hidden" name="TermUrl" value="${u(d)}" />
|
|
146
|
+
<input type="hidden" name="ThreeDSNotificationURL" value="${u(d)}" />
|
|
147
|
+
</form><script>document.forms[0].submit();<\/script>`;
|
|
148
|
+
i(), document.body.appendChild(s), n = s, c?.contentWindow && (c.contentWindow.document.open(), c.contentWindow.document.write(f), c.contentWindow.document.close());
|
|
149
|
+
})), o = (e) => {
|
|
150
|
+
if (e.data?.message === d) {
|
|
151
|
+
if (!n) {
|
|
152
|
+
l.log("Ignoring 3DS response without active dialog.");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (r) {
|
|
156
|
+
l.warn("Ignoring duplicate 3DS response while processing.");
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (r = !0, l.log("Received payment challenge response message.", e.data?.value), i(), t.removeError(), e.data?.value?.error) {
|
|
160
|
+
t.addError(e.data.value.error.message), t.releaseSubmitLoading(), r = !1;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
t.updateInputs("opayo3DSComplete", e.data.value?.transactionId ?? ""), t.triggerSubmit();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
return window.addEventListener("message", o), { destroy: () => {
|
|
167
|
+
a(), window.removeEventListener("message", o), i(), r = !1;
|
|
168
|
+
} };
|
|
169
|
+
},
|
|
170
|
+
onAfterSubmit: async ({ services: e }) => {
|
|
171
|
+
e.updateInputs([
|
|
172
|
+
"opayoTokenId",
|
|
173
|
+
"opayoSessionKey",
|
|
174
|
+
"opayo3DSComplete"
|
|
175
|
+
], "");
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
//#endregion
|
|
179
|
+
export { h as opayoModule };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { s as e } from "./event-names-BCI2FLD8.js";
|
|
2
|
-
import { t } from "./api-
|
|
2
|
+
import { t } from "./api-DqpfkZWL.js";
|
|
3
3
|
import { r as n } from "./scripts-CbQ7agX3.js";
|
|
4
4
|
//#region src/js/modules/payments/paddle.ts
|
|
5
5
|
var r = "FORMIE_PADDLE_SCRIPT", i = e("paddle", "initialize"), a = t({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./api-
|
|
1
|
+
import { t as e } from "./api-DqpfkZWL.js";
|
|
2
2
|
import { r as t } from "./scripts-CbQ7agX3.js";
|
|
3
3
|
import { t as n } from "./styles-BfoIZwJp.js";
|
|
4
4
|
//#endregion
|
|
@@ -11,49 +11,52 @@ function i(e) {
|
|
|
11
11
|
return String(n[0]?.id || r[0]?.id || "").trim();
|
|
12
12
|
}
|
|
13
13
|
function a(e, t) {
|
|
14
|
+
e?.close && e.close(), t.removeAttribute("data-formie-paypal-rendered"), t.innerHTML = "";
|
|
15
|
+
}
|
|
16
|
+
function o(e, t) {
|
|
14
17
|
return `https://www.paypal.com/sdk/js?${[
|
|
15
18
|
"intent=authorize",
|
|
16
19
|
`currency=${encodeURIComponent(t)}`,
|
|
17
20
|
`client-id=${encodeURIComponent(e)}`
|
|
18
21
|
].join("&")}`;
|
|
19
22
|
}
|
|
20
|
-
var
|
|
23
|
+
var s = e({
|
|
21
24
|
id: "paypal",
|
|
22
25
|
defaultRequiredInputSuffixes: ["paypalOrderId", "paypalAuthId"],
|
|
23
26
|
load: async (e) => {
|
|
24
27
|
let { provider: n } = e.options, i = n.clientId;
|
|
25
28
|
return i?.trim() ? (await t("paypal", {
|
|
26
29
|
id: r,
|
|
27
|
-
src:
|
|
30
|
+
src: o(i, n.currency || "AUD")
|
|
28
31
|
}), window.paypal) : (console.error("[formie] Missing clientId for PayPal."), null);
|
|
29
32
|
},
|
|
30
33
|
mount: async (e) => {
|
|
31
|
-
let { api: t, field: n, services: r, options:
|
|
32
|
-
if (!
|
|
33
|
-
|
|
34
|
-
let
|
|
35
|
-
value:
|
|
34
|
+
let { api: t, field: n, services: r, options: o, provider: s } = e, c = n.querySelector("[data-formie-paypal-button]");
|
|
35
|
+
if (!c || !t || c.getAttribute("data-formie-paypal-rendered") === "true") return null;
|
|
36
|
+
c.innerHTML = "";
|
|
37
|
+
let l = !!s.useSandbox, u = r.resolveCurrency({
|
|
38
|
+
value: s.currency,
|
|
36
39
|
defaultCurrency: "AUD"
|
|
37
40
|
});
|
|
38
|
-
if (!
|
|
39
|
-
let
|
|
40
|
-
layout:
|
|
41
|
-
color:
|
|
42
|
-
shape:
|
|
43
|
-
label:
|
|
44
|
-
width:
|
|
45
|
-
height:
|
|
41
|
+
if (!u.ok) return r.addError("error" in u ? u.error : "Invalid PayPal currency."), null;
|
|
42
|
+
let d = u.value, f = {
|
|
43
|
+
layout: s.buttonLayout || "vertical",
|
|
44
|
+
color: s.buttonColor || "gold",
|
|
45
|
+
shape: s.buttonShape || "rect",
|
|
46
|
+
label: s.buttonLabel || "paypal",
|
|
47
|
+
width: s.buttonWidth || 250,
|
|
48
|
+
height: s.buttonHeight || 35
|
|
46
49
|
};
|
|
47
|
-
|
|
48
|
-
let
|
|
49
|
-
env:
|
|
50
|
-
style:
|
|
50
|
+
f.layout === "horizontal" && (f.tagline = s.buttonTagline ?? !0);
|
|
51
|
+
let p = null, m = {
|
|
52
|
+
env: l ? "sandbox" : "production",
|
|
53
|
+
style: f,
|
|
51
54
|
createOrder: (e, t) => {
|
|
52
55
|
r.removeError();
|
|
53
56
|
let n = r.resolveAmount({
|
|
54
|
-
type:
|
|
55
|
-
fixed:
|
|
56
|
-
variable:
|
|
57
|
+
type: s.amountType,
|
|
58
|
+
fixed: s.amountFixed,
|
|
59
|
+
variable: s.amountVariable
|
|
57
60
|
});
|
|
58
61
|
if (!n.ok) {
|
|
59
62
|
let e = "error" in n ? n.error : "Invalid PayPal amount.";
|
|
@@ -63,7 +66,7 @@ var o = e({
|
|
|
63
66
|
intent: "AUTHORIZE",
|
|
64
67
|
application_context: { user_action: "CONTINUE" },
|
|
65
68
|
purchase_units: [{ amount: {
|
|
66
|
-
currency_code:
|
|
69
|
+
currency_code: d,
|
|
67
70
|
value: String(n.value)
|
|
68
71
|
} }]
|
|
69
72
|
});
|
|
@@ -74,22 +77,20 @@ var o = e({
|
|
|
74
77
|
onApprove: async (e, t) => {
|
|
75
78
|
try {
|
|
76
79
|
let n = i(await t.order.authorize());
|
|
77
|
-
r.updateInputs("paypalOrderId", e.orderID), r.updateInputs("paypalAuthId", n || ""), n ? r.addSuccess("Payment authorized. Finalize the form to complete payment.") : r.addSuccess("PayPal approval received. Finalizing payment on submit.");
|
|
80
|
+
r.updateInputs("paypalOrderId", e.orderID), r.updateInputs("paypalAuthId", n || ""), n ? r.addSuccess("Payment authorized. Finalize the form to complete payment.") : r.addSuccess("PayPal approval received. Finalizing payment on submit."), a(p, c);
|
|
78
81
|
} catch {
|
|
79
82
|
r.addError("Unable to authorize payment. Please try again.");
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
|
-
},
|
|
83
|
-
return
|
|
85
|
+
}, h = t.Buttons(m);
|
|
86
|
+
return c.setAttribute("data-formie-paypal-rendered", "true"), p = h.render(c), p;
|
|
84
87
|
},
|
|
85
88
|
unmount: async (e) => {
|
|
86
89
|
e.widget?.close && e.widget.close();
|
|
87
90
|
let t = e.field.querySelector("[data-formie-paypal-button]");
|
|
88
91
|
t && (t.removeAttribute("data-formie-paypal-rendered"), t.innerHTML = "");
|
|
89
92
|
},
|
|
90
|
-
onAfterSubmit: async ({ services: e }) => {
|
|
91
|
-
e.updateInputs(["paypalOrderId", "paypalAuthId"], ""), e.removeSuccess(), e.removeError();
|
|
92
|
-
}
|
|
93
|
+
onAfterSubmit: async ({ services: e, result: t }) => (e.updateInputs(["paypalOrderId", "paypalAuthId"], ""), e.removeSuccess(), e.removeError(), !t?.ok || t?.nextPage ? { remount: !0 } : {})
|
|
93
94
|
});
|
|
94
95
|
//#endregion
|
|
95
|
-
export {
|
|
96
|
+
export { s as paypalModule };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { s as e } from "./event-names-BCI2FLD8.js";
|
|
2
|
-
import { t } from "./api-
|
|
2
|
+
import { t } from "./api-DqpfkZWL.js";
|
|
3
3
|
import { r as n, t as r } from "./theme-classes-Tv7q7ToE.js";
|
|
4
4
|
import { r as i } from "./scripts-CbQ7agX3.js";
|
|
5
5
|
import { t as a } from "./styles-BfoIZwJp.js";
|
|
@@ -116,8 +116,10 @@
|
|
|
116
116
|
|
|
117
117
|
.formie-field-option:has(> input[data-formie-other-option]),
|
|
118
118
|
.formie-other-option {
|
|
119
|
+
display: flex;
|
|
119
120
|
flex-wrap: wrap;
|
|
120
|
-
align-items:
|
|
121
|
+
align-items: center;
|
|
122
|
+
width: 100%;
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
.formie-field-option:has(> input[data-formie-other-option]:checked) > .formie-other-option-text,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as e, d as t, l as n, o as r, r as i, t as a, u as o } from "./chunks/event-names-BCI2FLD8.js";
|
|
2
|
-
import { a as s, c, d as l, f as u, i as d, l as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y } from "./chunks/api-
|
|
2
|
+
import { a as s, c, d as l, f as u, i as d, l as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y } from "./chunks/api-DqpfkZWL.js";
|
|
3
3
|
import { a as b, i as x, n as ee, r as te, t as S } from "./chunks/debug-BV0DvdHx.js";
|
|
4
4
|
import { n as ne, r as C, t as w } from "./chunks/theme-classes-Tv7q7ToE.js";
|
|
5
5
|
import { t as T } from "./chunks/http-D-JExro7.js";
|
|
@@ -1407,17 +1407,17 @@ var L = class {
|
|
|
1407
1407
|
table: () => import("./chunks/table-CAjCJHrL.js").then((e) => e.tableModule),
|
|
1408
1408
|
"text-limit": () => import("./chunks/text-limit-Bn18WrPU.js").then((e) => e.textLimitModule)
|
|
1409
1409
|
}, Zt = {
|
|
1410
|
-
bpoint: () => import("./chunks/bpoint-
|
|
1411
|
-
eway: () => import("./chunks/eway-
|
|
1412
|
-
"go-cardless": () => import("./chunks/go-cardless-
|
|
1413
|
-
mollie: () => import("./chunks/mollie-
|
|
1414
|
-
moneris: () => import("./chunks/moneris-
|
|
1415
|
-
opayo: () => import("./chunks/opayo-
|
|
1416
|
-
paddle: () => import("./chunks/paddle-
|
|
1417
|
-
paypal: () => import("./chunks/paypal-
|
|
1418
|
-
payway: () => import("./chunks/payway-
|
|
1419
|
-
square: () => import("./chunks/square-
|
|
1420
|
-
stripe: () => import("./chunks/stripe-
|
|
1410
|
+
bpoint: () => import("./chunks/bpoint-Dlq34XH1.js").then((e) => e.bpointModule),
|
|
1411
|
+
eway: () => import("./chunks/eway-D9_m8ooj.js").then((e) => e.ewayModule),
|
|
1412
|
+
"go-cardless": () => import("./chunks/go-cardless-DAT3ZaQf.js").then((e) => e.goCardlessModule),
|
|
1413
|
+
mollie: () => import("./chunks/mollie-Bibhl67p.js").then((e) => e.mollieModule),
|
|
1414
|
+
moneris: () => import("./chunks/moneris-H2wSqk9h.js").then((e) => e.monerisModule),
|
|
1415
|
+
opayo: () => import("./chunks/opayo-CR0DtsLa.js").then((e) => e.opayoModule),
|
|
1416
|
+
paddle: () => import("./chunks/paddle-DkvIxQdG.js").then((e) => e.paddleModule),
|
|
1417
|
+
paypal: () => import("./chunks/paypal-CQpAF7Ua.js").then((e) => e.paypalModule),
|
|
1418
|
+
payway: () => import("./chunks/payway-CwDkC7YZ.js").then((e) => e.paywayModule),
|
|
1419
|
+
square: () => import("./chunks/square-DwdcOI1G.js").then((e) => e.squareModule),
|
|
1420
|
+
stripe: () => import("./chunks/stripe-DaoG2FT1.js").then((e) => e.stripeModule)
|
|
1421
1421
|
}, Qt = {
|
|
1422
1422
|
...Xt,
|
|
1423
1423
|
...Jt,
|
|
@@ -8,6 +8,10 @@ type PaymentSetupResult = {
|
|
|
8
8
|
destroy?: () => void | Promise<void>;
|
|
9
9
|
onBeforeStage?: (stageCtx: import('#contracts/modules').SubmitHookContext) => void | Promise<void>;
|
|
10
10
|
};
|
|
11
|
+
export type PaymentAfterSubmitResult = {
|
|
12
|
+
/** Tear down the current widget and mount again (for example after a failed payment). */
|
|
13
|
+
remount?: boolean;
|
|
14
|
+
};
|
|
11
15
|
export type ManagedPaymentModuleAdapter<TProvider extends Record<string, unknown>, TApi, TWidget> = {
|
|
12
16
|
id: string;
|
|
13
17
|
defaultRequiredInputSuffixes?: string[];
|
|
@@ -47,7 +51,7 @@ export type ManagedPaymentModuleAdapter<TProvider extends Record<string, unknown
|
|
|
47
51
|
options: NormalizedPaymentModuleOptions<TProvider>;
|
|
48
52
|
provider: TProvider;
|
|
49
53
|
result?: import('#contracts/schema').FormSubmitResult;
|
|
50
|
-
}) => void | Promise<void>;
|
|
54
|
+
}) => void | Promise<void> | PaymentAfterSubmitResult | Promise<PaymentAfterSubmitResult>;
|
|
51
55
|
};
|
|
52
56
|
export declare function createManagedPaymentModule<TProvider extends Record<string, unknown>, TApi, TWidget>(adapter: ManagedPaymentModuleAdapter<TProvider, TApi, TWidget>): FormieModuleDefinition;
|
|
53
57
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,sBAAsB,EAEtB,kBAAkB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEH,KAAK,8BAA8B,EACnC,KAAK,mBAAmB,EAE3B,MAAM,wBAAwB,CAAC;AAchC,MAAM,MAAM,yBAAyB,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,GAAG;IACrH,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;IACnD,QAAQ,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,oBAAoB,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtG,CAAC;AAEF,MAAM,MAAM,2BAA2B,CACnC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,IAAI,EACJ,OAAO,IACP;IACA,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,yBAAyB,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,uGAAuG;IACvG,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3G,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE;QACX,GAAG,EAAE,IAAI,CAAC;QACV,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;KACvB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QACb,GAAG,EAAE,IAAI,CAAC;QACV,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;KACvB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QACvB,GAAG,EAAE,IAAI,CAAC;QACV,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;QACvB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;QACpB,QAAQ,EAAE,OAAO,oBAAoB,EAAE,iBAAiB,CAAC;KAC5D,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjC,mFAAmF;IACnF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACnB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;QACpB,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,CAAC;KACzD,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/factories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,sBAAsB,EAEtB,kBAAkB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAEH,KAAK,8BAA8B,EACnC,KAAK,mBAAmB,EAE3B,MAAM,wBAAwB,CAAC;AAchC,MAAM,MAAM,yBAAyB,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,GAAG;IACrH,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;IACnD,QAAQ,EAAE,mBAAmB,CAAC;CACjC,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,oBAAoB,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtG,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACnC,yFAAyF;IACzF,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,2BAA2B,CACnC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,IAAI,EACJ,OAAO,IACP;IACA,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,yBAAyB,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,uGAAuG;IACvG,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3G,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE;QACX,GAAG,EAAE,IAAI,CAAC;QACV,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;KACvB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QACb,GAAG,EAAE,IAAI,CAAC;QACV,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;KACvB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QACvB,GAAG,EAAE,IAAI,CAAC;QACV,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;QACvB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;QACpB,QAAQ,EAAE,OAAO,oBAAoB,EAAE,iBAAiB,CAAC;KAC5D,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjC,mFAAmF;IACnF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACnB,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,mBAAmB,CAAC;QAC9B,OAAO,EAAE,8BAA8B,CAAC,SAAS,CAAC,CAAC;QACnD,QAAQ,EAAE,SAAS,CAAC;QACpB,MAAM,CAAC,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,CAAC;KACzD,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC7F,CAAC;AAEF,wBAAgB,0BAA0B,CACtC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,IAAI,EACJ,OAAO,EACT,OAAO,EAAE,2BAA2B,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,sBAAsB,CA4QxF"}
|
|
@@ -5,7 +5,7 @@ type SagePayTokeniseResult = {
|
|
|
5
5
|
message: string;
|
|
6
6
|
}>;
|
|
7
7
|
};
|
|
8
|
-
type
|
|
8
|
+
type SagePayOwnFormGlobal = {
|
|
9
9
|
(opts: {
|
|
10
10
|
merchantSessionKey: string;
|
|
11
11
|
}): {
|
|
@@ -15,9 +15,24 @@ type SagePayGlobal = {
|
|
|
15
15
|
}) => void;
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
|
+
type SagePayCheckoutInstance = {
|
|
19
|
+
tokenise: (opts?: {
|
|
20
|
+
newMerchantSessionKey?: string;
|
|
21
|
+
}) => void;
|
|
22
|
+
destroy: () => void;
|
|
23
|
+
};
|
|
24
|
+
type SagePayCheckoutGlobal = {
|
|
25
|
+
(opts: {
|
|
26
|
+
merchantSessionKey: string;
|
|
27
|
+
containerSelector: string;
|
|
28
|
+
onTokenise?: (result: SagePayTokeniseResult) => void;
|
|
29
|
+
reusableCardIdentifier?: string;
|
|
30
|
+
}): SagePayCheckoutInstance;
|
|
31
|
+
};
|
|
18
32
|
declare global {
|
|
19
33
|
interface Window {
|
|
20
|
-
sagepayOwnForm?:
|
|
34
|
+
sagepayOwnForm?: SagePayOwnFormGlobal;
|
|
35
|
+
sagepayCheckout?: SagePayCheckoutGlobal;
|
|
21
36
|
}
|
|
22
37
|
}
|
|
23
38
|
export declare const opayoModule: import("../../..").FormieModuleDefinition;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opayo.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/opayo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opayo.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/opayo.ts"],"names":[],"mappings":"AAUA,KAAK,qBAAqB,GAAG;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvC,CAAC;AAEF,KAAK,oBAAoB,GAAG;IACxB,CAAC,IAAI,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAA;KAAE,GAAG;QACpC,mBAAmB,EAAE,CAAC,IAAI,EAAE;YACxB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACpC,WAAW,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;SACxD,KAAK,IAAI,CAAC;KACd,CAAC;CACL,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC3B,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IACzB,CAAC,IAAI,EAAE;QACH,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;QACrD,sBAAsB,CAAC,EAAE,MAAM,CAAC;KACnC,GAAG,uBAAuB,CAAC;CAC/B,CAAC;AAEF,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,cAAc,CAAC,EAAE,oBAAoB,CAAC;QACtC,eAAe,CAAC,EAAE,qBAAqB,CAAC;KAC3C;CACJ;AAwFD,eAAO,MAAM,WAAW,2CAsUtB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paypal.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/paypal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"paypal.d.ts","sourceRoot":"","sources":["../../../../src/js/modules/payments/paypal.ts"],"names":[],"mappings":"AAqFA,eAAO,MAAM,YAAY,2CAoJvB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verbb/formie-browser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@placekit/autocomplete-js": "^2.2.1",
|
|
71
71
|
"@uppy/core": "^5.2.0",
|
|
72
72
|
"@uppy/xhr-upload": "^5.2.0",
|
|
73
|
-
"@verbb/formie-core": "1.0.
|
|
73
|
+
"@verbb/formie-core": "1.0.12",
|
|
74
74
|
"expression-language": "^2.5.4",
|
|
75
75
|
"flatpickr": "^4.6.13",
|
|
76
76
|
"friendly-challenge": "^0.9.19",
|
|
@@ -116,8 +116,10 @@
|
|
|
116
116
|
|
|
117
117
|
.formie-field-option:has(> input[data-formie-other-option]),
|
|
118
118
|
.formie-other-option {
|
|
119
|
+
display: flex;
|
|
119
120
|
flex-wrap: wrap;
|
|
120
|
-
align-items:
|
|
121
|
+
align-items: center;
|
|
122
|
+
width: 100%;
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
.formie-field-option:has(> input[data-formie-other-option]:checked) > .formie-other-option-text,
|
|
@@ -33,6 +33,11 @@ type PaymentSetupResult = {
|
|
|
33
33
|
onBeforeStage?: (stageCtx: import('#contracts/modules').SubmitHookContext) => void | Promise<void>;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
export type PaymentAfterSubmitResult = {
|
|
37
|
+
/** Tear down the current widget and mount again (for example after a failed payment). */
|
|
38
|
+
remount?: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
36
41
|
export type ManagedPaymentModuleAdapter<
|
|
37
42
|
TProvider extends Record<string, unknown>,
|
|
38
43
|
TApi,
|
|
@@ -74,7 +79,7 @@ export type ManagedPaymentModuleAdapter<
|
|
|
74
79
|
options: NormalizedPaymentModuleOptions<TProvider>;
|
|
75
80
|
provider: TProvider;
|
|
76
81
|
result?: import('#contracts/schema').FormSubmitResult;
|
|
77
|
-
}) => void | Promise<void>;
|
|
82
|
+
}) => void | Promise<void> | PaymentAfterSubmitResult | Promise<PaymentAfterSubmitResult>;
|
|
78
83
|
};
|
|
79
84
|
|
|
80
85
|
export function createManagedPaymentModule<
|
|
@@ -318,13 +323,33 @@ export function createManagedPaymentModule<
|
|
|
318
323
|
return;
|
|
319
324
|
}
|
|
320
325
|
|
|
321
|
-
await adapter.onAfterSubmit({
|
|
326
|
+
const afterSubmitResult = await adapter.onAfterSubmit({
|
|
322
327
|
field: ctx.target,
|
|
323
328
|
services,
|
|
324
329
|
options,
|
|
325
330
|
provider: options.provider,
|
|
326
331
|
result,
|
|
327
332
|
});
|
|
333
|
+
|
|
334
|
+
if (!afterSubmitResult?.remount || !adapter.mount) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (widget && adapter.unmount) {
|
|
339
|
+
const api = await getApi();
|
|
340
|
+
|
|
341
|
+
await adapter.unmount({
|
|
342
|
+
api,
|
|
343
|
+
widget,
|
|
344
|
+
field: ctx.target,
|
|
345
|
+
services,
|
|
346
|
+
options,
|
|
347
|
+
provider: options.provider,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
widget = null;
|
|
352
|
+
await ensureMounted();
|
|
328
353
|
},
|
|
329
354
|
};
|
|
330
355
|
},
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import opayoCss from '#theme-css/integrations/_opayo.css?inline';
|
|
2
|
+
|
|
1
3
|
import { definePaymentModule } from '#modules/payments/api';
|
|
4
|
+
import { ensureModuleStyles } from '#modules/styles';
|
|
2
5
|
import { createDebug } from '#utils/debug';
|
|
3
6
|
import { getPaymentProviderActionEventName } from '#utils/event-names';
|
|
4
7
|
import { loadScriptAndEnsureGlobal } from '#utils/scripts';
|
|
5
8
|
|
|
9
|
+
ensureModuleStyles('opayo', [opayoCss]);
|
|
10
|
+
|
|
6
11
|
type SagePayTokeniseResult = {
|
|
7
12
|
success: boolean;
|
|
8
13
|
cardIdentifier?: string;
|
|
9
14
|
errors?: Array<{ message: string }>;
|
|
10
15
|
};
|
|
11
16
|
|
|
12
|
-
type
|
|
17
|
+
type SagePayOwnFormGlobal = {
|
|
13
18
|
(opts: { merchantSessionKey: string }): {
|
|
14
19
|
tokeniseCardDetails: (opts: {
|
|
15
20
|
cardDetails: Record<string, string>;
|
|
@@ -18,34 +23,123 @@ type SagePayGlobal = {
|
|
|
18
23
|
};
|
|
19
24
|
};
|
|
20
25
|
|
|
26
|
+
type SagePayCheckoutInstance = {
|
|
27
|
+
tokenise: (opts?: { newMerchantSessionKey?: string }) => void;
|
|
28
|
+
destroy: () => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type SagePayCheckoutGlobal = {
|
|
32
|
+
(opts: {
|
|
33
|
+
merchantSessionKey: string;
|
|
34
|
+
containerSelector: string;
|
|
35
|
+
onTokenise?: (result: SagePayTokeniseResult) => void;
|
|
36
|
+
reusableCardIdentifier?: string;
|
|
37
|
+
}): SagePayCheckoutInstance;
|
|
38
|
+
};
|
|
39
|
+
|
|
21
40
|
declare global {
|
|
22
41
|
interface Window {
|
|
23
|
-
sagepayOwnForm?:
|
|
42
|
+
sagepayOwnForm?: SagePayOwnFormGlobal;
|
|
43
|
+
sagepayCheckout?: SagePayCheckoutGlobal;
|
|
24
44
|
}
|
|
25
45
|
}
|
|
26
46
|
|
|
47
|
+
type OpayoCheckoutMode = 'ownForm' | 'dropIn';
|
|
48
|
+
|
|
27
49
|
type OpayoProviderOptions = {
|
|
28
50
|
useSandbox?: boolean;
|
|
29
51
|
handle?: string;
|
|
30
52
|
sessionToken?: string | null;
|
|
53
|
+
checkoutMode?: OpayoCheckoutMode;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type OpayoDropInWidget = {
|
|
57
|
+
checkout: SagePayCheckoutInstance;
|
|
58
|
+
merchantSessionKey: string;
|
|
59
|
+
pendingAuthorize: ((success: boolean) => void) | null;
|
|
60
|
+
retriedTokenise: boolean;
|
|
31
61
|
};
|
|
32
62
|
|
|
33
63
|
const SCRIPT_ID = 'FORMIE_OPAYO_SCRIPT';
|
|
34
64
|
const SCRIPT_SRC_LIVE = 'https://live.opayo.eu.elavon.com/api/v1/js/sagepay.js';
|
|
35
65
|
const SCRIPT_SRC_SANDBOX = 'https://sandbox.opayo.eu.elavon.com/api/v1/js/sagepay.js';
|
|
66
|
+
const DROP_IN_SELECTOR = '[data-formie-opayo-drop-in]';
|
|
36
67
|
const debug = createDebug('payments', 'opayo');
|
|
37
68
|
const CHALLENGE_EVENT = getPaymentProviderActionEventName('opayo', 'challenge');
|
|
38
69
|
const CHALLENGE_RESPONSE_MESSAGE = 'formie:payment:opayo:challenge:response';
|
|
39
70
|
|
|
40
|
-
|
|
71
|
+
function isDropInCheckoutMode(provider: OpayoProviderOptions): boolean {
|
|
72
|
+
return provider.checkoutMode === 'dropIn';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function requestMerchantSessionKey(args: {
|
|
76
|
+
form: HTMLFormElement;
|
|
77
|
+
handle: string;
|
|
78
|
+
sessionToken: string;
|
|
79
|
+
services: {
|
|
80
|
+
addError: (message: string) => void;
|
|
81
|
+
};
|
|
82
|
+
}): Promise<string | null> {
|
|
83
|
+
const { form, handle, sessionToken, services } = args;
|
|
84
|
+
const formData = new FormData();
|
|
85
|
+
formData.append('action', 'formie/payment-webhooks/process-callback');
|
|
86
|
+
formData.append('merchantSessionKey', 'true');
|
|
87
|
+
formData.append('handle', handle);
|
|
88
|
+
formData.append('sessionToken', sessionToken);
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const res = await fetch(form.action, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
body: formData,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (res.status < 200 || res.status >= 300) {
|
|
97
|
+
services.addError(`${res.status}: ${res.statusText}`);
|
|
98
|
+
debug.warn('Merchant session request failed.', {
|
|
99
|
+
status: res.status,
|
|
100
|
+
statusText: res.statusText,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const response = await res.json();
|
|
107
|
+
const merchantSessionKey = response.merchantSessionKey;
|
|
108
|
+
|
|
109
|
+
if (!merchantSessionKey) {
|
|
110
|
+
services.addError('Unable to get merchant session.');
|
|
111
|
+
debug.warn('merchantSessionKey missing in callback response.');
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return merchantSessionKey as string;
|
|
117
|
+
} catch {
|
|
118
|
+
services.addError('Network error. Please try again.');
|
|
119
|
+
debug.warn('Network error requesting merchant session.');
|
|
120
|
+
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function ensureDropInContainerId(container: HTMLElement): string {
|
|
126
|
+
if (!container.id) {
|
|
127
|
+
container.id = `formie-opayo-drop-in-${Math.random().toString(36).slice(2, 9)}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return container.id;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const opayoModule = definePaymentModule<OpayoProviderOptions, null, OpayoDropInWidget | null>({
|
|
41
134
|
id: 'opayo',
|
|
42
135
|
defaultRequiredInputSuffixes: ['opayoTokenId'],
|
|
43
136
|
load: async(ctx) => {
|
|
44
137
|
const { provider } = ctx.options;
|
|
45
138
|
const useSandbox = Boolean(provider.useSandbox);
|
|
46
139
|
const src = useSandbox ? SCRIPT_SRC_SANDBOX : SCRIPT_SRC_LIVE;
|
|
140
|
+
const globalName = isDropInCheckoutMode(provider) ? 'sagepayCheckout' : 'sagepayOwnForm';
|
|
47
141
|
|
|
48
|
-
await loadScriptAndEnsureGlobal<Window['sagepayOwnForm']>(
|
|
142
|
+
await loadScriptAndEnsureGlobal<Window['sagepayOwnForm'] | Window['sagepayCheckout']>(globalName, {
|
|
49
143
|
id: SCRIPT_ID,
|
|
50
144
|
src,
|
|
51
145
|
timeoutMs: 10000,
|
|
@@ -53,9 +147,118 @@ export const opayoModule = definePaymentModule<OpayoProviderOptions, null, null>
|
|
|
53
147
|
|
|
54
148
|
return null;
|
|
55
149
|
},
|
|
150
|
+
mount: async({ field, services, provider }) => {
|
|
151
|
+
if (!isDropInCheckoutMode(provider)) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const form = services.form;
|
|
156
|
+
const sagepayCheckout = window.sagepayCheckout;
|
|
157
|
+
const container = field.querySelector<HTMLElement>(DROP_IN_SELECTOR);
|
|
158
|
+
|
|
159
|
+
if (!form?.action) {
|
|
160
|
+
services.addError('Form action is missing.');
|
|
161
|
+
debug.warn('Missing form action before drop-in mount.');
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!sagepayCheckout) {
|
|
167
|
+
services.addError('Opayo script failed to load.');
|
|
168
|
+
debug.warn('sagepayCheckout global not available.');
|
|
169
|
+
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!container) {
|
|
174
|
+
services.addError('Opayo drop-in container is missing.');
|
|
175
|
+
debug.warn('Drop-in container not found in payment field.');
|
|
176
|
+
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const handle = (provider.handle || 'opayo') as string;
|
|
181
|
+
const merchantSessionKey = await requestMerchantSessionKey({
|
|
182
|
+
form,
|
|
183
|
+
handle,
|
|
184
|
+
sessionToken: provider.sessionToken || '',
|
|
185
|
+
services,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (!merchantSessionKey) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const containerId = ensureDropInContainerId(container);
|
|
193
|
+
const widget: OpayoDropInWidget = {
|
|
194
|
+
checkout: null as unknown as SagePayCheckoutInstance,
|
|
195
|
+
merchantSessionKey,
|
|
196
|
+
pendingAuthorize: null,
|
|
197
|
+
retriedTokenise: false,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
widget.checkout = sagepayCheckout({
|
|
201
|
+
merchantSessionKey,
|
|
202
|
+
containerSelector: `#${containerId}`,
|
|
203
|
+
onTokenise: (result) => {
|
|
204
|
+
const resolve = widget.pendingAuthorize;
|
|
205
|
+
widget.pendingAuthorize = null;
|
|
206
|
+
|
|
207
|
+
if (!resolve) {
|
|
208
|
+
debug.warn('Drop-in tokenisation completed without a pending authorize step.');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (result.success && result.cardIdentifier) {
|
|
213
|
+
services.updateInputs('opayoTokenId', result.cardIdentifier);
|
|
214
|
+
services.updateInputs('opayoSessionKey', widget.merchantSessionKey);
|
|
215
|
+
debug.log('Drop-in tokenization succeeded.', {
|
|
216
|
+
hasCardIdentifier: !!result.cardIdentifier,
|
|
217
|
+
});
|
|
218
|
+
resolve(true);
|
|
219
|
+
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!widget.retriedTokenise) {
|
|
224
|
+
widget.retriedTokenise = true;
|
|
225
|
+
void requestMerchantSessionKey({
|
|
226
|
+
form,
|
|
227
|
+
handle,
|
|
228
|
+
sessionToken: provider.sessionToken || '',
|
|
229
|
+
services,
|
|
230
|
+
}).then((newMerchantSessionKey) => {
|
|
231
|
+
if (!newMerchantSessionKey) {
|
|
232
|
+
services.addError(result.errors?.[0]?.message || 'Tokenization failed.');
|
|
233
|
+
debug.warn('Drop-in tokenization failed after session refresh.', result);
|
|
234
|
+
resolve(false);
|
|
235
|
+
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
widget.merchantSessionKey = newMerchantSessionKey;
|
|
240
|
+
widget.pendingAuthorize = resolve;
|
|
241
|
+
widget.checkout.tokenise({ newMerchantSessionKey });
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
services.addError(result.errors?.[0]?.message || 'Tokenization failed.');
|
|
248
|
+
debug.warn('Drop-in tokenization failed.', result);
|
|
249
|
+
resolve(false);
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
debug.log('Drop-in checkout mounted.', { containerId });
|
|
254
|
+
|
|
255
|
+
return widget;
|
|
256
|
+
},
|
|
257
|
+
unmount: async({ widget }) => {
|
|
258
|
+
widget?.checkout?.destroy?.();
|
|
259
|
+
},
|
|
56
260
|
onBeforeAuthorize: async(args) => {
|
|
57
|
-
const { field, services, options } = args;
|
|
58
|
-
const provider = options.provider as OpayoProviderOptions;
|
|
261
|
+
const { field, services, options, provider, widget } = args;
|
|
59
262
|
const handle = (provider.handle || 'opayo') as string;
|
|
60
263
|
const form = services.form;
|
|
61
264
|
|
|
@@ -66,7 +269,23 @@ export const opayoModule = definePaymentModule<OpayoProviderOptions, null, null>
|
|
|
66
269
|
return false;
|
|
67
270
|
}
|
|
68
271
|
|
|
69
|
-
|
|
272
|
+
if (isDropInCheckoutMode(provider)) {
|
|
273
|
+
if (!widget) {
|
|
274
|
+
services.addError('Opayo drop-in checkout is not ready.');
|
|
275
|
+
debug.warn('Drop-in authorize requested before widget mount.');
|
|
276
|
+
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
widget.retriedTokenise = false;
|
|
281
|
+
|
|
282
|
+
return new Promise<boolean>((resolve) => {
|
|
283
|
+
widget.pendingAuthorize = resolve;
|
|
284
|
+
widget.checkout.tokenise();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const sagepayOwnForm = window.sagepayOwnForm;
|
|
70
289
|
|
|
71
290
|
if (!sagepayOwnForm) {
|
|
72
291
|
services.addError('Opayo script failed to load.');
|
|
@@ -83,72 +302,40 @@ export const opayoModule = definePaymentModule<OpayoProviderOptions, null, null>
|
|
|
83
302
|
cardNumber = cardNumber.replace(/[\s/]/g, '');
|
|
84
303
|
expiryDate = expiryDate.replace(/[\s/]/g, '');
|
|
85
304
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
fetch(form.action, {
|
|
94
|
-
method: 'POST',
|
|
95
|
-
body: formData,
|
|
96
|
-
}).then(async(res) => {
|
|
97
|
-
if (res.status < 200 || res.status >= 300) {
|
|
98
|
-
services.addError(`${res.status}: ${res.statusText}`);
|
|
99
|
-
debug.warn('Merchant session request failed.', {
|
|
100
|
-
status: res.status,
|
|
101
|
-
statusText: res.statusText,
|
|
102
|
-
});
|
|
103
|
-
resolve(false);
|
|
104
|
-
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
305
|
+
const merchantSessionKey = await requestMerchantSessionKey({
|
|
306
|
+
form,
|
|
307
|
+
handle,
|
|
308
|
+
sessionToken: provider.sessionToken || '',
|
|
309
|
+
services,
|
|
310
|
+
});
|
|
107
311
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
312
|
+
if (!merchantSessionKey) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
111
315
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
316
|
+
return new Promise<boolean>((resolve) => {
|
|
317
|
+
sagepayOwnForm({ merchantSessionKey }).tokeniseCardDetails({
|
|
318
|
+
cardDetails: {
|
|
319
|
+
cardholderName,
|
|
320
|
+
cardNumber,
|
|
321
|
+
expiryDate,
|
|
322
|
+
securityCode,
|
|
323
|
+
},
|
|
324
|
+
onTokenised: (result) => {
|
|
325
|
+
if (result.success && result.cardIdentifier) {
|
|
326
|
+
services.updateInputs('opayoTokenId', result.cardIdentifier);
|
|
327
|
+
services.updateInputs('opayoSessionKey', merchantSessionKey);
|
|
328
|
+
debug.log('Tokenization succeeded.', {
|
|
329
|
+
hasCardIdentifier: !!result.cardIdentifier,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
resolve(true);
|
|
333
|
+
} else {
|
|
334
|
+
services.addError(result.errors?.[0]?.message || 'Tokenization failed.');
|
|
335
|
+
debug.warn('Tokenization failed.', result);
|
|
115
336
|
resolve(false);
|
|
116
|
-
|
|
117
|
-
return;
|
|
118
337
|
}
|
|
119
|
-
|
|
120
|
-
sagepayOwnForm({ merchantSessionKey }).tokeniseCardDetails({
|
|
121
|
-
cardDetails: {
|
|
122
|
-
cardholderName,
|
|
123
|
-
cardNumber,
|
|
124
|
-
expiryDate,
|
|
125
|
-
securityCode,
|
|
126
|
-
},
|
|
127
|
-
onTokenised: (result) => {
|
|
128
|
-
if (result.success && result.cardIdentifier) {
|
|
129
|
-
services.updateInputs('opayoTokenId', result.cardIdentifier);
|
|
130
|
-
services.updateInputs('opayoSessionKey', merchantSessionKey);
|
|
131
|
-
debug.log('Tokenization succeeded.', {
|
|
132
|
-
hasCardIdentifier: !!result.cardIdentifier,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
resolve(true);
|
|
136
|
-
} else {
|
|
137
|
-
services.addError(result.errors?.[0]?.message || 'Tokenization failed.');
|
|
138
|
-
debug.warn('Tokenization failed.', result);
|
|
139
|
-
resolve(false);
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
} catch {
|
|
144
|
-
services.addError('Unable to parse merchant session response.');
|
|
145
|
-
debug.warn('Failed to parse merchant session response.');
|
|
146
|
-
resolve(false);
|
|
147
|
-
}
|
|
148
|
-
}).catch(() => {
|
|
149
|
-
services.addError('Network error. Please try again.');
|
|
150
|
-
debug.warn('Network error requesting merchant session.');
|
|
151
|
-
resolve(false);
|
|
338
|
+
},
|
|
152
339
|
});
|
|
153
340
|
});
|
|
154
341
|
},
|
|
@@ -64,6 +64,15 @@ function extractAuthIdFromAuthorization(result: Record<string, unknown> | null):
|
|
|
64
64
|
return authId.trim();
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
function hidePayPalButtons(widget: PayPalButtonsInstance | null, placeholder: HTMLElement): void {
|
|
68
|
+
if (widget?.close) {
|
|
69
|
+
widget.close();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
placeholder.removeAttribute('data-formie-paypal-rendered');
|
|
73
|
+
placeholder.innerHTML = '';
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
function getScriptUrl(clientId: string, currency: string): string {
|
|
68
77
|
const params = [
|
|
69
78
|
'intent=authorize',
|
|
@@ -137,6 +146,8 @@ export const paypalModule = definePaymentModule<PayPalProviderOptions, PayPalGlo
|
|
|
137
146
|
style.tagline = provider.buttonTagline ?? true;
|
|
138
147
|
}
|
|
139
148
|
|
|
149
|
+
let widget: PayPalButtonsInstance | null = null;
|
|
150
|
+
|
|
140
151
|
const paypalOptions: PayPalButtonsOptions = {
|
|
141
152
|
env: useSandbox ? 'sandbox' : 'production',
|
|
142
153
|
style,
|
|
@@ -183,6 +194,8 @@ export const paypalModule = definePaymentModule<PayPalProviderOptions, PayPalGlo
|
|
|
183
194
|
// Allow submit to continue using order ID fallback on the backend.
|
|
184
195
|
services.addSuccess('PayPal approval received. Finalizing payment on submit.');
|
|
185
196
|
}
|
|
197
|
+
|
|
198
|
+
hidePayPalButtons(widget, placeholder);
|
|
186
199
|
} catch {
|
|
187
200
|
services.addError('Unable to authorize payment. Please try again.');
|
|
188
201
|
}
|
|
@@ -191,9 +204,9 @@ export const paypalModule = definePaymentModule<PayPalProviderOptions, PayPalGlo
|
|
|
191
204
|
|
|
192
205
|
const buttons = api.Buttons(paypalOptions);
|
|
193
206
|
placeholder.setAttribute('data-formie-paypal-rendered', 'true');
|
|
194
|
-
|
|
207
|
+
widget = buttons.render(placeholder);
|
|
195
208
|
|
|
196
|
-
return
|
|
209
|
+
return widget;
|
|
197
210
|
},
|
|
198
211
|
unmount: async (args) => {
|
|
199
212
|
if (args.widget?.close) {
|
|
@@ -206,9 +219,16 @@ export const paypalModule = definePaymentModule<PayPalProviderOptions, PayPalGlo
|
|
|
206
219
|
placeholder.innerHTML = '';
|
|
207
220
|
}
|
|
208
221
|
},
|
|
209
|
-
onAfterSubmit: async ({ services }) => {
|
|
222
|
+
onAfterSubmit: async ({ services, result }) => {
|
|
210
223
|
services.updateInputs(['paypalOrderId', 'paypalAuthId'], '');
|
|
211
224
|
services.removeSuccess();
|
|
212
225
|
services.removeError();
|
|
226
|
+
|
|
227
|
+
// Restore buttons when auth was cleared but payment did not fully complete.
|
|
228
|
+
if (!result?.ok || result?.nextPage) {
|
|
229
|
+
return { remount: true };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {};
|
|
213
233
|
},
|
|
214
234
|
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { s as e } from "./event-names-BCI2FLD8.js";
|
|
2
|
-
import { t } from "./api-BYe9YPko.js";
|
|
3
|
-
import { t as n } from "./debug-BV0DvdHx.js";
|
|
4
|
-
import { r } from "./scripts-CbQ7agX3.js";
|
|
5
|
-
//#region src/js/modules/payments/opayo.ts
|
|
6
|
-
var i = "FORMIE_OPAYO_SCRIPT", a = "https://live.opayo.eu.elavon.com/api/v1/js/sagepay.js", o = "https://sandbox.opayo.eu.elavon.com/api/v1/js/sagepay.js", s = n("payments", "opayo"), c = e("opayo", "challenge"), l = "formie:payment:opayo:challenge:response", u = t({
|
|
7
|
-
id: "opayo",
|
|
8
|
-
defaultRequiredInputSuffixes: ["opayoTokenId"],
|
|
9
|
-
load: async (e) => {
|
|
10
|
-
let { provider: t } = e.options;
|
|
11
|
-
return await r("sagepayOwnForm", {
|
|
12
|
-
id: i,
|
|
13
|
-
src: t.useSandbox ? o : a,
|
|
14
|
-
timeoutMs: 1e4
|
|
15
|
-
}), null;
|
|
16
|
-
},
|
|
17
|
-
onBeforeAuthorize: async (e) => {
|
|
18
|
-
let { field: t, services: n, options: r } = e, i = r.provider, a = i.handle || "opayo", o = n.form;
|
|
19
|
-
if (!o?.action) return n.addError("Form action is missing."), s.warn("Missing form action before authorize."), !1;
|
|
20
|
-
let c = window.sagepayOwnForm;
|
|
21
|
-
if (!c) return n.addError("Opayo script failed to load."), s.warn("sagepayOwnForm global not available."), !1;
|
|
22
|
-
let l = t.querySelector("[data-opayo-card=\"cardholder-name\"]")?.value ?? "", u = t.querySelector("[data-opayo-card=\"card-number\"]")?.value ?? "", d = t.querySelector("[data-opayo-card=\"expiry-date\"]")?.value ?? "", f = t.querySelector("[data-opayo-card=\"security-code\"]")?.value ?? "";
|
|
23
|
-
return u = u.replace(/[\s/]/g, ""), d = d.replace(/[\s/]/g, ""), new Promise((e) => {
|
|
24
|
-
let t = new FormData();
|
|
25
|
-
t.append("action", "formie/payment-webhooks/process-callback"), t.append("merchantSessionKey", "true"), t.append("handle", a), t.append("sessionToken", i.sessionToken || ""), fetch(o.action, {
|
|
26
|
-
method: "POST",
|
|
27
|
-
body: t
|
|
28
|
-
}).then(async (t) => {
|
|
29
|
-
if (t.status < 200 || t.status >= 300) {
|
|
30
|
-
n.addError(`${t.status}: ${t.statusText}`), s.warn("Merchant session request failed.", {
|
|
31
|
-
status: t.status,
|
|
32
|
-
statusText: t.statusText
|
|
33
|
-
}), e(!1);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
let r = (await t.json()).merchantSessionKey;
|
|
38
|
-
if (!r) {
|
|
39
|
-
n.addError("Unable to get merchant session."), s.warn("merchantSessionKey missing in callback response."), e(!1);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
c({ merchantSessionKey: r }).tokeniseCardDetails({
|
|
43
|
-
cardDetails: {
|
|
44
|
-
cardholderName: l,
|
|
45
|
-
cardNumber: u,
|
|
46
|
-
expiryDate: d,
|
|
47
|
-
securityCode: f
|
|
48
|
-
},
|
|
49
|
-
onTokenised: (t) => {
|
|
50
|
-
t.success && t.cardIdentifier ? (n.updateInputs("opayoTokenId", t.cardIdentifier), n.updateInputs("opayoSessionKey", r), s.log("Tokenization succeeded.", { hasCardIdentifier: !!t.cardIdentifier }), e(!0)) : (n.addError(t.errors?.[0]?.message || "Tokenization failed."), s.warn("Tokenization failed.", t), e(!1));
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
} catch {
|
|
54
|
-
n.addError("Unable to parse merchant session response."), s.warn("Failed to parse merchant session response."), e(!1);
|
|
55
|
-
}
|
|
56
|
-
}).catch(() => {
|
|
57
|
-
n.addError("Network error. Please try again."), s.warn("Network error requesting merchant session."), e(!1);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
},
|
|
61
|
-
setup: async (e) => {
|
|
62
|
-
let { services: t } = e;
|
|
63
|
-
e.target;
|
|
64
|
-
let n = null, r = !1, i = () => {
|
|
65
|
-
n?.parentNode && n.parentNode.removeChild(n), n = null;
|
|
66
|
-
}, a = t.events.onForm(c, ((e) => {
|
|
67
|
-
let a = e.detail?.data;
|
|
68
|
-
if (!a?.acsUrl || !a?.creq) return;
|
|
69
|
-
r = !1, s.log("Received payment challenge event.", {
|
|
70
|
-
hasAcsUrl: !!a.acsUrl,
|
|
71
|
-
hasCreq: !!a.creq
|
|
72
|
-
});
|
|
73
|
-
let o = t.form?.querySelector("input[name*=\"opayoSessionKey\"]")?.value || "", c = document.createElement("div");
|
|
74
|
-
c.className = "formie-modal", c.id = `formie-opayo-dialog-${Math.random().toString(36).slice(2, 9)}`, c.innerHTML = "\n <div class=\"formie-modal-backdrop\" data-dialog-close></div>\n <div class=\"formie-modal-content\">\n <div class=\"formie-loading formie-loading-large\" style=\"--formie-loading-width: 3rem; --formie-loading-height: 3rem; top: 50%; margin-top: -1.5rem;\"></div>\n <iframe width=\"100%\" height=\"100%\" style=\"width: 100%; height: 100%; position: relative; z-index: 1;\"></iframe>\n </div>\n ";
|
|
75
|
-
let l = c.querySelector("iframe"), u = (e) => e.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<"), d = a.returnUrl || a.redirectUrl || "", f = `<form action="${u(a.acsUrl)}" method="post">
|
|
76
|
-
<input type="hidden" name="creq" value="${u(a.creq || "")}" />
|
|
77
|
-
<input type="hidden" name="threeDSSessionData" value="${u(a.threeDSSessionData || "")}" />
|
|
78
|
-
<input type="hidden" name="MD" value="${u(o)}" />
|
|
79
|
-
<input type="hidden" name="TermUrl" value="${u(d)}" />
|
|
80
|
-
<input type="hidden" name="ThreeDSNotificationURL" value="${u(d)}" />
|
|
81
|
-
</form><script>document.forms[0].submit();<\/script>`;
|
|
82
|
-
i(), document.body.appendChild(c), n = c, l?.contentWindow && (l.contentWindow.document.open(), l.contentWindow.document.write(f), l.contentWindow.document.close());
|
|
83
|
-
})), o = (e) => {
|
|
84
|
-
if (e.data?.message === l) {
|
|
85
|
-
if (!n) {
|
|
86
|
-
s.log("Ignoring 3DS response without active dialog.");
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (r) {
|
|
90
|
-
s.warn("Ignoring duplicate 3DS response while processing.");
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (r = !0, s.log("Received payment challenge response message.", e.data?.value), i(), t.removeError(), e.data?.value?.error) {
|
|
94
|
-
t.addError(e.data.value.error.message), t.releaseSubmitLoading(), r = !1;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
t.updateInputs("opayo3DSComplete", e.data.value?.transactionId ?? ""), t.triggerSubmit();
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
return window.addEventListener("message", o), { destroy: () => {
|
|
101
|
-
a(), window.removeEventListener("message", o), i(), r = !1;
|
|
102
|
-
} };
|
|
103
|
-
},
|
|
104
|
-
onAfterSubmit: async ({ services: e }) => {
|
|
105
|
-
e.updateInputs([
|
|
106
|
-
"opayoTokenId",
|
|
107
|
-
"opayoSessionKey",
|
|
108
|
-
"opayo3DSComplete"
|
|
109
|
-
], "");
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
//#endregion
|
|
113
|
-
export { u as opayoModule };
|