2021-07-05 06:04:05 +02:00
|
|
|
// restore flow
|
2021-07-03 19:19:23 +02:00
|
|
|
/* eslint-disable no-undef */
|
|
|
|
/* eslint-disable react/prop-types */
|
|
|
|
import React from 'react';
|
|
|
|
import Page from 'component/page';
|
|
|
|
import Card from 'component/common/card';
|
|
|
|
import { Lbryio } from 'lbryinc';
|
2021-07-06 22:28:29 +02:00
|
|
|
import Plastic from 'react-plastic';
|
|
|
|
import Button from 'component/button';
|
|
|
|
import * as ICONS from 'constants/icons';
|
|
|
|
import * as MODALS from 'constants/modal_types';
|
2021-08-13 19:59:43 +02:00
|
|
|
import * as PAGES from 'constants/pages';
|
2022-03-22 23:24:26 +01:00
|
|
|
import { FormField } from 'component/common/form';
|
2021-08-18 00:34:16 +02:00
|
|
|
import { STRIPE_PUBLIC_KEY } from 'config';
|
|
|
|
import { getStripeEnvironment } from 'util/stripe';
|
|
|
|
let stripeEnvironment = getStripeEnvironment();
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-03-15 03:38:45 +01:00
|
|
|
const STRIPE_PLUGIN_SRC = 'https://js.stripe.com/v3/';
|
|
|
|
|
2021-08-11 22:58:55 +02:00
|
|
|
const APIS_DOWN_ERROR_RESPONSE = __('There was an error from the server, please try again later');
|
|
|
|
const CARD_SETUP_ERROR_RESPONSE = __('There was an error getting your card setup, please try again later');
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
// eslint-disable-next-line flowtype/no-types-missing-file-annotation
|
|
|
|
type Props = {
|
|
|
|
disabled: boolean,
|
|
|
|
label: ?string,
|
|
|
|
email: ?string,
|
|
|
|
scriptFailedToLoad: boolean,
|
|
|
|
doOpenModal: (string, {}) => void,
|
2022-03-29 17:11:37 +02:00
|
|
|
doToast: ({}) => void,
|
2021-07-06 22:28:29 +02:00
|
|
|
openModal: (string, {}) => void,
|
|
|
|
setAsConfirmingCard: () => void,
|
2022-03-23 18:13:04 +01:00
|
|
|
locale: ?any,
|
2022-03-29 17:11:37 +02:00
|
|
|
preferredCurrency: string,
|
|
|
|
setPreferredCurrency: (string) => void,
|
2021-07-06 22:28:29 +02:00
|
|
|
};
|
2021-07-19 23:29:01 +02:00
|
|
|
|
2021-07-05 06:04:05 +02:00
|
|
|
// type State = {
|
|
|
|
// open: boolean,
|
|
|
|
// currentFlowStage: string,
|
|
|
|
// customerTransactions: Array<any>,
|
|
|
|
// pageTitle: string,
|
|
|
|
// userCardDetails: any, // fill this out
|
|
|
|
// scriptFailedToLoad: boolean,
|
|
|
|
// };
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2021-07-06 03:29:46 +02:00
|
|
|
class SettingsStripeCard extends React.Component<Props, State> {
|
2021-07-05 06:04:05 +02:00
|
|
|
constructor(props) {
|
|
|
|
// :Props
|
2021-07-03 19:19:23 +02:00
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
open: false,
|
|
|
|
scriptFailedToLoad: false,
|
|
|
|
currentFlowStage: 'loading', // loading, confirmingCard, cardConfirmed
|
|
|
|
customerTransactions: [],
|
|
|
|
pageTitle: 'Add Card',
|
|
|
|
userCardDetails: {},
|
2021-07-06 22:28:29 +02:00
|
|
|
paymentMethodId: '',
|
2022-03-22 23:24:26 +01:00
|
|
|
preferredCurrency: 'USD',
|
2021-07-03 19:19:23 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
2021-07-17 18:08:53 +02:00
|
|
|
let that = this;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
that.setState({
|
|
|
|
cardNameValue: '',
|
|
|
|
});
|
|
|
|
|
2022-03-23 18:13:04 +01:00
|
|
|
const { preferredCurrency, locale } = this.props;
|
2022-03-22 23:24:26 +01:00
|
|
|
|
2022-03-23 18:13:04 +01:00
|
|
|
// use preferredCurrency if it's set on client, otherwise use USD, unless in Europe then use EUR
|
2022-03-22 23:24:26 +01:00
|
|
|
if (preferredCurrency) {
|
|
|
|
that.setState({
|
|
|
|
preferredCurrency: preferredCurrency,
|
|
|
|
});
|
2022-03-23 18:13:04 +01:00
|
|
|
} else if (locale) {
|
|
|
|
if (locale.continent === 'EU') {
|
|
|
|
that.setState({
|
|
|
|
preferredCurrency: 'EUR',
|
|
|
|
});
|
|
|
|
}
|
2022-03-22 23:24:26 +01:00
|
|
|
}
|
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
let doToast = this.props.doToast;
|
2021-07-06 22:28:29 +02:00
|
|
|
|
2022-03-15 03:38:45 +01:00
|
|
|
// only add script if it doesn't already exist
|
|
|
|
const stripeScriptExists = document.querySelectorAll(`script[src="${STRIPE_PLUGIN_SRC}"]`).length > 0;
|
|
|
|
|
|
|
|
if (!stripeScriptExists) {
|
|
|
|
const script = document.createElement('script');
|
|
|
|
script.src = STRIPE_PLUGIN_SRC;
|
|
|
|
script.async = true;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-03-15 03:38:45 +01:00
|
|
|
// $FlowFixMe
|
|
|
|
document.body.appendChild(script);
|
|
|
|
}
|
2021-07-03 19:19:23 +02:00
|
|
|
|
|
|
|
// public key of the stripe account
|
2021-07-17 18:08:53 +02:00
|
|
|
let publicKey = STRIPE_PUBLIC_KEY;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
|
|
|
// client secret of the SetupIntent (don't share with anyone but customer)
|
2021-07-17 18:08:53 +02:00
|
|
|
let clientSecret = '';
|
2021-07-03 19:19:23 +02:00
|
|
|
|
|
|
|
// setting a timeout to let the client secret populate
|
|
|
|
// TODO: fix this, should be a cleaner way
|
2021-07-17 18:08:53 +02:00
|
|
|
setTimeout(function () {
|
2021-07-03 19:19:23 +02:00
|
|
|
// check if customer has card setup already
|
2021-08-18 00:34:16 +02:00
|
|
|
if (stripeEnvironment) {
|
|
|
|
Lbryio.call(
|
|
|
|
'customer',
|
|
|
|
'status',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
)
|
|
|
|
.then((customerStatusResponse) => {
|
|
|
|
// user has a card saved if their defaultPaymentMethod has an id
|
|
|
|
const defaultPaymentMethod = customerStatusResponse.Customer.invoice_settings.default_payment_method;
|
|
|
|
let userHasAlreadySetupPayment = Boolean(defaultPaymentMethod && defaultPaymentMethod.id);
|
|
|
|
|
|
|
|
// show different frontend if user already has card
|
|
|
|
if (userHasAlreadySetupPayment) {
|
|
|
|
let card = customerStatusResponse.PaymentMethods[0].card;
|
|
|
|
|
|
|
|
let customer = customerStatusResponse.Customer;
|
|
|
|
|
|
|
|
let topOfDisplay = customer.email.split('@')[0];
|
|
|
|
let bottomOfDisplay = '@' + customer.email.split('@')[1];
|
|
|
|
|
|
|
|
let cardDetails = {
|
|
|
|
brand: card.brand,
|
|
|
|
expiryYear: card.exp_year,
|
|
|
|
expiryMonth: card.exp_month,
|
|
|
|
lastFour: card.last4,
|
|
|
|
topOfDisplay: topOfDisplay,
|
|
|
|
bottomOfDisplay: bottomOfDisplay,
|
|
|
|
};
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
const formattedEmailName = cardDetails.topOfDisplay + ' ' + cardDetails.bottomOfDisplay;
|
|
|
|
|
2021-08-18 00:34:16 +02:00
|
|
|
that.setState({
|
|
|
|
currentFlowStage: 'cardConfirmed',
|
2022-03-23 21:14:15 +01:00
|
|
|
pageTitle: 'Payment Methods',
|
2021-08-18 00:34:16 +02:00
|
|
|
userCardDetails: cardDetails,
|
|
|
|
paymentMethodId: customerStatusResponse.PaymentMethods[0].id,
|
2022-06-14 15:21:47 +02:00
|
|
|
cardName: customerStatusResponse.PaymentMethods[0].billing_details.name || formattedEmailName,
|
2021-08-18 00:34:16 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// otherwise, prompt them to save a card
|
|
|
|
} else {
|
|
|
|
that.setState({
|
|
|
|
currentFlowStage: 'confirmingCard',
|
|
|
|
});
|
|
|
|
|
|
|
|
// get a payment method secret for frontend
|
|
|
|
Lbryio.call(
|
|
|
|
'customer',
|
|
|
|
'setup',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
).then((customerSetupResponse) => {
|
|
|
|
clientSecret = customerSetupResponse.client_secret;
|
|
|
|
|
|
|
|
// instantiate stripe elements
|
|
|
|
setupStripe();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// get customer transactions
|
2021-07-05 06:04:05 +02:00
|
|
|
Lbryio.call(
|
|
|
|
'customer',
|
2021-08-18 00:34:16 +02:00
|
|
|
'list',
|
2021-07-05 06:04:05 +02:00
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
2021-08-18 00:34:16 +02:00
|
|
|
).then((customerTransactionsResponse) => {
|
|
|
|
that.setState({
|
|
|
|
customerTransactions: customerTransactionsResponse,
|
|
|
|
});
|
2021-07-06 22:28:29 +02:00
|
|
|
});
|
2021-08-18 00:34:16 +02:00
|
|
|
// if the status call fails, either an actual error or need to run setup first
|
|
|
|
})
|
|
|
|
.catch(function (error) {
|
|
|
|
// errorString passed from the API (with a 403 error)
|
|
|
|
const errorString = 'user as customer is not setup yet';
|
|
|
|
|
|
|
|
// if it's beamer's error indicating the account is not linked yet
|
|
|
|
if (error.message && error.message.indexOf(errorString) > -1) {
|
|
|
|
// send them to save a card
|
|
|
|
that.setState({
|
|
|
|
currentFlowStage: 'confirmingCard',
|
|
|
|
});
|
|
|
|
|
|
|
|
// get a payment method secret for frontend
|
|
|
|
Lbryio.call(
|
|
|
|
'customer',
|
|
|
|
'setup',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
).then((customerSetupResponse) => {
|
|
|
|
clientSecret = customerSetupResponse.client_secret;
|
|
|
|
|
|
|
|
// instantiate stripe elements
|
|
|
|
setupStripe();
|
|
|
|
});
|
|
|
|
// 500 error from the backend being down
|
|
|
|
} else if (error === 'internal_apis_down') {
|
|
|
|
doToast({ message: APIS_DOWN_ERROR_RESPONSE, isError: true });
|
|
|
|
} else {
|
|
|
|
// probably an error from stripe
|
|
|
|
doToast({ message: CARD_SETUP_ERROR_RESPONSE, isError: true });
|
|
|
|
}
|
2021-07-06 22:28:29 +02:00
|
|
|
});
|
2021-08-18 00:34:16 +02:00
|
|
|
}
|
2021-07-03 19:19:23 +02:00
|
|
|
}, 250);
|
|
|
|
|
|
|
|
function setupStripe() {
|
|
|
|
// TODO: have to fix this, using so that the script is available
|
2021-07-17 18:08:53 +02:00
|
|
|
setTimeout(function () {
|
|
|
|
var stripeElements = function (publicKey, setupIntent) {
|
2021-07-03 19:19:23 +02:00
|
|
|
var stripe = Stripe(publicKey);
|
|
|
|
var elements = stripe.elements();
|
|
|
|
|
|
|
|
// Element styles
|
|
|
|
var style = {
|
|
|
|
base: {
|
|
|
|
fontSize: '16px',
|
|
|
|
color: '#32325d',
|
2021-07-05 06:04:05 +02:00
|
|
|
fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif',
|
2021-07-03 19:19:23 +02:00
|
|
|
fontSmoothing: 'antialiased',
|
|
|
|
'::placeholder': {
|
|
|
|
color: 'rgba(0,0,0,0.4)',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
var card = elements.create('card', { style: style });
|
|
|
|
|
|
|
|
card.mount('#card-element');
|
|
|
|
|
|
|
|
// Element focus ring
|
2021-07-17 18:08:53 +02:00
|
|
|
card.on('focus', function () {
|
2021-07-03 19:19:23 +02:00
|
|
|
var el = document.getElementById('card-element');
|
|
|
|
el.classList.add('focused');
|
|
|
|
});
|
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
card.on('blur', function () {
|
2021-07-03 19:19:23 +02:00
|
|
|
var el = document.getElementById('card-element');
|
|
|
|
el.classList.remove('focused');
|
|
|
|
});
|
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
card.on('ready', function () {
|
2022-06-14 15:21:47 +02:00
|
|
|
// focus on the name input
|
|
|
|
document.querySelector('#card-name').focus();
|
2021-07-03 19:19:23 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
var email = that.props.email;
|
|
|
|
|
|
|
|
function submitForm(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
const cardUserName = document.querySelector('#card-name').value;
|
|
|
|
if (!cardUserName) {
|
|
|
|
return (document.querySelector('.sr-field-error').innerHTML = __('Please enter the name on the card'));
|
|
|
|
}
|
|
|
|
|
2021-07-03 19:19:23 +02:00
|
|
|
// if client secret wasn't loaded properly
|
|
|
|
if (!clientSecret) {
|
|
|
|
var displayErrorText = 'There was an error in generating your payment method. Please contact a developer';
|
|
|
|
var displayError = document.getElementById('card-errors');
|
|
|
|
displayError.textContent = displayErrorText;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
changeLoadingState(true);
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
const name = document.querySelector('#card-name').value;
|
|
|
|
|
2021-07-05 06:04:05 +02:00
|
|
|
stripe
|
|
|
|
.confirmCardSetup(clientSecret, {
|
|
|
|
payment_method: {
|
|
|
|
card: card,
|
2022-06-14 15:21:47 +02:00
|
|
|
billing_details: {
|
|
|
|
email,
|
|
|
|
name,
|
|
|
|
},
|
2021-07-05 06:04:05 +02:00
|
|
|
},
|
|
|
|
})
|
2021-07-17 18:08:53 +02:00
|
|
|
.then(function (result) {
|
2021-07-05 06:04:05 +02:00
|
|
|
if (result.error) {
|
|
|
|
changeLoadingState(false);
|
|
|
|
var displayError = document.getElementById('card-errors');
|
|
|
|
displayError.textContent = result.error.message;
|
|
|
|
} else {
|
|
|
|
// The PaymentMethod was successfully set up
|
|
|
|
// hide and show the proper divs
|
|
|
|
orderComplete(stripe, clientSecret);
|
|
|
|
}
|
|
|
|
});
|
2021-07-03 19:19:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle payment submission when user clicks the pay button.
|
|
|
|
var button = document.getElementById('submit');
|
2021-07-17 18:08:53 +02:00
|
|
|
button.addEventListener('click', function (event) {
|
2021-07-03 19:19:23 +02:00
|
|
|
submitForm(event);
|
|
|
|
});
|
|
|
|
|
|
|
|
// currently doesn't work because the iframe javascript context is different
|
|
|
|
// would be nice though if it's even technically possible
|
|
|
|
// window.addEventListener('keyup', function(event) {
|
|
|
|
// if (event.keyCode === 13) {
|
|
|
|
// submitForm(event);
|
|
|
|
// }
|
|
|
|
// }, false);
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: possible bug here where clientSecret isn't done
|
|
|
|
stripeElements(publicKey, clientSecret);
|
|
|
|
|
|
|
|
// Show a spinner on payment submission
|
2021-07-17 18:08:53 +02:00
|
|
|
var changeLoadingState = function (isLoading) {
|
2021-07-03 19:19:23 +02:00
|
|
|
if (isLoading) {
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-03 19:19:23 +02:00
|
|
|
document.querySelector('button').disabled = true;
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-05 21:04:07 +02:00
|
|
|
document.querySelector('#stripe-spinner').classList.remove('hidden');
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-03 19:19:23 +02:00
|
|
|
document.querySelector('#button-text').classList.add('hidden');
|
|
|
|
} else {
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-03 19:19:23 +02:00
|
|
|
document.querySelector('button').disabled = false;
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-05 21:04:07 +02:00
|
|
|
document.querySelector('#stripe-spinner').classList.add('hidden');
|
2021-07-05 06:04:05 +02:00
|
|
|
// $FlowFixMe
|
2021-07-03 19:19:23 +02:00
|
|
|
document.querySelector('#button-text').classList.remove('hidden');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// shows a success / error message when the payment is complete
|
2021-07-17 18:08:53 +02:00
|
|
|
var orderComplete = function (stripe, clientSecret) {
|
|
|
|
stripe.retrieveSetupIntent(clientSecret).then(function (result) {
|
2021-07-05 06:04:05 +02:00
|
|
|
Lbryio.call(
|
|
|
|
'customer',
|
|
|
|
'status',
|
|
|
|
{
|
|
|
|
environment: stripeEnvironment,
|
|
|
|
},
|
|
|
|
'post'
|
|
|
|
).then((customerStatusResponse) => {
|
2021-07-17 18:08:53 +02:00
|
|
|
let card = customerStatusResponse.PaymentMethods[0].card;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
let customer = customerStatusResponse.Customer;
|
2021-07-06 22:28:29 +02:00
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
let topOfDisplay = customer.email.split('@')[0];
|
|
|
|
let bottomOfDisplay = '@' + customer.email.split('@')[1];
|
2021-07-06 22:28:29 +02:00
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
let cardDetails = {
|
2021-07-03 19:19:23 +02:00
|
|
|
brand: card.brand,
|
|
|
|
expiryYear: card.exp_year,
|
|
|
|
expiryMonth: card.exp_month,
|
|
|
|
lastFour: card.last4,
|
2021-07-06 22:28:29 +02:00
|
|
|
topOfDisplay,
|
|
|
|
bottomOfDisplay,
|
2021-07-03 19:19:23 +02:00
|
|
|
};
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
const formattedEmailName = cardDetails.topOfDisplay + ' ' + cardDetails.bottomOfDisplay;
|
|
|
|
|
2021-07-03 19:19:23 +02:00
|
|
|
that.setState({
|
|
|
|
currentFlowStage: 'cardConfirmed',
|
2022-03-23 21:14:15 +01:00
|
|
|
pageTitle: 'Payment Methods',
|
2021-07-03 19:19:23 +02:00
|
|
|
userCardDetails: cardDetails,
|
2021-07-06 22:28:29 +02:00
|
|
|
paymentMethodId: customerStatusResponse.PaymentMethods[0].id,
|
2022-06-14 15:21:47 +02:00
|
|
|
cardName: customerStatusResponse.PaymentMethods[0].billing_details.name || formattedEmailName,
|
2021-07-03 19:19:23 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
changeLoadingState(false);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
render() {
|
2021-07-17 18:08:53 +02:00
|
|
|
let that = this;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-03-29 17:11:37 +02:00
|
|
|
const returnToValue = new URLSearchParams(location.search).get('returnTo');
|
2022-03-23 21:14:15 +01:00
|
|
|
let shouldShowBackToMembershipButton = returnToValue === 'premium';
|
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
function setAsConfirmingCard() {
|
2021-07-06 22:28:29 +02:00
|
|
|
that.setState({
|
|
|
|
currentFlowStage: 'confirmingCard',
|
2021-07-17 18:08:53 +02:00
|
|
|
});
|
2021-07-06 22:28:29 +02:00
|
|
|
}
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-03-22 23:24:26 +01:00
|
|
|
const { setPreferredCurrency } = this.props;
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
function clearErrorMessage() {
|
|
|
|
const errorElement = document.querySelector('.sr-field-error');
|
|
|
|
|
|
|
|
errorElement.innerHTML = '';
|
|
|
|
}
|
|
|
|
|
2022-03-22 23:24:26 +01:00
|
|
|
// when user changes currency in selector
|
2022-03-23 18:13:04 +01:00
|
|
|
function onCurrencyChange(event) {
|
2022-03-22 23:24:26 +01:00
|
|
|
const { value } = event.target;
|
|
|
|
|
|
|
|
// update preferred currency in frontend
|
|
|
|
that.setState({
|
|
|
|
preferredCurrency: value,
|
|
|
|
});
|
|
|
|
|
|
|
|
// update client settings
|
|
|
|
setPreferredCurrency(value);
|
|
|
|
}
|
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
function onChangeCardName(event) {
|
|
|
|
const { value } = event.target;
|
|
|
|
|
|
|
|
const numberOrSpecialCharacter = /[0-9!@#$%^&*()_+=[\]{};:"\\|,<>?~]/;
|
|
|
|
|
|
|
|
const errorElement = document.querySelector('.sr-field-error');
|
|
|
|
|
|
|
|
if (numberOrSpecialCharacter.test(value)) {
|
|
|
|
errorElement.innerHTML = __('Special characters and numbers are not allowed');
|
|
|
|
} else if (value.length > 48) {
|
|
|
|
errorElement.innerHTML = __('Name must be less than 48 characters long');
|
|
|
|
} else {
|
|
|
|
errorElement.innerHTML = '';
|
|
|
|
|
|
|
|
that.setState({
|
|
|
|
cardNameValue: value,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-17 18:08:53 +02:00
|
|
|
const { scriptFailedToLoad, openModal } = this.props;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
2022-06-14 15:21:47 +02:00
|
|
|
const {
|
|
|
|
currentFlowStage,
|
|
|
|
pageTitle,
|
|
|
|
userCardDetails,
|
|
|
|
paymentMethodId,
|
|
|
|
preferredCurrency,
|
|
|
|
cardName,
|
|
|
|
cardNameValue,
|
|
|
|
} = this.state;
|
2021-07-03 19:19:23 +02:00
|
|
|
|
|
|
|
return (
|
2022-03-23 21:14:15 +01:00
|
|
|
<Page noFooter noSideNavigation className="card-stack" backout={{ title: __(pageTitle), backLabel: __('Back') }}>
|
2021-09-09 18:52:03 +02:00
|
|
|
{/* if Stripe javascript didn't load */}
|
2021-07-03 19:19:23 +02:00
|
|
|
<div>
|
|
|
|
{scriptFailedToLoad && (
|
2021-08-13 19:59:43 +02:00
|
|
|
<div className="error__text">{__('There was an error connecting to Stripe. Please try again later.')}</div>
|
2021-07-03 19:19:23 +02:00
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
|
2021-09-09 18:52:03 +02:00
|
|
|
{/* initial markup to show while getting information */}
|
2021-07-05 06:04:05 +02:00
|
|
|
{currentFlowStage === 'loading' && (
|
2022-06-14 15:21:47 +02:00
|
|
|
<div className="getting-card-status">
|
2021-07-05 06:04:05 +02:00
|
|
|
<Card title={__('Connect your card with Odysee')} subtitle={__('Getting your card connection status...')} />
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
{/* customer has not added a card yet */}
|
2021-07-05 06:04:05 +02:00
|
|
|
{currentFlowStage === 'confirmingCard' && (
|
|
|
|
<div className="sr-root">
|
|
|
|
<div className="sr-main">
|
2022-06-14 15:21:47 +02:00
|
|
|
<div className="">
|
|
|
|
<div className="sr-form-row">
|
|
|
|
<label className="payment-details">{__('Name on card')}</label>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
id="card-name"
|
|
|
|
onChange={onChangeCardName}
|
|
|
|
value={cardNameValue}
|
|
|
|
onBlur={clearErrorMessage}
|
|
|
|
/>
|
|
|
|
</div>
|
2021-07-05 06:04:05 +02:00
|
|
|
<div className="sr-form-row">
|
2022-06-14 15:21:47 +02:00
|
|
|
<label className="payment-details">{__('Card details')}</label>
|
2021-07-05 06:04:05 +02:00
|
|
|
<div className="sr-input sr-element sr-card-element" id="card-element" />
|
|
|
|
</div>
|
|
|
|
<div className="sr-field-error" id="card-errors" role="alert" />
|
|
|
|
<button className="linkButton" id="submit">
|
2021-07-05 21:04:07 +02:00
|
|
|
<div className="stripe__spinner hidden" id="stripe-spinner" />
|
2021-08-27 06:42:23 +02:00
|
|
|
<span id="button-text">{__('Add Card')}</span>
|
2021-07-05 06:04:05 +02:00
|
|
|
</button>
|
2021-07-03 19:19:23 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2021-07-05 06:04:05 +02:00
|
|
|
)}
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
{/* if the user has already confirmed their card */}
|
2021-07-05 06:04:05 +02:00
|
|
|
{currentFlowStage === 'cardConfirmed' && (
|
|
|
|
<div className="successCard">
|
2022-03-23 21:14:15 +01:00
|
|
|
{/* back to membership button */}
|
|
|
|
{shouldShowBackToMembershipButton && (
|
|
|
|
<Button
|
|
|
|
button="primary"
|
|
|
|
label={__('Back To Odysee Premium')}
|
|
|
|
icon={ICONS.UPGRADE}
|
|
|
|
navigate={`/$/${PAGES.ODYSEE_MEMBERSHIP}`}
|
|
|
|
style={{ marginBottom: '20px' }}
|
|
|
|
/>
|
|
|
|
)}
|
2021-07-05 06:04:05 +02:00
|
|
|
<Card
|
|
|
|
title={__('Card Details')}
|
2022-03-29 17:58:11 +02:00
|
|
|
className="add-payment-card-div"
|
2021-07-05 06:04:05 +02:00
|
|
|
body={
|
|
|
|
<>
|
2021-07-06 22:28:29 +02:00
|
|
|
<Plastic
|
|
|
|
type={userCardDetails.brand}
|
2022-06-14 15:21:47 +02:00
|
|
|
name={cardName}
|
2021-07-06 22:28:29 +02:00
|
|
|
expiry={userCardDetails.expiryMonth + '/' + userCardDetails.expiryYear}
|
|
|
|
number={'____________' + userCardDetails.lastFour}
|
|
|
|
/>
|
|
|
|
<br />
|
|
|
|
<Button
|
2021-09-09 18:52:03 +02:00
|
|
|
button="primary"
|
2021-07-06 22:28:29 +02:00
|
|
|
label={__('Remove Card')}
|
|
|
|
icon={ICONS.DELETE}
|
|
|
|
onClick={(e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
openModal(MODALS.CONFIRM_REMOVE_CARD, {
|
|
|
|
paymentMethodId: paymentMethodId,
|
|
|
|
setAsConfirmingCard: setAsConfirmingCard,
|
|
|
|
});
|
|
|
|
}}
|
2021-07-17 18:08:53 +02:00
|
|
|
/>
|
2021-09-09 18:52:03 +02:00
|
|
|
<Button
|
|
|
|
button="secondary"
|
|
|
|
label={__('View Transactions')}
|
|
|
|
icon={ICONS.SETTINGS}
|
|
|
|
navigate={`/$/${PAGES.WALLET}?fiatType=outgoing&tab=fiat-payment-history¤cy=fiat`}
|
2022-03-15 03:38:45 +01:00
|
|
|
style={{ marginLeft: '10px' }}
|
2021-09-09 18:52:03 +02:00
|
|
|
/>
|
2021-07-05 06:04:05 +02:00
|
|
|
</>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
<br />
|
2022-03-22 23:24:26 +01:00
|
|
|
|
|
|
|
<div className="currency-to-use-div">
|
2022-03-29 17:11:37 +02:00
|
|
|
<h1 className="currency-to-use-header">{__('Currency To Use')}:</h1>
|
2022-03-22 23:24:26 +01:00
|
|
|
|
|
|
|
<fieldset-section>
|
|
|
|
<FormField
|
|
|
|
className="currency-to-use-selector"
|
|
|
|
name="currency_selector"
|
|
|
|
type="select"
|
|
|
|
onChange={onCurrencyChange}
|
|
|
|
value={preferredCurrency}
|
|
|
|
>
|
|
|
|
{['USD', 'EUR'].map((currency) => (
|
|
|
|
<option key={currency} value={currency}>
|
2022-03-31 11:13:34 +02:00
|
|
|
{currency}
|
2022-03-22 23:24:26 +01:00
|
|
|
</option>
|
|
|
|
))}
|
|
|
|
</FormField>
|
|
|
|
</fieldset-section>
|
|
|
|
</div>
|
2021-07-05 06:04:05 +02:00
|
|
|
</div>
|
|
|
|
)}
|
2021-07-03 19:19:23 +02:00
|
|
|
</Page>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 03:29:46 +02:00
|
|
|
export default SettingsStripeCard;
|
2021-07-03 19:19:23 +02:00
|
|
|
/* eslint-enable no-undef */
|
|
|
|
/* eslint-enable react/prop-types */
|