@churchapps/apphelper 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/donations/components/BankForm.js.map +1 -1
- package/dist/donations/components/CardForm.js.map +1 -1
- package/dist/donations/components/DonationForm.js.map +1 -1
- package/dist/donations/components/KingdomFundingNonAuthDonationInner.d.ts +13 -0
- package/dist/donations/components/KingdomFundingNonAuthDonationInner.d.ts.map +1 -0
- package/dist/donations/components/KingdomFundingNonAuthDonationInner.js +282 -0
- package/dist/donations/components/KingdomFundingNonAuthDonationInner.js.map +1 -0
- package/dist/donations/components/KingdomFundingTokenForm.d.ts +19 -0
- package/dist/donations/components/KingdomFundingTokenForm.d.ts.map +1 -0
- package/dist/donations/components/KingdomFundingTokenForm.js +147 -0
- package/dist/donations/components/KingdomFundingTokenForm.js.map +1 -0
- package/dist/donations/components/MultiGatewayDonationForm.d.ts.map +1 -1
- package/dist/donations/components/MultiGatewayDonationForm.js +104 -108
- package/dist/donations/components/MultiGatewayDonationForm.js.map +1 -1
- package/dist/donations/components/NonAuthDonation.d.ts.map +1 -1
- package/dist/donations/components/NonAuthDonation.js +16 -48
- package/dist/donations/components/NonAuthDonation.js.map +1 -1
- package/dist/donations/components/PaymentMethods.d.ts.map +1 -1
- package/dist/donations/components/PaymentMethods.js +97 -16
- package/dist/donations/components/PaymentMethods.js.map +1 -1
- package/dist/donations/components/RecurringDonations.d.ts.map +1 -1
- package/dist/donations/components/RecurringDonations.js +29 -6
- package/dist/donations/components/RecurringDonations.js.map +1 -1
- package/dist/donations/components/index.d.ts +3 -0
- package/dist/donations/components/index.d.ts.map +1 -1
- package/dist/donations/components/index.js +2 -0
- package/dist/donations/components/index.js.map +1 -1
- package/dist/donations/helpers/DonationHelper.d.ts +2 -2
- package/dist/donations/helpers/DonationHelper.d.ts.map +1 -1
- package/dist/donations/helpers/DonationHelper.js +1 -1
- package/dist/donations/helpers/DonationHelper.js.map +1 -1
- package/dist/donations/helpers/DonationInterface.d.ts +1 -1
- package/dist/donations/helpers/DonationInterface.d.ts.map +1 -1
- package/dist/donations/helpers/Locale.d.ts.map +1 -1
- package/dist/donations/helpers/Locale.js +24 -0
- package/dist/donations/helpers/Locale.js.map +1 -1
- package/dist/donations/helpers/PaymentMethod.d.ts +4 -2
- package/dist/donations/helpers/PaymentMethod.d.ts.map +1 -1
- package/dist/donations/helpers/StripePaymentMethod.d.ts +1 -1
- package/dist/donations/helpers/StripePaymentMethod.d.ts.map +1 -1
- package/dist/donations/index.d.ts +1 -0
- package/dist/donations/index.d.ts.map +1 -1
- package/dist/donations/index.js +1 -0
- package/dist/donations/index.js.map +1 -1
- package/dist/donations/modals/DonationPreviewModal.d.ts.map +1 -1
- package/dist/donations/modals/DonationPreviewModal.js +3 -1
- package/dist/donations/modals/DonationPreviewModal.js.map +1 -1
- package/dist/donations/providers/KingdomFundingProvider.d.ts +3 -0
- package/dist/donations/providers/KingdomFundingProvider.d.ts.map +1 -0
- package/dist/donations/providers/KingdomFundingProvider.js +86 -0
- package/dist/donations/providers/KingdomFundingProvider.js.map +1 -0
- package/dist/donations/providers/PayPalProvider.d.ts +3 -0
- package/dist/donations/providers/PayPalProvider.d.ts.map +1 -0
- package/dist/donations/providers/PayPalProvider.js +81 -0
- package/dist/donations/providers/PayPalProvider.js.map +1 -0
- package/dist/donations/providers/StripeProvider.d.ts +34 -0
- package/dist/donations/providers/StripeProvider.d.ts.map +1 -0
- package/dist/donations/providers/StripeProvider.js +74 -0
- package/dist/donations/providers/StripeProvider.js.map +1 -0
- package/dist/donations/providers/index.d.ts +3 -0
- package/dist/donations/providers/index.d.ts.map +1 -0
- package/dist/donations/providers/index.js +6 -0
- package/dist/donations/providers/index.js.map +1 -0
- package/dist/donations/providers/registry.d.ts +6 -0
- package/dist/donations/providers/registry.d.ts.map +1 -0
- package/dist/donations/providers/registry.js +36 -0
- package/dist/donations/providers/registry.js.map +1 -0
- package/dist/donations/providers/types.d.ts +113 -0
- package/dist/donations/providers/types.d.ts.map +1 -0
- package/dist/donations/providers/types.js +2 -0
- package/dist/donations/providers/types.js.map +1 -0
- package/dist/public/locales/en.json +24 -0
- package/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState, useCallback, forwardRef, useImperativeHandle } from "react";
|
|
4
|
+
import { Box, CircularProgress, Typography } from "@mui/material";
|
|
5
|
+
import { Locale } from "../helpers";
|
|
6
|
+
// CSS strings for each CardFormStyles field to match MUI outlined TextField
|
|
7
|
+
// accept.blue labelType options: "floating" | "static-left" | "static-top" | "hidden"
|
|
8
|
+
const inputBase = "font-family: 'Roboto','Helvetica','Arial',sans-serif; font-size: 1rem; color: rgba(0,0,0,0.87); border: 1px solid rgba(0,0,0,0.23); border-radius: 4px; padding: 16.5px 14px; background: #fff; outline: none; box-sizing: border-box; transition: border-color 200ms cubic-bezier(0.0,0,0.2,1);";
|
|
9
|
+
const tokenFormStyles = {
|
|
10
|
+
container: "display: flex; flex-wrap: wrap; gap: 12px; width: 100%; align-items: flex-end;",
|
|
11
|
+
card: inputBase + " flex: 1 0 100%; width: 100%;",
|
|
12
|
+
expiryContainer: "display: flex; align-items: flex-end; gap: 4px;",
|
|
13
|
+
expiryMonth: inputBase + " width: 64px; text-align: center;",
|
|
14
|
+
expirySeparator: "font-size: 1.25rem; color: rgba(0,0,0,0.4); padding: 16.5px 0; line-height: 1;",
|
|
15
|
+
expiryYear: inputBase + " width: 64px; text-align: center;",
|
|
16
|
+
cvv2: inputBase + " width: 90px;",
|
|
17
|
+
labels: "font-family: 'Roboto','Helvetica','Arial',sans-serif; font-size: 0.75rem; color: rgba(0,0,0,0.6);",
|
|
18
|
+
labelType: "floating"
|
|
19
|
+
};
|
|
20
|
+
export const KingdomFundingTokenForm = forwardRef(({ tokenizationKey, sandbox = false }, ref) => {
|
|
21
|
+
const containerRef = useRef(null);
|
|
22
|
+
const hostedTokenizationRef = useRef(null);
|
|
23
|
+
const [loading, setLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
const initCalledRef = useRef(false);
|
|
26
|
+
const destroyTokenization = useCallback(() => {
|
|
27
|
+
if (hostedTokenizationRef.current) {
|
|
28
|
+
try {
|
|
29
|
+
// destroy() returns a Promise that often rejects with undefined when the
|
|
30
|
+
// iframe was never fully initialized (e.g. unmount during loading).
|
|
31
|
+
// Swallow both sync throws and the async rejection so it doesn't surface
|
|
32
|
+
// as an Unhandled Promise Rejection in the console.
|
|
33
|
+
const result = hostedTokenizationRef.current.destroy();
|
|
34
|
+
if (result && typeof result.catch === "function") {
|
|
35
|
+
result.catch(() => { });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (_e) { /* ignore */ }
|
|
39
|
+
hostedTokenizationRef.current = null;
|
|
40
|
+
}
|
|
41
|
+
// Clear any leftover iframes in the container
|
|
42
|
+
if (containerRef.current) {
|
|
43
|
+
containerRef.current.innerHTML = "";
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const initTokenization = useCallback(() => {
|
|
47
|
+
if (initCalledRef.current)
|
|
48
|
+
return;
|
|
49
|
+
try {
|
|
50
|
+
const HostedTokenization = window.HostedTokenization;
|
|
51
|
+
if (!HostedTokenization) {
|
|
52
|
+
setError(Locale.label("donation.kingdomFunding.paymentFormNotAvailable"));
|
|
53
|
+
setLoading(false);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Clean up any previous instance first
|
|
57
|
+
destroyTokenization();
|
|
58
|
+
const containerId = "kf-token-container";
|
|
59
|
+
if (containerRef.current) {
|
|
60
|
+
containerRef.current.id = containerId;
|
|
61
|
+
}
|
|
62
|
+
initCalledRef.current = true;
|
|
63
|
+
hostedTokenizationRef.current = new HostedTokenization(tokenizationKey, {
|
|
64
|
+
target: `#${containerId}`,
|
|
65
|
+
styles: tokenFormStyles
|
|
66
|
+
});
|
|
67
|
+
setLoading(false);
|
|
68
|
+
}
|
|
69
|
+
catch (_e) {
|
|
70
|
+
setError(Locale.label("donation.kingdomFunding.failedToInitPaymentForm"));
|
|
71
|
+
setLoading(false);
|
|
72
|
+
}
|
|
73
|
+
}, [tokenizationKey, destroyTokenization]);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
initCalledRef.current = false;
|
|
76
|
+
if (!tokenizationKey) {
|
|
77
|
+
setError(Locale.label("donation.kingdomFunding.missingTokenizationKey"));
|
|
78
|
+
setLoading(false);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const scriptUrl = sandbox
|
|
82
|
+
? "https://tokenization.sandbox.accept.blue/tokenization/v0.3"
|
|
83
|
+
: "https://tokenization.accept.blue/tokenization/v0.3";
|
|
84
|
+
// Check if script already loaded
|
|
85
|
+
if (window.HostedTokenization) {
|
|
86
|
+
initTokenization();
|
|
87
|
+
return () => { destroyTokenization(); initCalledRef.current = false; };
|
|
88
|
+
}
|
|
89
|
+
const existingScript = document.querySelector(`script[src="${scriptUrl}"]`);
|
|
90
|
+
if (existingScript) {
|
|
91
|
+
const onLoad = () => { initTokenization(); };
|
|
92
|
+
if (window.HostedTokenization) {
|
|
93
|
+
initTokenization();
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
existingScript.addEventListener("load", onLoad);
|
|
97
|
+
}
|
|
98
|
+
return () => {
|
|
99
|
+
existingScript.removeEventListener("load", onLoad);
|
|
100
|
+
destroyTokenization();
|
|
101
|
+
initCalledRef.current = false;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const script = document.createElement("script");
|
|
105
|
+
script.src = scriptUrl;
|
|
106
|
+
script.async = true;
|
|
107
|
+
script.onload = () => { initTokenization(); };
|
|
108
|
+
script.onerror = () => {
|
|
109
|
+
setError(Locale.label("donation.kingdomFunding.failedToLoadPaymentForm"));
|
|
110
|
+
setLoading(false);
|
|
111
|
+
};
|
|
112
|
+
document.head.appendChild(script);
|
|
113
|
+
return () => {
|
|
114
|
+
destroyTokenization();
|
|
115
|
+
initCalledRef.current = false;
|
|
116
|
+
};
|
|
117
|
+
}, [tokenizationKey, sandbox, initTokenization, destroyTokenization]);
|
|
118
|
+
useImperativeHandle(ref, () => ({
|
|
119
|
+
getNonce: async () => {
|
|
120
|
+
if (!hostedTokenizationRef.current) {
|
|
121
|
+
throw new Error(Locale.label("donation.kingdomFunding.paymentFormNotInitialized"));
|
|
122
|
+
}
|
|
123
|
+
const result = await hostedTokenizationRef.current.getNonceToken();
|
|
124
|
+
if (!result?.nonce) {
|
|
125
|
+
throw new Error(result?.error || Locale.label("donation.kingdomFunding.failedToTokenizeCard"));
|
|
126
|
+
}
|
|
127
|
+
// Normalize expiry year to 4-digit (accept.blue API requires 2020-9999)
|
|
128
|
+
let expYear = result.expiryYear ? Number(result.expiryYear) : 0;
|
|
129
|
+
if (expYear > 0 && expYear < 100)
|
|
130
|
+
expYear += 2000;
|
|
131
|
+
return {
|
|
132
|
+
nonce: result.nonce,
|
|
133
|
+
last4: result.last4 || "",
|
|
134
|
+
cardType: result.cardType || "",
|
|
135
|
+
expiryMonth: result.expiryMonth ? String(result.expiryMonth) : "",
|
|
136
|
+
expiryYear: expYear ? String(expYear) : "",
|
|
137
|
+
maskedCard: result.maskedCard || ""
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
if (error) {
|
|
142
|
+
return _jsx(Typography, { color: "error", sx: { py: 2 }, children: error });
|
|
143
|
+
}
|
|
144
|
+
return (_jsxs(Box, { children: [loading && (_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1, py: 2 }, children: [_jsx(CircularProgress, { size: 20 }), _jsx(Typography, { variant: "body2", children: Locale.label("donation.kingdomFunding.loadingPaymentForm") })] })), _jsx("div", { ref: containerRef, style: { minHeight: loading ? 0 : undefined } })] }));
|
|
145
|
+
});
|
|
146
|
+
KingdomFundingTokenForm.displayName = "KingdomFundingTokenForm";
|
|
147
|
+
//# sourceMappingURL=KingdomFundingTokenForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KingdomFundingTokenForm.js","sourceRoot":"","sources":["../../../src/donations/components/KingdomFundingTokenForm.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiGatewayDonationForm.d.ts","sourceRoot":"","sources":["../../../src/donations/components/MultiGatewayDonationForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"MultiGatewayDonationForm.d.ts","sourceRoot":"","sources":["../../../src/donations/components/MultiGatewayDonationForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAOhD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAiC,MAAM,YAAY,CAAC;AAG/F,OAAO,EAAE,eAAe,EAAwC,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAkB7G,UAAU,KAAK;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAijBD,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAKpD,CAAC"}
|
|
@@ -4,14 +4,16 @@ import { useCallback, useState, useEffect, useMemo, useRef } from "react";
|
|
|
4
4
|
import { useStripe } from "@stripe/react-stripe-js";
|
|
5
5
|
import { InputBox, ErrorMessages } from "../..";
|
|
6
6
|
import { FundDonations } from ".";
|
|
7
|
-
import { PayPalHostedFields } from "./PayPalHostedFields";
|
|
8
7
|
import { DonationPreviewModal } from "../modals/DonationPreviewModal";
|
|
9
8
|
import { ApiHelper, CurrencyHelper, DateHelper } from "@churchapps/helpers";
|
|
10
9
|
import { Locale, DonationHelper } from "../helpers";
|
|
11
|
-
import {
|
|
12
|
-
|
|
10
|
+
import { getPaymentProvider } from "../providers";
|
|
11
|
+
import { Grid, Icon, InputLabel, MenuItem, Select, TextField, FormControl, Button, FormControlLabel, Checkbox, FormGroup, Typography, Alert } from "@mui/material";
|
|
12
|
+
const MultiGatewayDonationInner = (props) => {
|
|
13
13
|
const stripe = useStripe();
|
|
14
14
|
const [errorMessage, setErrorMessage] = useState();
|
|
15
|
+
const [saveCard, setSaveCard] = useState(false);
|
|
16
|
+
const [useNewCard, setUseNewCard] = useState(false);
|
|
15
17
|
const [fundDonations, setFundDonations] = useState();
|
|
16
18
|
const [funds, setFunds] = useState([]);
|
|
17
19
|
const [fundsLoaded, setFundsLoaded] = useState(false);
|
|
@@ -19,8 +21,9 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
19
21
|
const [transactionFee, setTransactionFee] = useState(0);
|
|
20
22
|
const [payFee, setPayFee] = useState(0);
|
|
21
23
|
const [total, setTotal] = useState(0);
|
|
22
|
-
const [paymentMethodName, setPaymentMethodName] = useState(props?.paymentMethods?.length > 0 ? `${props.paymentMethods[0].name} ${props.paymentMethods[0].last4 ? `****${props.paymentMethods[0].last4}` : props.paymentMethods[0].email ||
|
|
23
|
-
const [selectedGateway
|
|
24
|
+
const [paymentMethodName, setPaymentMethodName] = useState(props?.paymentMethods?.length > 0 ? `${props.paymentMethods[0].name} ${props.paymentMethods[0].last4 ? `****${props.paymentMethods[0].last4}` : props.paymentMethods[0].email || ""}` : "");
|
|
25
|
+
const [selectedGateway] = useState(DonationHelper.normalizeProvider(props?.paymentGateways?.find(g => g.enabled !== false)?.provider || "stripe"));
|
|
26
|
+
const paymentProvider = useMemo(() => getPaymentProvider(selectedGateway), [selectedGateway]);
|
|
24
27
|
const selectedGatewayObj = useMemo(() => {
|
|
25
28
|
return (props.paymentGateways.find((g) => DonationHelper.normalizeProvider(g.provider) === selectedGateway) || null);
|
|
26
29
|
}, [props.paymentGateways, selectedGateway]);
|
|
@@ -28,11 +31,7 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
28
31
|
const [showDonationPreviewModal, setShowDonationPreviewModal] = useState(false);
|
|
29
32
|
const [interval, setInterval] = useState("one_month");
|
|
30
33
|
const [gateway, setGateway] = useState(selectedGatewayObj);
|
|
31
|
-
const
|
|
32
|
-
const gw = props.paymentGateways.find(g => DonationHelper.isProvider(g.provider, "paypal"));
|
|
33
|
-
return gw?.publicKey || "";
|
|
34
|
-
}, [props.paymentGateways]);
|
|
35
|
-
const hostedRef = useRef(null);
|
|
34
|
+
const entryRef = useRef(null);
|
|
36
35
|
const feeTimeoutRef = useRef(null);
|
|
37
36
|
const [donation, setDonation] = useState({
|
|
38
37
|
id: props?.paymentMethods?.length > 0 ? props.paymentMethods[0].id : "",
|
|
@@ -110,35 +109,17 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
110
109
|
const d = { ...donation };
|
|
111
110
|
const value = e.target.value;
|
|
112
111
|
switch (e.target.name) {
|
|
113
|
-
case "
|
|
114
|
-
setSelectedGateway(value);
|
|
115
|
-
d.provider = value;
|
|
116
|
-
const matchedGateway = props.paymentGateways.find(g => DonationHelper.normalizeProvider(g.provider) === value);
|
|
117
|
-
d.gatewayId = matchedGateway?.id;
|
|
118
|
-
d.currency = matchedGateway?.currency || "usd";
|
|
119
|
-
// Reset payment method when changing gateways
|
|
120
|
-
const availableMethods = props.paymentMethods.filter(pm => DonationHelper.normalizeProvider(pm.provider) === value);
|
|
121
|
-
if (availableMethods.length > 0) {
|
|
122
|
-
d.id = availableMethods[0].id;
|
|
123
|
-
d.type = availableMethods[0].type;
|
|
124
|
-
setPaymentMethodName(`${availableMethods[0].name} ${availableMethods[0].last4 ? `****${availableMethods[0].last4}` : availableMethods[0].email || ''}`);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
d.id = "";
|
|
128
|
-
if (value === "paypal")
|
|
129
|
-
d.type = "paypal";
|
|
130
|
-
}
|
|
131
|
-
break;
|
|
132
|
-
case "method":
|
|
112
|
+
case "method": {
|
|
133
113
|
d.id = value;
|
|
134
114
|
const pm = props.paymentMethods.find(pm => pm.id === value);
|
|
135
115
|
if (pm) {
|
|
136
116
|
d.type = pm.type;
|
|
137
117
|
d.provider = DonationHelper.normalizeProvider(pm.provider);
|
|
138
118
|
d.gatewayId = pm.gatewayId || gateway?.id || selectedGatewayObj?.id;
|
|
139
|
-
setPaymentMethodName(`${pm.name} ${pm.last4 ? `****${pm.last4}` : pm.email ||
|
|
119
|
+
setPaymentMethodName(`${pm.name} ${pm.last4 ? `****${pm.last4}` : pm.email || ""}`);
|
|
140
120
|
}
|
|
141
121
|
break;
|
|
122
|
+
}
|
|
142
123
|
case "type":
|
|
143
124
|
setDonationType(value);
|
|
144
125
|
break;
|
|
@@ -152,15 +133,16 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
152
133
|
case "notes":
|
|
153
134
|
d.notes = value;
|
|
154
135
|
break;
|
|
155
|
-
case "transaction-fee":
|
|
136
|
+
case "transaction-fee": {
|
|
156
137
|
const element = e.target;
|
|
157
138
|
d.amount = element.checked ? fundsTotal + transactionFee : fundsTotal;
|
|
158
139
|
const showFee = element.checked ? transactionFee : 0;
|
|
159
140
|
setTotal(d.amount);
|
|
160
141
|
setPayFee(showFee);
|
|
142
|
+
}
|
|
161
143
|
}
|
|
162
144
|
setDonation(d);
|
|
163
|
-
}, [donation, props.paymentMethods, fundsTotal, transactionFee, gateway?.id,
|
|
145
|
+
}, [donation, props.paymentMethods, fundsTotal, transactionFee, gateway?.id, selectedGatewayObj?.id]);
|
|
164
146
|
const handleCancel = useCallback(() => { setDonationType(undefined); }, []);
|
|
165
147
|
const handleDonationSelect = useCallback((type) => {
|
|
166
148
|
const dt = donationType === type ? undefined : type;
|
|
@@ -168,67 +150,79 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
168
150
|
}, [donationType]);
|
|
169
151
|
const handleSingleDonationClick = useCallback(() => handleDonationSelect("once"), [handleDonationSelect]);
|
|
170
152
|
const handleRecurringDonationClick = useCallback(() => handleDonationSelect("recurring"), [handleDonationSelect]);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
153
|
+
// Snapshot of the gift in flight, in the shape every provider adapter expects.
|
|
154
|
+
const buildContext = useCallback(() => ({
|
|
155
|
+
provider: selectedGateway,
|
|
156
|
+
gatewayId: donation.gatewayId || gateway?.id || selectedGatewayObj?.id,
|
|
157
|
+
churchId: props?.church?.id || "",
|
|
158
|
+
amount: total,
|
|
159
|
+
funds: (donation.funds || []).map((f) => ({ id: f.id, amount: f.amount })),
|
|
160
|
+
person: {
|
|
161
|
+
id: donation.person?.id || "",
|
|
162
|
+
email: donation.person?.email || "",
|
|
163
|
+
name: donation.person?.name || ""
|
|
164
|
+
},
|
|
165
|
+
notes: donation?.notes || "",
|
|
166
|
+
church: {
|
|
174
167
|
name: props?.church?.name || "",
|
|
175
168
|
subDomain: props?.church?.subDomain || "",
|
|
176
169
|
churchURL: typeof window !== "undefined" ? window.location.origin : "",
|
|
177
170
|
logo: props?.churchLogo || ""
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
171
|
+
},
|
|
172
|
+
recurring: donationType === "recurring",
|
|
173
|
+
interval: donation.interval,
|
|
174
|
+
billingCycleAnchor: donation.billing_cycle_anchor,
|
|
175
|
+
saveCard,
|
|
176
|
+
customerId: props.customerId,
|
|
177
|
+
currency: donation.currency
|
|
178
|
+
}), [
|
|
179
|
+
donation, total, donationType, saveCard, selectedGateway, gateway?.id, selectedGatewayObj?.id, props.church?.id, props.church?.name, props.church?.subDomain, props.churchLogo, props.customerId
|
|
180
|
+
]);
|
|
181
|
+
const makeDonation = useCallback(async (message) => {
|
|
182
|
+
const ctx = buildContext();
|
|
183
|
+
// Capture a new payment if the provider needs one (no saved-card support, or
|
|
184
|
+
// the user is entering a fresh card); otherwise charge the chosen saved method.
|
|
185
|
+
const needsToken = !!paymentProvider.MemberEntry
|
|
186
|
+
&& (!paymentProvider.capabilities.savedCard || useNewCard || !donation.id || donation.id === "");
|
|
187
|
+
let token;
|
|
188
|
+
if (needsToken) {
|
|
181
189
|
try {
|
|
182
|
-
|
|
183
|
-
const orderId = payload?.orderId || payload?.id || "";
|
|
184
|
-
if (orderId) {
|
|
185
|
-
// Capture and persist via unified /donate/charge endpoint for PayPal
|
|
186
|
-
const compactFunds = (donation.funds || []).map((f) => ({ id: f.id, amount: f.amount }));
|
|
187
|
-
results = await ApiHelper.post("/donate/charge", {
|
|
188
|
-
provider: "paypal",
|
|
189
|
-
gatewayId: selectedGatewayObj?.id,
|
|
190
|
-
id: orderId,
|
|
191
|
-
churchId: props?.church?.id || "",
|
|
192
|
-
amount: total,
|
|
193
|
-
funds: compactFunds,
|
|
194
|
-
person: donation.person,
|
|
195
|
-
notes: donation?.notes || ""
|
|
196
|
-
}, "GivingApi");
|
|
197
|
-
}
|
|
190
|
+
token = await entryRef.current.tokenize();
|
|
198
191
|
}
|
|
199
192
|
catch (e) {
|
|
200
|
-
|
|
193
|
+
setShowDonationPreviewModal(false);
|
|
194
|
+
setErrorMessage("Failed to process payment: " + (e.message || "Unknown error"));
|
|
195
|
+
return;
|
|
201
196
|
}
|
|
202
197
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
results = await ApiHelper.post("/donate/subscribe", payload, "GivingApi");
|
|
198
|
+
else {
|
|
199
|
+
token = { id: donation.id, type: donation.type, saved: true };
|
|
200
|
+
}
|
|
201
|
+
const { endpoint, body } = paymentProvider.buildChargeRequest(ctx, token);
|
|
202
|
+
let results = await ApiHelper.post(endpoint, body, "GivingApi");
|
|
203
|
+
// Terminal: a freshly-tokenized payment must never silently retry on a falsy
|
|
204
|
+
// response, or we'd double-charge.
|
|
205
|
+
if (needsToken && !results) {
|
|
206
|
+
setShowDonationPreviewModal(false);
|
|
207
|
+
setErrorMessage(Locale.label("donation.kingdomFunding.unexpectedError"));
|
|
208
|
+
return;
|
|
215
209
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (threeDSResult.requiresAction) {
|
|
210
|
+
if (paymentProvider.finalizeResult) {
|
|
211
|
+
const fin = await paymentProvider.finalizeResult(results, { stripe });
|
|
212
|
+
if (fin.requiresAction) {
|
|
220
213
|
setShowDonationPreviewModal(false);
|
|
221
|
-
if (
|
|
214
|
+
if (fin.success) {
|
|
222
215
|
setDonationType(undefined);
|
|
223
216
|
props.donationSuccess(message);
|
|
224
217
|
}
|
|
225
218
|
else {
|
|
226
|
-
setErrorMessage(Locale.label("donation.common.error") + ": " +
|
|
219
|
+
setErrorMessage(Locale.label("donation.common.error") + ": " + fin.error);
|
|
227
220
|
}
|
|
228
221
|
return;
|
|
229
222
|
}
|
|
223
|
+
results = fin.result;
|
|
230
224
|
}
|
|
231
|
-
if (results?.status === "succeeded" || results?.status === "pending" || results?.status === "active" || results?.status === "processing" || results?.status === "CREATED") {
|
|
225
|
+
if (results?.status === "succeeded" || results?.status === "pending" || results?.status === "active" || results?.status === "processing" || results?.status === "CREATED" || results?.status === "Approved") {
|
|
232
226
|
setShowDonationPreviewModal(false);
|
|
233
227
|
setDonationType(undefined);
|
|
234
228
|
props.donationSuccess(message);
|
|
@@ -237,7 +231,7 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
237
231
|
setShowDonationPreviewModal(false);
|
|
238
232
|
setErrorMessage(Locale.label("donation.common.error") + ": " + (results?.raw?.message || results?.message));
|
|
239
233
|
}
|
|
240
|
-
}, [
|
|
234
|
+
}, [buildContext, paymentProvider, donation.id, donation.type, useNewCard, stripe, props.donationSuccess]);
|
|
241
235
|
const getTransactionFee = useCallback(async (amount, activeGatewayId, provider = "stripe", paymentMethodType) => {
|
|
242
236
|
if (amount > 0) {
|
|
243
237
|
try {
|
|
@@ -322,7 +316,10 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
322
316
|
};
|
|
323
317
|
}, []);
|
|
324
318
|
const availablePaymentMethods = props.paymentMethods.filter(pm => DonationHelper.normalizeProvider(pm.provider) === selectedGateway);
|
|
325
|
-
|
|
319
|
+
// Show the provider's inline entry widget when there's no saved method to use:
|
|
320
|
+
// PayPal (no vault) always; Kingdom Funding when adding a new card or none saved.
|
|
321
|
+
const showInlineEntry = !!paymentProvider.MemberEntry
|
|
322
|
+
&& (!paymentProvider.capabilities.savedCard || useNewCard || availablePaymentMethods.length === 0);
|
|
326
323
|
if (!fundsLoaded) {
|
|
327
324
|
return _jsx(Alert, { severity: "info", children: "Loading donation settings\u2026" });
|
|
328
325
|
}
|
|
@@ -330,6 +327,7 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
330
327
|
return (_jsx(Alert, { severity: "warning", children: "No donation funds have been configured for this church. Please contact your administrator." }));
|
|
331
328
|
}
|
|
332
329
|
else {
|
|
330
|
+
const MemberEntry = paymentProvider.MemberEntry;
|
|
333
331
|
return (_jsxs(_Fragment, { children: [_jsx(DonationPreviewModal, { show: showDonationPreviewModal, onHide: () => setShowDonationPreviewModal(false), handleDonate: makeDonation, donation: {
|
|
334
332
|
...donation,
|
|
335
333
|
person: {
|
|
@@ -337,39 +335,37 @@ export const MultiGatewayDonationForm = (props) => {
|
|
|
337
335
|
email: donation.person?.email || "",
|
|
338
336
|
name: donation.person?.name || ""
|
|
339
337
|
}
|
|
340
|
-
}, donationType: donationType || "", payFee: payFee, paymentMethodName: paymentMethodName, funds: funds }), _jsxs(InputBox, { id: "donation-form", "aria-label": "donation-box", headerIcon: "volunteer_activism", headerText: Locale.label("donation.donationForm.donate"), ariaLabelSave: "save-button", cancelFunction: donationType ? handleCancel : undefined, saveFunction: donationType ? handleSave : undefined, saveText: Locale.label("donation.donationForm.preview"), children: [_jsxs(Grid, { id: "donation-type-selector", container: true, spacing: 3, children: [_jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsx(Button, { id: "single-donation-button", "aria-label": "single-donation", size: "small", fullWidth: true, style: { minHeight: "50px" }, variant: donationType === "once" ? "contained" : "outlined", onClick: handleSingleDonationClick, children: Locale.label("donation.donationForm.make") }) }), _jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsx(Button, { id: "recurring-donation-button", "aria-label": "recurring-donation", size: "small", fullWidth: true, style: { minHeight: "50px" }, variant: donationType === "recurring" ? "contained" : "outlined", onClick: handleRecurringDonationClick, children: Locale.label("donation.donationForm.makeRecurring") }) })] }), donationType && (_jsxs("div", { id: "donation-details", style: { marginTop: "20px" }, children: [
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const token = resp?.clientToken || resp?.token || resp?.result || resp;
|
|
348
|
-
return typeof token === "string" && token.length > 0 ? token : "";
|
|
349
|
-
}
|
|
350
|
-
catch {
|
|
351
|
-
return "";
|
|
338
|
+
}, donationType: donationType || "", payFee: payFee, paymentMethodName: paymentMethodName, funds: funds }), _jsxs(InputBox, { id: "donation-form", "aria-label": "donation-box", headerIcon: "volunteer_activism", headerText: Locale.label("donation.donationForm.donate"), ariaLabelSave: "save-button", cancelFunction: donationType ? handleCancel : undefined, saveFunction: donationType ? handleSave : undefined, saveText: Locale.label("donation.donationForm.preview"), children: [_jsxs(Grid, { id: "donation-type-selector", container: true, spacing: 3, children: [_jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsx(Button, { id: "single-donation-button", "aria-label": "single-donation", size: "small", fullWidth: true, style: { minHeight: "50px" }, variant: donationType === "once" ? "contained" : "outlined", onClick: handleSingleDonationClick, children: Locale.label("donation.donationForm.make") }) }), _jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsx(Button, { id: "recurring-donation-button", "aria-label": "recurring-donation", size: "small", fullWidth: true, style: { minHeight: "50px" }, variant: donationType === "recurring" ? "contained" : "outlined", onClick: handleRecurringDonationClick, children: Locale.label("donation.donationForm.makeRecurring") }) })] }), donationType && (_jsxs("div", { id: "donation-details", style: { marginTop: "20px" }, children: [_jsx(Grid, { container: true, spacing: 3, children: !showInlineEntry ? (_jsx(Grid, { size: { xs: 12 }, children: _jsxs(FormControl, { fullWidth: true, children: [_jsx(InputLabel, { children: Locale.label("donation.donationForm.method") }), _jsxs(Select, { id: "payment-method-select", label: Locale.label("donation.donationForm.method"), name: "method", "aria-label": "method", value: donation.id, className: "capitalize", onChange: (e) => {
|
|
339
|
+
if (e.target.value === "__new__") {
|
|
340
|
+
setUseNewCard(true);
|
|
341
|
+
setPaymentMethodName("New card");
|
|
342
|
+
const d = { ...donation };
|
|
343
|
+
d.id = "";
|
|
344
|
+
setDonation(d);
|
|
352
345
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
churchId: props?.church?.id || "",
|
|
360
|
-
provider: "paypal",
|
|
361
|
-
gatewayId: selectedGatewayObj?.id || gateway?.id,
|
|
362
|
-
amount: total,
|
|
363
|
-
currency: (selectedGatewayObj?.currency || gateway?.currency || "USD").toUpperCase(),
|
|
364
|
-
funds: fundsPayload,
|
|
365
|
-
notes: donation?.notes || ""
|
|
366
|
-
}, "GivingApi");
|
|
367
|
-
return response?.id || response?.orderId || "";
|
|
346
|
+
else {
|
|
347
|
+
// Switching back to a saved card after picking "Enter new card"
|
|
348
|
+
// must clear useNewCard, otherwise the submit handler still
|
|
349
|
+
// tries to tokenize a card the iframe never collected.
|
|
350
|
+
setUseNewCard(false);
|
|
351
|
+
handleChange(e);
|
|
368
352
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
|
|
353
|
+
}, children: [availablePaymentMethods.map((paymentMethod) => (_jsxs(MenuItem, { value: paymentMethod.id, children: [paymentMethod.name, " ", paymentMethod.last4 ? `****${paymentMethod.last4}` : paymentMethod.email || ""] }, paymentMethod.id))), paymentProvider.capabilities.memberNewCard && (_jsxs(MenuItem, { value: "__new__", children: [_jsx(Icon, { sx: { mr: 1, fontSize: 18 }, children: "add_circle" }), " Enter new card"] }))] })] }) })) : (_jsx(Grid, { size: { xs: 12 }, children: selectedGatewayObj?.publicKey && MemberEntry ? (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "subtitle1", sx: { mb: 1 }, children: Locale.label("donation.kingdomFunding.enterCardDetails") }), _jsx(MemberEntry, { ref: entryRef, gateway: selectedGatewayObj, getContext: buildContext }), paymentProvider.capabilities.savedCard && props.person?.id && (_jsx(FormGroup, { sx: { mt: 1 }, children: _jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: saveCard, onChange: (e) => setSaveCard(e.target.checked) }), label: "Save this card for future donations" }) })), paymentProvider.capabilities.savedCard && availablePaymentMethods.length > 0 && (_jsx(Button, { size: "small", sx: { mt: 1 }, onClick: () => {
|
|
354
|
+
setUseNewCard(false);
|
|
355
|
+
const d = { ...donation };
|
|
356
|
+
d.id = availablePaymentMethods[0].id;
|
|
357
|
+
d.type = availablePaymentMethods[0].type;
|
|
358
|
+
setDonation(d);
|
|
359
|
+
setPaymentMethodName(`${availablePaymentMethods[0].name} ${availablePaymentMethods[0].last4 ? `****${availablePaymentMethods[0].last4}` : ""}`);
|
|
360
|
+
}, children: "Use a saved payment method instead" }))] })) : (_jsx(Alert, { severity: "warning", children: Locale.label("donation.kingdomFunding.gatewayConfigMissing") })) })) }), donationType === "recurring" && (_jsxs(Grid, { container: true, spacing: 3, style: { marginTop: 10 }, children: [_jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsx(TextField, { id: "start-date-field", fullWidth: true, name: "date", type: "date", "aria-label": "date", label: Locale.label("donation.donationForm.startDate"), value: DateHelper.formatHtml5Date(new Date(donation.billing_cycle_anchor || Date.now())), onChange: handleChange, onKeyDown: handleKeyDown }) }), _jsx(Grid, { size: { xs: 12, md: 6 }, children: _jsxs(FormControl, { fullWidth: true, children: [_jsx(InputLabel, { children: Locale.label("donation.donationForm.frequency") }), _jsxs(Select, { id: "frequency-select", label: Locale.label("donation.donationForm.frequency"), name: "interval", "aria-label": "interval", value: interval, onChange: handleChange, children: [_jsx(MenuItem, { value: "one_week", children: Locale.label("donation.donationForm.weekly") }), _jsx(MenuItem, { value: "two_week", children: Locale.label("donation.donationForm.biWeekly") }), _jsx(MenuItem, { value: "one_month", children: Locale.label("donation.donationForm.monthly") }), _jsx(MenuItem, { value: "three_month", children: Locale.label("donation.donationForm.quarterly") }), _jsx(MenuItem, { value: "one_year", children: Locale.label("donation.donationForm.annually") })] })] }) })] })), _jsxs("div", { id: "fund-selection", className: "form-group", children: [funds && fundDonations && (_jsxs(_Fragment, { children: [_jsx("h4", { children: Locale.label("donation.donationForm.fund") }), _jsx(FundDonations, { fundDonations: fundDonations, funds: funds, updatedFunction: handleFundDonationsChange, currency: gateway?.currency })] })), fundsTotal > 0 && (_jsxs(_Fragment, { children: [(gateway?.payFees === true) ? (_jsxs(Typography, { fontSize: 14, fontStyle: "italic", children: ["*", Locale.label("donation.donationForm.fees").replace("{}", CurrencyHelper.formatCurrencyWithLocale(transactionFee, gateway?.currency || "USD"))] })) : (_jsx(FormGroup, { children: _jsx(FormControlLabel, { control: _jsx(Checkbox, {}), name: "transaction-fee", label: Locale.label("donation.donationForm.cover").replace("{}", CurrencyHelper.formatCurrencyWithLocale(transactionFee, gateway?.currency || "USD")), onChange: handleCheckChange }) })), _jsxs("p", { children: [Locale.label("donation.donationForm.total"), ": ", CurrencyHelper.formatCurrencyWithLocale(total, gateway?.currency || "USD")] })] })), _jsx(TextField, { id: "donation-notes", fullWidth: true, label: Locale.label("donation.kingdomFunding.memo"), multiline: true, "aria-label": "note", name: "notes", value: donation.notes || "", onChange: handleChange, onKeyDown: handleKeyDown })] }), errorMessage && _jsx(ErrorMessages, { errors: [errorMessage] })] }))] })] }));
|
|
373
361
|
}
|
|
374
362
|
};
|
|
363
|
+
// Public member donation form. Applies the resolved provider's SDK wrapper
|
|
364
|
+
// (Stripe -> <Elements>, so 3DS works) around the provider-agnostic inner form.
|
|
365
|
+
export const MultiGatewayDonationForm = (props) => {
|
|
366
|
+
const provider = getPaymentProvider(props?.paymentGateways?.find(g => g.enabled !== false)?.provider || "stripe");
|
|
367
|
+
const Wrapper = provider.MemberWrapper;
|
|
368
|
+
const inner = _jsx(MultiGatewayDonationInner, { ...props });
|
|
369
|
+
return Wrapper ? _jsx(Wrapper, { stripePromise: props.stripePromise, children: inner }) : inner;
|
|
370
|
+
};
|
|
375
371
|
//# sourceMappingURL=MultiGatewayDonationForm.js.map
|