payments: integrate with payment server
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/braintree-web-drop-in": "^1.22.3",
|
"@types/braintree-web-drop-in": "^1.22.3",
|
||||||
|
"axios": "^0.21.1",
|
||||||
"braintree-web-drop-in": "^1.30.1",
|
"braintree-web-drop-in": "^1.30.1",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.2",
|
||||||
"framer-motion": "^3.10.0",
|
"framer-motion": "^3.10.0",
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import React, { useRef, useState, useEffect } from "react";
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
import dropin, { Dropin } from "braintree-web-drop-in";
|
import dropin, { Dropin } from "braintree-web-drop-in";
|
||||||
|
import axios from "axios";
|
||||||
|
import { CurrencyCircleDollar } from "phosphor-react";
|
||||||
|
|
||||||
import { StepProps } from "./DonationModal";
|
import { StepProps } from "./DonationModal";
|
||||||
|
|
||||||
|
const PaymentServer = axios.create({
|
||||||
|
baseURL: "https://us-central1-phosphor-14c61.cloudfunctions.net/paymentsApi",
|
||||||
|
});
|
||||||
|
|
||||||
const BT_PAYMENT_FIELDS = {
|
const BT_PAYMENT_FIELDS = {
|
||||||
number: {
|
number: {
|
||||||
placeholder: "4111 1111 1111 1111",
|
placeholder: "4111 1111 1111 1111",
|
||||||
@@ -17,16 +24,40 @@ const BT_PAYMENT_FIELDS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const PaymentModal: React.FC<StepProps> = ({ previousStep, routeProps }) => {
|
const PaymentModal: React.FC<StepProps> = ({
|
||||||
|
nextStep,
|
||||||
|
previousStep,
|
||||||
|
routeProps,
|
||||||
|
}) => {
|
||||||
const instance = useRef<Dropin>();
|
const instance = useRef<Dropin>();
|
||||||
const [isValid, setIsValid] = useState<boolean>(false);
|
const [isValid, setIsValid] = useState<boolean>(false);
|
||||||
|
const [isLoading, setLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
const { donationAmount } = routeProps;
|
const { donationAmount } = routeProps;
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (!instance.current) return;
|
if (!instance.current) return;
|
||||||
const payload = await instance.current.requestPaymentMethod();
|
|
||||||
console.log({ payload });
|
setLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const payload = await instance.current.requestPaymentMethod();
|
||||||
|
console.log({ ...payload, donationAmount });
|
||||||
|
const response = await PaymentServer.post("/", {
|
||||||
|
...payload,
|
||||||
|
donationAmount,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log({ response });
|
||||||
|
if (!!response.data?.success) {
|
||||||
|
nextStep();
|
||||||
|
} else {
|
||||||
|
setIsValid(false);
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -47,13 +78,13 @@ const PaymentModal: React.FC<StepProps> = ({ previousStep, routeProps }) => {
|
|||||||
flow: "checkout",
|
flow: "checkout",
|
||||||
amount: donationAmount.toFixed(2).toString(),
|
amount: donationAmount.toFixed(2).toString(),
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
commit: true,
|
commit: false,
|
||||||
},
|
},
|
||||||
paypalCredit: {
|
paypalCredit: {
|
||||||
flow: "checkout",
|
flow: "checkout",
|
||||||
amount: donationAmount.toFixed(2).toString(),
|
amount: donationAmount.toFixed(2).toString(),
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
commit: true,
|
commit: false,
|
||||||
},
|
},
|
||||||
venmo: { allowNewBrowserTab: false },
|
venmo: { allowNewBrowserTab: false },
|
||||||
});
|
});
|
||||||
@@ -72,12 +103,22 @@ const PaymentModal: React.FC<StepProps> = ({ previousStep, routeProps }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id="braintree-dropin"></div>
|
<div id="braintree-dropin"></div>
|
||||||
|
<div className="donation-details">
|
||||||
|
<CurrencyCircleDollar size={64} weight="duotone" />
|
||||||
|
<span>
|
||||||
|
Preparing your ${routeProps.donationAmount.toFixed(2)} donation...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div className="step-button-container">
|
<div className="step-button-container">
|
||||||
<button className="main-button" onClick={previousStep}>
|
<button className="main-button" onClick={previousStep}>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
<button className="main-button" onClick={submit} disabled={!isValid}>
|
<button
|
||||||
Submit
|
className="main-button"
|
||||||
|
onClick={submit}
|
||||||
|
disabled={isLoading || !isValid}
|
||||||
|
>
|
||||||
|
{isLoading ? "Processing..." : "Donate"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -38,6 +38,12 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.donation-details {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
button.modal-close-button {
|
button.modal-close-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 24px;
|
top: 24px;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ ReactDOM.render(
|
|||||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||||
serviceWorker.unregister();
|
serviceWorker.unregister();
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
console.log(`
|
console.log(`
|
||||||
%c sphorphosphor %co%cspho
|
%c sphorphosphor %co%cspho
|
||||||
%c s%cphorphosphor %co%csphorpho%cs
|
%c s%cphorphosphor %co%csphorpho%cs
|
||||||
|
|||||||
Reference in New Issue
Block a user