mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
[WIP] refactor renew subscription modal
This commit is contained in:
parent
17a0baac7e
commit
6cd91d0291
@ -17,7 +17,7 @@ interface PaymentScheduleSummaryProps {
|
|||||||
/**
|
/**
|
||||||
* This component displays a summary of the monthly payment schedule for the current cart, with a subscription
|
* This component displays a summary of the monthly payment schedule for the current cart, with a subscription
|
||||||
*/
|
*/
|
||||||
const PaymentScheduleSummary: React.FC<PaymentScheduleSummaryProps> = ({ schedule }) => {
|
export const PaymentScheduleSummary: React.FC<PaymentScheduleSummaryProps> = ({ schedule }) => {
|
||||||
const { t } = useTranslation('shared');
|
const { t } = useTranslation('shared');
|
||||||
|
|
||||||
// is open, the modal dialog showing the full details of the payment schedule?
|
// is open, the modal dialog showing the full details of the payment schedule?
|
||||||
|
@ -12,19 +12,19 @@ interface SelectScheduleProps {
|
|||||||
show: boolean,
|
show: boolean,
|
||||||
selected: boolean,
|
selected: boolean,
|
||||||
onChange: (selected: boolean) => void,
|
onChange: (selected: boolean) => void,
|
||||||
className: string,
|
className?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component is a switch enabling the users to choose if they want to pay by monthly schedule
|
* This component is a switch enabling the users to choose if they want to pay by monthly schedule
|
||||||
* or with a one time payment
|
* or with a one time payment
|
||||||
*/
|
*/
|
||||||
const SelectSchedule: React.FC<SelectScheduleProps> = ({ show, selected, onChange, className }) => {
|
export const SelectSchedule: React.FC<SelectScheduleProps> = ({ show, selected, onChange, className }) => {
|
||||||
const { t } = useTranslation('shared');
|
const { t } = useTranslation('shared');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="select-schedule">
|
<div className="select-schedule">
|
||||||
{show && <div className={className}>
|
{show && <div className={className || ''}>
|
||||||
<label htmlFor="payment_schedule">{ t('app.shared.cart.monthly_payment') }</label>
|
<label htmlFor="payment_schedule">{ t('app.shared.cart.monthly_payment') }</label>
|
||||||
<Switch checked={selected} id="payment_schedule" onChange={onChange} className="schedule-switch" />
|
<Switch checked={selected} id="payment_schedule" onChange={onChange} className="schedule-switch" />
|
||||||
</div>}
|
</div>}
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Subscription, SubscriptionPaymentDetails } from '../../models/subscription';
|
||||||
|
import { FabModal, ModalSize } from '../base/fab-modal';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FabAlert } from '../base/fab-alert';
|
||||||
|
import { FabInput } from '../base/fab-input';
|
||||||
|
import FormatLib from '../../lib/format';
|
||||||
|
import { Loader } from '../base/loader';
|
||||||
|
import { react2angular } from 'react2angular';
|
||||||
|
import { IApplication } from '../../models/application';
|
||||||
|
import LocalPaymentAPI from '../../api/local-payment';
|
||||||
|
import { PaymentMethod, ShoppingCart } from '../../models/payment';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { SelectSchedule } from '../payment-schedule/select-schedule';
|
||||||
|
import SubscriptionAPI from '../../api/subscription';
|
||||||
|
import { PaymentScheduleSummary } from '../payment-schedule/payment-schedule-summary';
|
||||||
|
|
||||||
|
declare const Application: IApplication;
|
||||||
|
|
||||||
|
interface RenewModalProps {
|
||||||
|
isOpen: boolean,
|
||||||
|
toggleModal: () => void,
|
||||||
|
subscription?: Subscription,
|
||||||
|
customerId: number,
|
||||||
|
onSuccess: (message: string, newExpirationDate: Date) => void,
|
||||||
|
onError: (message: string) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modal dialog shown to renew the current subscription of a customer, for free
|
||||||
|
*/
|
||||||
|
const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => {
|
||||||
|
const { t } = useTranslation('admin');
|
||||||
|
|
||||||
|
const [expirationDate, setExpirationDate] = useState<Date>(new Date());
|
||||||
|
const [localPaymentModal, setLocalPaymentModal] = useState<boolean>(false);
|
||||||
|
const [cart, setCart] = useState<ShoppingCart>(null);
|
||||||
|
const [scheduleRequired, setScheduleRequired] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// on init, we compute the new expiration date
|
||||||
|
useEffect(() => {
|
||||||
|
if (!subscription) return;
|
||||||
|
|
||||||
|
setExpirationDate(moment(subscription.expired_at)
|
||||||
|
.add(subscription.plan.interval_count, subscription.plan.interval)
|
||||||
|
.toDate());
|
||||||
|
SubscriptionAPI.paymentsDetails(subscription.id)
|
||||||
|
.then(res => setScheduleRequired(res.payment_schedule))
|
||||||
|
.catch(err => onError(err));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the formatted localized date for the given date
|
||||||
|
*/
|
||||||
|
const formatDateTime = (date: Date): string => {
|
||||||
|
return t('app.admin.free_extend_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback triggered when the user validates the renew of the subscription
|
||||||
|
*/
|
||||||
|
const handleConfirmRenew = (): void => {
|
||||||
|
LocalPaymentAPI.confirmPayment({
|
||||||
|
customer_id: customerId,
|
||||||
|
payment_method: PaymentMethod.Other,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
subscription: {
|
||||||
|
plan_id: subscription.plan_id
|
||||||
|
// start_at: subscription.expired_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).then(() => {
|
||||||
|
onSuccess(t('app.admin.renew_subscription_modal.renew_success'), expirationDate);
|
||||||
|
toggleModal();
|
||||||
|
}).catch(err => onError(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
// we do not render the modal if the subscription was not provided
|
||||||
|
if (!subscription) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FabModal isOpen={isOpen}
|
||||||
|
toggleModal={toggleModal}
|
||||||
|
width={ModalSize.large}
|
||||||
|
className="renew-modal"
|
||||||
|
title={t('app.admin.renew_subscription_modal.renew_subscription')}
|
||||||
|
confirmButton={t('app.admin.renew_subscription_modal.renew')}
|
||||||
|
onConfirm={handleConfirmRenew}
|
||||||
|
closeButton>
|
||||||
|
<FabAlert level="danger" className="conditions">
|
||||||
|
<p>{t('app.admin.renew_subscription_modal.renew_subscription_info')}</p>
|
||||||
|
<p>{t('app.admin.renew_subscription_modal.credits_will_be_reset')}</p>
|
||||||
|
</FabAlert>
|
||||||
|
<div className="form-and-payment">
|
||||||
|
<form className="configuration-form">
|
||||||
|
<label htmlFor="current_expiration">{t('app.admin.renew_subscription_modal.current_expiration')}</label>
|
||||||
|
<FabInput id="current_expiration"
|
||||||
|
defaultValue={formatDateTime(subscription.expired_at)}
|
||||||
|
readOnly />
|
||||||
|
<label htmlFor="new_start">{t('app.admin.renew_subscription_modal.new_start')}</label>
|
||||||
|
<FabInput id="new_start"
|
||||||
|
defaultValue={formatDateTime(subscription.expired_at)}
|
||||||
|
readOnly />
|
||||||
|
<label htmlFor="new_expiration">{t('app.admin.renew_subscription_modal.new_expiration_date')}</label>
|
||||||
|
<FabInput id="new_expiration"
|
||||||
|
defaultValue={formatDateTime(expirationDate)}
|
||||||
|
readOnly/>
|
||||||
|
</form>
|
||||||
|
<div className="payment">
|
||||||
|
<SelectSchedule show selected={scheduleRequired} onChange={setScheduleRequired} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FabModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RenewModalWrapper: React.FC<RenewModalProps> = ({ toggleModal, subscription, customerId, isOpen, onSuccess, onError }) => {
|
||||||
|
return (
|
||||||
|
<Loader>
|
||||||
|
<RenewModal toggleModal={toggleModal} subscription={subscription} customerId={customerId} isOpen={isOpen} onError={onError} onSuccess={onSuccess} />
|
||||||
|
</Loader>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Application.Components.component('renewModal', react2angular(RenewModalWrapper, ['toggleModal', 'subscription', 'customerId', 'isOpen', 'onError', 'onSuccess']));
|
@ -705,9 +705,12 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
|||||||
// current active authentication provider
|
// current active authentication provider
|
||||||
$scope.activeProvider = activeProviderPromise;
|
$scope.activeProvider = activeProviderPromise;
|
||||||
|
|
||||||
// modal dialog to extend the current subscription for free
|
// modal dialog to extend the current subscription for free
|
||||||
$scope.isOpenFreeExtendModal = false;
|
$scope.isOpenFreeExtendModal = false;
|
||||||
|
|
||||||
|
// modal dialog to renew the current subscription
|
||||||
|
$scope.isOpenRenewModal = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a modal dialog asking for confirmation to change the role of the given user
|
* Open a modal dialog asking for confirmation to change the role of the given user
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
@ -765,6 +768,16 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
|
|||||||
}, 50);
|
}, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens/closes the modal dialog to renew the subscription (with payment)
|
||||||
|
*/
|
||||||
|
$scope.toggleRenewModal = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
$scope.isOpenRenewModal = !$scope.isOpenRenewModal;
|
||||||
|
$scope.$apply();
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback triggered if the subscription was successfully extended
|
* Callback triggered if the subscription was successfully extended
|
||||||
*/
|
*/
|
||||||
|
@ -66,5 +66,6 @@
|
|||||||
@import "modules/prepaid-packs/propose-packs-modal";
|
@import "modules/prepaid-packs/propose-packs-modal";
|
||||||
@import "modules/prepaid-packs/packs-summary";
|
@import "modules/prepaid-packs/packs-summary";
|
||||||
@import "modules/subscriptions/free-extend-modal";
|
@import "modules/subscriptions/free-extend-modal";
|
||||||
|
@import "modules/subscriptions/renew-modal";
|
||||||
|
|
||||||
@import "app.responsive";
|
@import "app.responsive";
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
.renew-modal {
|
||||||
|
.fab-modal-content {
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
.form-and-payment {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.configuration-form {
|
||||||
|
padding-right: 15px;
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -78,7 +78,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<div ng-hide="user.id === currentUser.id">
|
<div ng-hide="user.id === currentUser.id">
|
||||||
<button class="btn btn-default" ng-click="toggleFreeExtendModal()" translate>{{ 'app.admin.members_edit.offer_free_days' }}</button>
|
<button class="btn btn-default" ng-click="toggleFreeExtendModal()" translate>{{ 'app.admin.members_edit.offer_free_days' }}</button>
|
||||||
<button class="btn btn-default" ng-click="updateSubscriptionModal(subscription, false)" translate>{{ 'app.admin.members_edit.renew_subscription' }}</button>
|
<button class="btn btn-default" ng-click="toggleRenewModal()" translate>{{ 'app.admin.members_edit.renew_subscription' }}</button>
|
||||||
<free-extend-modal is-open="isOpenFreeExtendModal"
|
<free-extend-modal is-open="isOpenFreeExtendModal"
|
||||||
toggle-modal="toggleFreeExtendModal"
|
toggle-modal="toggleFreeExtendModal"
|
||||||
subscription="subscription"
|
subscription="subscription"
|
||||||
@ -86,6 +86,13 @@
|
|||||||
on-error="onError"
|
on-error="onError"
|
||||||
on-success="onExtendSuccess">
|
on-success="onExtendSuccess">
|
||||||
</free-extend-modal>
|
</free-extend-modal>
|
||||||
|
<renew-modal is-open="isOpenRenewModal"
|
||||||
|
toggle-modal="toggleRenewModal"
|
||||||
|
subscription="subscription"
|
||||||
|
customer-id="user.id"
|
||||||
|
on-error="onError"
|
||||||
|
on-success="onExtendSuccess">
|
||||||
|
</renew-modal>
|
||||||
</div>
|
</div>
|
||||||
<p class="alert alert-info" ng-show="user.id === currentUser.id" translate>
|
<p class="alert alert-info" ng-show="user.id === currentUser.id" translate>
|
||||||
{{ 'app.admin.members_edit.cannot_extend_own_subscription' }}
|
{{ 'app.admin.members_edit.cannot_extend_own_subscription' }}
|
||||||
|
@ -888,13 +888,6 @@ en:
|
|||||||
download_the_invoice: "Download the invoice"
|
download_the_invoice: "Download the invoice"
|
||||||
download_the_refund_invoice: "Download the refund invoice"
|
download_the_refund_invoice: "Download the refund invoice"
|
||||||
no_invoices_for_now: "No invoices for now."
|
no_invoices_for_now: "No invoices for now."
|
||||||
current_expiration_date: "Current subscription will expire at:"
|
|
||||||
expiration_date: "Change subscription expiration date"
|
|
||||||
new_subscription_start: "The new subscription will start at:"
|
|
||||||
payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month."
|
|
||||||
payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments."
|
|
||||||
one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now."
|
|
||||||
one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment."
|
|
||||||
you_successfully_changed_the_expiration_date_of_the_user_s_subscription: "You successfully changed the expiration date of the user's subscription"
|
you_successfully_changed_the_expiration_date_of_the_user_s_subscription: "You successfully changed the expiration date of the user's subscription"
|
||||||
a_problem_occurred_while_saving_the_date: "A problem occurred while saving the date."
|
a_problem_occurred_while_saving_the_date: "A problem occurred while saving the date."
|
||||||
new_subscription: "New subscription"
|
new_subscription: "New subscription"
|
||||||
@ -922,6 +915,15 @@ en:
|
|||||||
renew_subscription: "Renew the subscription"
|
renew_subscription: "Renew the subscription"
|
||||||
renew_subscription_info: "You are about to renew the user's subscription by charging him again for his current subscription."
|
renew_subscription_info: "You are about to renew the user's subscription by charging him again for his current subscription."
|
||||||
credits_will_be_reset: "The balance of free credits (training / machines / spaces) of the user will be reset, unused credits will be lost."
|
credits_will_be_reset: "The balance of free credits (training / machines / spaces) of the user will be reset, unused credits will be lost."
|
||||||
|
current_expiration: "Current subscription will expire at:"
|
||||||
|
new_start: "The new subscription will start at:"
|
||||||
|
new_expiration_date: "The new subscription will expire at:"
|
||||||
|
payment_schedule_card: "The previous subscription was charged by card through a payment schedule, this one will be charged the same way. The first deadline will be charged when the current subscription expires, then each following month."
|
||||||
|
payment_schedule_check: "The previous subscription was charged by check through a payment schedule, this one will be charged the same way. Before confirming please ensure you have all the checks to collect all the monthly payments."
|
||||||
|
one_payment_card: "The previous subscription was charged by card through a single payment, this one will be charged the same way. The payment will be charged right now."
|
||||||
|
one_payment_check: "The previous subscription was charged by check through a single payment, this one will be charged the same way. Before confirming please ensure you have collected the payment."
|
||||||
|
renew: "Renew"
|
||||||
|
renew_success: "The subscription was successfully renewed"
|
||||||
#add a new administrator to the platform
|
#add a new administrator to the platform
|
||||||
admins_new:
|
admins_new:
|
||||||
add_an_administrator: "Add an administrator"
|
add_an_administrator: "Add an administrator"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user