@churchapps/apphelper-donations
Version:
Donation components for ChurchApps AppHelper
159 lines • 9.57 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useImperativeHandle, useState, useEffect } from "react";
import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
import { Box, Grid, TextField } from "@mui/material";
import { CurrencyHelper } from "@churchapps/helpers";
import { ApiHelper, ArrayHelper, UserHelper } from "@churchapps/helpers";
import { Locale, DonationHelper } from "../helpers";
export const FormCardPayment = forwardRef((props, ref) => {
const formStyling = { style: { base: { fontSize: "18px" } } };
const elements = useElements();
const stripe = useStripe();
const [email, setEmail] = useState((ApiHelper.isAuthenticated && UserHelper.user?.email) ? UserHelper.user.email : "");
const [firstName, setFirstName] = useState((ApiHelper.isAuthenticated && UserHelper.user?.firstName) ? UserHelper.user.firstName : "");
const [lastName, setLastName] = useState((ApiHelper.isAuthenticated && UserHelper.user?.lastName) ? UserHelper.user.lastName : "");
const [church, setChurch] = useState();
const [fund, setFund] = useState(undefined);
const [gateway, setGateway] = useState(null);
const amt = Number(props.question.choices?.find(c => c.text === "Amount")?.value || 0);
const fundId = props.question.choices?.find(c => c.text === "FundId")?.value || "";
const getChurchData = () => {
ApiHelper.get("/churches/" + props.churchId, "MembershipApi").then((data) => {
setChurch(data);
});
ApiHelper.get("/funds/churchId/" + props.churchId, "GivingApi").then((data) => {
const result = ArrayHelper.getOne(data, "id", fundId);
setFund(result);
});
ApiHelper.get(`/donate/gateways/${props.churchId}`, "GivingApi").then((response) => {
const gateways = Array.isArray(response?.gateways) ? response.gateways : [];
const stripeGateway = gateways.find((g) => g.provider?.toLowerCase() === "stripe");
if (stripeGateway)
setGateway(stripeGateway);
});
};
const handlePayment = async () => {
const validateErrors = validate();
if (validateErrors.length > 0) {
return { paymentSuccessful: false, errors: validateErrors };
}
try {
const userData = await ApiHelper.post("/users/loadOrCreate", { userEmail: email, firstName, lastName }, "MembershipApi");
const personData = { churchId: props.churchId, firstName, lastName, email };
const person = await ApiHelper.post("/people/loadOrCreate", personData, "MembershipApi");
const cardSavedRes = await saveCard(userData, person);
if (!cardSavedRes.success) {
return { paymentSuccessful: false, name: "", errors: cardSavedRes.errors || [] };
}
return { paymentSuccessful: true, name: person?.name?.display || "", errors: [] };
}
catch (err) {
const errorMessage = "An error occurred while processing your payment.";
return { paymentSuccessful: false, name: "", errors: [errorMessage] };
}
};
const saveCard = async (_user, person) => {
const cardData = elements?.getElement(CardElement);
try {
if (!stripe || !cardData) {
return { success: false, errors: ["Payment processing unavailable"] };
}
const stripePM = await stripe.createPaymentMethod({ type: "card", card: cardData });
if (stripePM.error) {
return { success: false, errors: [stripePM.error.message || "Payment method error"] };
}
else {
const pm = {
id: stripePM.paymentMethod?.id || "",
personId: person.id,
email: email,
name: person?.name?.display || "",
churchId: props.churchId,
provider: "stripe",
gatewayId: gateway?.id
};
try {
const result = await ApiHelper.post("/paymentmethods/addcard", pm, "GivingApi");
if (result?.raw?.message) {
return { success: false, errors: [result.raw.message] };
}
else {
const p = result;
const savedPaymentRes = await savePayment(p.paymentMethod, p.customerId, person);
if (!savedPaymentRes?.success) {
return { success: false, errors: savedPaymentRes?.errors || [] };
}
return { success: true, errors: [] };
}
}
catch (apiError) {
return { success: false, errors: ["An error occurred while saving the card."] };
}
}
}
catch (stripeError) {
return { success: false, errors: ["An error occurred while processing your payment method."] };
}
};
const savePayment = async (paymentMethod, customerId, person) => {
const payment = {
amount: amt,
id: paymentMethod.id,
customerId: customerId,
type: paymentMethod.type,
churchId: props.churchId,
funds: [{ id: fundId, amount: amt, name: fund?.name || "" }],
person: {
id: person?.id || "",
email: person?.contactInfo?.email || "",
name: person?.name?.display || ""
}
};
const churchObj = {
name: church?.name || "",
subDomain: church?.subDomain || "",
churchURL: typeof window !== "undefined" ? window.location.origin : "",
logo: ""
};
try {
const result = await ApiHelper.post("/donate/charge", { ...payment, church: churchObj }, "GivingApi");
// Handle 3D Secure authentication if required
const threeDSResult = await DonationHelper.handle3DSIfRequired(result, stripe);
if (threeDSResult.requiresAction) {
return { success: threeDSResult.success, errors: threeDSResult.error ? [threeDSResult.error] : [] };
}
if (result?.status === "succeeded" || result?.status === "pending" || result?.status === "processing") {
return { success: true, errors: [] };
}
if (result?.raw?.message) {
return { success: false, errors: [result.raw.message] };
}
return { success: false, errors: ["Payment was not successful."] };
}
catch (err) {
return { success: false, errors: ["An error occurred while saving your payment."] };
}
};
const validate = () => {
const result = [];
if (!firstName)
result.push(Locale.label("donation.donationForm.validate.firstName"));
if (!lastName)
result.push(Locale.label("donation.donationForm.validate.lastName"));
if (!email)
result.push(Locale.label("donation.donationForm.validate.email"));
if (result.length === 0) {
if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/))
result.push(Locale.label("donation.donationForm.validate.validEmail"));
}
return result;
};
useImperativeHandle(ref, () => ({
handlePayment,
questionId: props.question.id
}));
useEffect(getChurchData, []);
return _jsx("div", { style: { backgroundColor: "#bdbdbd", padding: 35, borderRadius: 20 }, children: _jsxs(Grid, { container: true, spacing: 2, children: [_jsx(Grid, { size: 12, children: _jsx(TextField, { fullWidth: true, required: true, size: "small", margin: "none", style: { backgroundColor: "white", borderRadius: "4px" }, InputLabelProps: { sx: { fontWeight: "bold" } }, label: Locale.label("person.email"), value: email, onChange: (e) => setEmail(e.target.value), disabled: ApiHelper.isAuthenticated && (UserHelper.user?.email || "") !== "" }) }), _jsx(Grid, { size: { xs: 12, sm: 6 }, children: _jsx(TextField, { fullWidth: true, required: true, size: "small", margin: "none", style: { backgroundColor: "white", borderRadius: "4px" }, InputLabelProps: { sx: { fontWeight: "bold" } }, label: Locale.label("person.firstName"), value: firstName, onChange: (e) => setFirstName(e.target.value), disabled: ApiHelper.isAuthenticated && (UserHelper.user?.firstName || "") !== "" }) }), _jsx(Grid, { size: { xs: 12, sm: 6 }, children: _jsx(TextField, { fullWidth: true, required: true, size: "small", margin: "none", style: { backgroundColor: "white", borderRadius: "4px" }, InputLabelProps: { sx: { fontWeight: "bold" } }, label: Locale.label("person.lastName"), value: lastName, onChange: (e) => setLastName(e.target.value), disabled: ApiHelper.isAuthenticated && (UserHelper.user?.lastName || "") !== "" }) }), _jsx(Grid, { size: 12, children: _jsxs(Box, { sx: { backgroundColor: "white", padding: 1.5, borderRadius: 1, color: "gray", fontWeight: "bold", fontSize: 18 }, children: [CurrencyHelper.getCurrencySymbol(gateway?.currency || "usd"), " ", amt] }) }), _jsx(Grid, { size: 12, children: _jsx("div", { style: { padding: 10, border: "1px solid #CCC", borderRadius: 5, backgroundColor: "white" }, children: _jsx(CardElement, { options: formStyling }) }) })] }) });
});
//# sourceMappingURL=FormCardPayment.js.map