/* eslint-disable react/jsx-no-bind */
import React, { Fragment, useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import Slider from 'rc-slider';
import Tooltip from 'rc-tooltip';
import {
Alert,
Button,
Card,
CardBody,
CardTitle,
Col,
Form,
FormGroup,
Label,
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Row
} from 'reactstrap';
import {
licenses,
mediaTypes,
features,
addonFeatures
} from '../../../LoginRegister/Registration/PlanConstants';
import useForm from '../../../common/hooks/useForm';
import { debounce } from 'lodash';
import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
import useIsMounted from '../../../common/hooks/useIsMounted';
import reduxConnect from '../../../../redux/utils/connect';
import {
getPlans,
updatePrice
} from '../../../../api/registration/registration';
import {
updatePlanHubspot,
updatePlanPayment
} from '../../../../api/plans/userPlans';
import { planRoutes } from './UserPlans';
import BillingDetailsForm from './BillingDetailsForm';
import simpleNumberLocalizer from 'react-widgets-simple-number';
import NumberPicker from 'react-widgets/lib/NumberPicker';
import LoadersAdvanced from '../../../common/Loader/Loader';
import { IoIosWarning } from 'react-icons/io';
import { convertUTCtoLocal, setDocumentData } from '../../../../common/helper';
import { translate } from 'react-i18next';
simpleNumberLocalizer();
const Handle = Slider.Handle;
const handle = (props) => {
// eslint-disable-next-line react/prop-types
const { value, dragging, index, ...restProps } = props;
return (
);
};
const initialForm = {
savedFeeds: 0,
searchesPerDay: 0,
webFeeds: 0,
alerts: 0,
news: 0,
blog: 0,
reddit: 0,
instagram: 0,
twitter: 0,
analytics: 0,
subscriberAccounts: 0,
masterAccounts: 0
};
const initialPaymentForm = {
name: '',
line1: '',
line2: '',
city: '',
state: '',
postal_code: '',
country: '',
email: '',
phone: '',
errors: {
name: null,
line1: null,
city: null,
state: null,
postal_code: null,
country: null,
email: null,
phone: null
}
};
function UpdatePlan({ actions, restrictions, t }) {
const stripe = useStripe();
const elements = useElements();
const isMounted = useIsMounted();
// first step
const { form, handleChange, resetForm } = useForm(initialForm);
const [updatingPrice, setUpdatingPrice] = useState(true);
const [totalCost, setTotalCost] = useState(' - ');
const [modal, setModal] = useState(false);
const [loading, setLoading] = useState(false);
const [planLoading, setPlanLoading] = useState(true);
const [planError, setPlanError] = useState(false);
const [planList, setPlanList] = useState([]);
const [disableUpdate, setDisableUpdate] = useState(true);
// second step
const [nextStep, setNextStep] = useState(false);
const {
form: paymentForm,
handleChange: handlePaymentForm,
errors: paymentFormErrors,
handleValidation: handlePaymentValidation,
validateSubmit
} = useForm(initialPaymentForm);
const [paymentError, setPaymentError] = useState(false);
const [paymentLoading, setPaymentLoading] = useState(false);
// to update price when input changes
useEffect(() => {
if (planList.length > 0) {
debouncePrice(form);
}
}, [...Object.values(form)]);
const debouncePrice = useCallback(
debounce((form) => {
setUpdatingPrice(true);
updatePrice(form).then((res) => {
if (!isMounted.current) {
return false;
}
if (res.error || isNaN(res.data.totalPrice)) {
actions.addAlert(res.data);
setUpdatingPrice(false);
setTotalCost('Error');
return;
}
setTotalCost(res.data.totalPrice);
setUpdatingPrice(false);
});
}, 1000),
[isMounted.current]
);
useEffect(() => {
if (!restrictions.isPlanCancelled && !restrictions.isPlanDowngrade) {
setDisableUpdate(false);
} else {
setDisableUpdate(true);
}
}, [restrictions.isPlanCancelled, restrictions.isPlanDowngrade]);
useEffect(() => {
getBillingPlans();
setDocumentData('title', 'Update Plan');
return () => setDocumentData('title'); // default
}, []);
function getBillingPlans() {
setPlanLoading(true);
setPlanError(false);
getPlans().then((res) => {
if (!isMounted.current) {
return false;
}
if (res.error || !res.data || !res.data.length) {
setPlanError(true);
setPlanLoading(false);
res.data && res.data.length > 0 && actions.addAlert(res.data);
return;
}
setPlanLoading(false);
setPlanList(res.data);
const modified = { ...initialForm };
let selectedPlan = {};
if (restrictions.plans.price > 0) {
selectedPlan = { ...restrictions.plans };
Object.entries(restrictions.limits).map(([key, value]) => {
selectedPlan[key] = value.limit;
});
selectedPlan.blog = selectedPlan.blogs;
delete selectedPlan.blogs;
} else {
selectedPlan = res.data[0];
}
Object.keys(initialForm).map((key) => {
modified[key] =
selectedPlan[key] === undefined
? modified[key]
: selectedPlan[key] === true
? 1
: selectedPlan[key] === false
? 0
: selectedPlan[key];
});
resetForm(modified);
});
}
function changePlan(id) {
const selectedPlan = planList.find((plan) => plan.id === id);
const modified = { ...initialForm };
Object.keys(initialForm).map((key) => {
modified[key] =
selectedPlan[key] === undefined
? modified[key]
: selectedPlan[key] === true
? 1
: selectedPlan[key] === false
? 0
: selectedPlan[key];
});
resetForm(modified);
}
function handleSubmit() {
if (restrictions.isPlanCancelled || restrictions.isPlanDowngrade) {
return;
}
// move to payment page if new basic user
// instruct according to upgrade and downgrade
// if card already stored then only update the plan by showing modal or providing option to change card
setLoading(true);
if (restrictions.isPaymentId) {
setModal(true); // show details of card
} else {
setNextStep(true);
window.scrollTo(0, 0);
}
setLoading(false);
}
function toggle() {
setModal((prev) => !prev);
}
function proceedToDetails() {
toggle();
setNextStep(true);
window.scrollTo(0, 0);
}
const submitPayment = async () => {
if (!stripe || !elements) {
// Stripe.js has not loaded yet.
return;
}
if (restrictions.isPlanCancelled || restrictions.isPlanDowngrade) {
return;
}
setPaymentError(false);
setPaymentLoading(true);
const obj = validateSubmit();
if (!obj) {
setPaymentLoading(false);
return actions.addAlert({
type: 'error',
transKey: 'requiredInfo'
});
}
const cardElement = elements.getElement(CardElement);
const {
name,
line1,
line2,
city,
state,
postal_code,
country,
email,
phone
} = obj;
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {
name,
email,
phone,
address: {
line1: line1,
line2: line2,
city: city,
state: state,
postal_code: postal_code,
country: country
}
}
});
if (error) {
setPaymentError(error);
setPaymentLoading(false);
return;
}
const newObj = { ...form };
newObj.masterAccounts = '1';
newObj.paymentID = paymentMethod.id; //stripe card element ID
const res = await updatePlanPayment(newObj);
if (res.error) {
res.data
? actions.addAlert(res.data)
: actions.addAlert({ type: 'error', transKey: 'somethingWrong' });
setPaymentLoading(false);
return;
}
window.gtag &&
window.gtag('event', 'purchase', {
currency: 'USD',
value: totalCost
});
await updatePlanHubspot({ ...obj, ...form, totalCost });
actions.addAlert({ type: 'notice', transKey: 'planUpdated' });
// refresh page on success and move to active plan details
setTimeout(() => {
window.location.pathname = `/app/plans/${planRoutes.current}`;
}, 1000);
};
const proceedPayment = async () => {
// payment with old card
setLoading(true);
const newObj = { ...form };
newObj.masterAccounts = '1';
const res = await updatePlanPayment(newObj);
if (res.error) {
res.data
? actions.addAlert(res.data)
: actions.addAlert({ type: 'error', transKey: 'somethingWrong' });
setLoading(false);
return;
}
window.gtag &&
window.gtag('event', 'purchase', {
currency: 'USD',
value: totalCost
});
await updatePlanHubspot({ ...form, totalCost });
actions.addAlert({ type: 'notice', transKey: 'planUpdated' });
// refresh page on success and move to active plan details
setTimeout(() => {
window.location.pathname = `/app/plans/${planRoutes.current}`;
}, 1000);
};
function moveBack() {
window.scrollTo(0, 0);
setNextStep(false);
}
if (planError || planLoading) {
return (
{t('plans.updatePlan.heading')}
{planError && (
{t('plans.updatePlan.planLoadingFailed')}{' '}
)}
{planLoading && }
);
}
const isRTL = document.documentElement.dir === 'rtl';
return (
{!nextStep ? (
{t('plans.updatePlan.heading')}
{t('plans.updatePlan.subText')}{' '}
{t('plans.updatePlan.learnMoreBtn')}
.
) : (
{t('plans.updatePlan.billingHeading')}
{paymentError && (
{t('plans.updatePlan.error')}
{paymentError.message}
)}
)}
{t('plans.updatePlan.confirmationHeading')}
{restrictions.plans && restrictions.plans.price > 0 ? (
restrictions.plans.price === totalCost ? null : restrictions.plans
.price < totalCost ? (
{t('plans.updatePlan.upgradeNotice')}
) : (
{t('plans.updatePlan.downgradeNotice')}
)
) : null}
{t('plans.updatePlan.alreadyStoredCard')}
);
}
UpdatePlan.propTypes = {
t: PropTypes.func.isRequired,
actions: PropTypes.object,
restrictions: PropTypes.object
};
export default reduxConnect('restrictions', [
'common',
'auth',
'user',
'restrictions'
])(translate(['tabsContent'], { wait: true })(UpdatePlan));