2021-10-18 10:15:48 +02:00
|
|
|
import React, { FormEvent, useEffect, useState } from 'react';
|
2021-06-30 15:32:10 +02:00
|
|
|
import Select from 'react-select';
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { GatewayFormProps } from '../abstract-payment-modal';
|
|
|
|
import LocalPaymentAPI from '../../../api/local-payment';
|
|
|
|
import FormatLib from '../../../lib/format';
|
|
|
|
import SettingAPI from '../../../api/setting';
|
|
|
|
import { SettingName } from '../../../models/setting';
|
2022-01-18 16:27:12 +01:00
|
|
|
import { CardPaymentModal } from '../card-payment-modal';
|
2021-06-30 15:32:10 +02:00
|
|
|
import { PaymentSchedule } from '../../../models/payment-schedule';
|
2022-01-05 15:58:33 +01:00
|
|
|
import { HtmlTranslate } from '../../base/html-translate';
|
2022-08-25 08:52:17 +02:00
|
|
|
import CheckoutAPI from '../../../api/checkout';
|
2021-06-30 15:32:10 +02:00
|
|
|
|
2022-01-05 15:58:33 +01:00
|
|
|
const ALL_SCHEDULE_METHODS = ['card', 'check', 'transfer'] as const;
|
2021-06-30 15:32:10 +02:00
|
|
|
type scheduleMethod = typeof ALL_SCHEDULE_METHODS[number];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Option format, expected by react-select
|
|
|
|
* @see https://github.com/JedWatson/react-select
|
|
|
|
*/
|
|
|
|
type selectOption = { value: scheduleMethod, label: string };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A form component to ask for confirmation before cashing a payment directly at the FabLab's reception.
|
|
|
|
* This is intended for use by privileged users.
|
|
|
|
* The form validation button must be created elsewhere, using the attribute form={formId}.
|
|
|
|
*/
|
2022-08-25 08:52:17 +02:00
|
|
|
export const LocalPaymentForm: React.FC<GatewayFormProps> = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule, cart, updateCart, customer, operator, formId, order }) => {
|
2021-06-30 15:32:10 +02:00
|
|
|
const { t } = useTranslation('admin');
|
|
|
|
|
|
|
|
const [method, setMethod] = useState<scheduleMethod>('check');
|
|
|
|
const [onlinePaymentModal, setOnlinePaymentModal] = useState<boolean>(false);
|
|
|
|
|
2021-10-18 10:15:48 +02:00
|
|
|
useEffect(() => {
|
2022-01-05 15:58:33 +01:00
|
|
|
setMethod(cart.payment_method || 'check');
|
2021-10-18 10:15:48 +02:00
|
|
|
}, [cart]);
|
|
|
|
|
2021-06-30 15:32:10 +02:00
|
|
|
/**
|
|
|
|
* Open/closes the online payment modal, used to collect card credentials when paying the payment schedule by card.
|
|
|
|
*/
|
|
|
|
const toggleOnlinePaymentModal = (): void => {
|
|
|
|
setOnlinePaymentModal(!onlinePaymentModal);
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert all payement methods for schedules to the react-select format
|
|
|
|
*/
|
|
|
|
const buildMethodOptions = (): Array<selectOption> => {
|
|
|
|
return ALL_SCHEDULE_METHODS.map(i => methodToOption(i));
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert the given payment-method to the react-select format
|
|
|
|
*/
|
|
|
|
const methodToOption = (value: scheduleMethod): selectOption => {
|
|
|
|
if (!value) return { value, label: '' };
|
|
|
|
|
2022-06-21 12:09:56 +02:00
|
|
|
return { value, label: t(`app.admin.local_payment_form.method_${value}`) };
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback triggered when the user selects a payment method for the current payment schedule.
|
|
|
|
*/
|
|
|
|
const handleUpdateMethod = (option: selectOption) => {
|
2022-01-05 15:58:33 +01:00
|
|
|
updateCart(Object.assign({}, cart, { payment_method: option.value }));
|
2021-06-30 15:32:10 +02:00
|
|
|
setMethod(option.value);
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle the submission of the form. It will process the local payment.
|
|
|
|
*/
|
|
|
|
const handleSubmit = async (event: FormEvent): Promise<void> => {
|
|
|
|
event.preventDefault();
|
|
|
|
onSubmit();
|
|
|
|
|
|
|
|
if (paymentSchedule && method === 'card') {
|
|
|
|
// check that the online payment is active
|
|
|
|
try {
|
|
|
|
const online = await SettingAPI.get(SettingName.OnlinePaymentModule);
|
|
|
|
if (online.value !== 'true') {
|
2022-06-21 12:09:56 +02:00
|
|
|
return onError(t('app.admin.local_payment_form.online_payment_disabled'));
|
2021-06-30 15:32:10 +02:00
|
|
|
}
|
|
|
|
return toggleOnlinePaymentModal();
|
|
|
|
} catch (e) {
|
|
|
|
onError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2022-08-25 08:52:17 +02:00
|
|
|
let res;
|
|
|
|
if (order) {
|
|
|
|
res = await CheckoutAPI.payment(order.token);
|
|
|
|
} else {
|
|
|
|
res = await LocalPaymentAPI.confirmPayment(cart);
|
|
|
|
}
|
|
|
|
onSuccess(res);
|
2021-06-30 15:32:10 +02:00
|
|
|
} catch (e) {
|
|
|
|
onError(e);
|
|
|
|
}
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback triggered after a successful payment by online card for a schedule.
|
|
|
|
*/
|
|
|
|
const afterCreatePaymentSchedule = (document: PaymentSchedule) => {
|
|
|
|
toggleOnlinePaymentModal();
|
|
|
|
onSuccess(document);
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|
2021-06-30 15:32:10 +02:00
|
|
|
|
2021-10-22 15:43:33 +02:00
|
|
|
/**
|
|
|
|
* Generally, this form component is only shown to admins or to managers when they book for someone else.
|
|
|
|
* If this is not the case, then it is shown to validate a free (or prepaid by wallet) cart.
|
|
|
|
* This function will return `true` in the later case.
|
|
|
|
*/
|
|
|
|
const isFreeOfCharge = (): boolean => {
|
|
|
|
return (customer.id === operator.id);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the type of the main item in the cart compile
|
|
|
|
*/
|
|
|
|
const mainItemType = (): string => {
|
|
|
|
return Object.keys(cart.items[0])[0];
|
|
|
|
};
|
|
|
|
|
2021-06-30 15:32:10 +02:00
|
|
|
return (
|
2022-06-01 15:24:25 +02:00
|
|
|
<form onSubmit={handleSubmit} id={formId} className={`local-payment-form ${className || ''}`}>
|
2022-06-21 12:09:56 +02:00
|
|
|
{!paymentSchedule && !isFreeOfCharge() && <p className="payment">{t('app.admin.local_payment_form.about_to_cash')}</p>}
|
|
|
|
{!paymentSchedule && isFreeOfCharge() && <p className="payment">{t('app.admin.local_payment_form.about_to_confirm', { ITEM: mainItemType() })}</p>}
|
2021-06-30 15:32:10 +02:00
|
|
|
{paymentSchedule && <div className="payment-schedule">
|
|
|
|
<div className="schedule-method">
|
2022-06-21 12:09:56 +02:00
|
|
|
<label htmlFor="payment-method">{t('app.admin.local_payment_form.payment_method')}</label>
|
|
|
|
<Select placeholder={ t('app.admin.local_payment_form.payment_method') }
|
2021-07-01 12:34:10 +02:00
|
|
|
id="payment-method"
|
|
|
|
className="method-select"
|
|
|
|
onChange={handleUpdateMethod}
|
|
|
|
options={buildMethodOptions()}
|
2021-10-18 10:15:48 +02:00
|
|
|
value={methodToOption(method)} />
|
2022-06-21 12:09:56 +02:00
|
|
|
{method === 'card' && <p>{t('app.admin.local_payment_form.card_collection_info')}</p>}
|
|
|
|
{method === 'check' && <p>{t('app.admin.local_payment_form.check_collection_info', { DEADLINES: paymentSchedule.items.length })}</p>}
|
2022-06-22 13:01:22 +02:00
|
|
|
{method === 'transfer' && <HtmlTranslate trKey="app.admin.local_payment_form.transfer_collection_info" options={{ DEADLINES: paymentSchedule.items.length }} />}
|
2021-06-30 15:32:10 +02:00
|
|
|
</div>
|
|
|
|
<div className="full-schedule">
|
|
|
|
<ul>
|
|
|
|
{paymentSchedule.items.map(item => {
|
|
|
|
return (
|
2021-06-30 16:35:25 +02:00
|
|
|
<li key={`${item.due_date}`}>
|
2021-06-30 15:32:10 +02:00
|
|
|
<span className="schedule-item-date">{FormatLib.date(item.due_date)}</span>
|
|
|
|
<span> </span>
|
|
|
|
<span className="schedule-item-price">{FormatLib.price(item.amount)}</span>
|
|
|
|
</li>
|
2021-07-01 12:34:10 +02:00
|
|
|
);
|
2021-06-30 15:32:10 +02:00
|
|
|
})}
|
|
|
|
</ul>
|
|
|
|
</div>
|
2022-01-18 16:27:12 +01:00
|
|
|
<CardPaymentModal isOpen={onlinePaymentModal}
|
2021-07-01 12:34:10 +02:00
|
|
|
toggleModal={toggleOnlinePaymentModal}
|
|
|
|
afterSuccess={afterCreatePaymentSchedule}
|
|
|
|
onError={onError}
|
|
|
|
cart={cart}
|
|
|
|
currentUser={operator}
|
2021-09-10 18:32:39 +02:00
|
|
|
customer={customer}
|
|
|
|
schedule={paymentSchedule} />
|
2021-06-30 15:32:10 +02:00
|
|
|
</div>}
|
|
|
|
{children}
|
|
|
|
</form>
|
|
|
|
);
|
2021-07-01 12:34:10 +02:00
|
|
|
};
|