-
Notifications
You must be signed in to change notification settings - Fork 114
/
addPaymentMethodForm.js
95 lines (86 loc) · 3.17 KB
/
addPaymentMethodForm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { useState } from 'react';
import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';
import Loading from '../../../components/loading/loading';
import { APIError, defaultErrorMessageForEndUser, userBillingSettings } from '../../../lib/api';
import Button from '../../../components/button/button';
import { planIdToStorageSubscription } from '../../contexts/plansContext';
/**
* @typedef {import('../../contexts/plansContext').Plan} Plan
*/
/**
* @param {object} obj
* @param {(v: boolean) => void} [obj.setHasPaymentMethods]
* @param {(v: boolean) => void} [obj.setEditingPaymentMethod]
* @param {Plan['id']} [obj.currentPlan]
* @returns
*/
const AddPaymentMethodForm = ({ setHasPaymentMethods, setEditingPaymentMethod, currentPlan }) => {
const elements = useElements();
const stripe = useStripe();
const [isLoading, setIsLoading] = useState(false);
const [paymentMethodError, setPaymentMethodError] = useState(/** @type {Error|null} */ (null));
const handlePaymentMethodAdd = async event => {
event.preventDefault();
if (!stripe || !elements) {
console.warn('stripe or elements is not loaded, so handlePaymentMethodAdd cannot use it');
return;
}
if (typeof currentPlan === 'undefined') {
console.warn(
'handlePaymentMethodAdd called when currentPlan is undefined, which should mean its still being fetched. This is unexpected, so the payment method will not be saved.'
);
return;
}
const cardElement = elements.getElement(CardElement);
if (cardElement) {
try {
setIsLoading(true);
const { paymentMethod, error } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
});
if (error) throw new Error(error.message);
if (!paymentMethod?.id) return;
const currStorageSubscription = planIdToStorageSubscription(currentPlan);
await userBillingSettings(paymentMethod.id, currStorageSubscription);
setHasPaymentMethods?.(true);
setEditingPaymentMethod?.(false);
setPaymentMethodError(null);
} catch (error) {
if (!(error instanceof APIError)) {
console.warn('unexpected error adding payment method', error);
}
setPaymentMethodError(new Error(defaultErrorMessageForEndUser));
} finally {
setIsLoading(false);
}
}
};
return (
<form>
<div className="billing-card card-transparent">
<CardElement
options={{
style: {
base: {
iconColor: '#cebcf4',
color: '#fff',
'::placeholder': {
color: '#ddd',
},
},
},
}}
/>
</div>
<div className="billing-validation">{paymentMethodError ? paymentMethodError.message : <></>}</div>
<div className="billing-card-add-card-wrapper">
<Button onClick={handlePaymentMethodAdd} variant="outline-light" disabled={!stripe}>
Add Card
</Button>
{isLoading && <Loading size="medium" message="Adding card info..." />}
</div>
</form>
);
};
export default AddPaymentMethodForm;