1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-10 00:46:15 +01:00
fab-manager/app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx
Sylvain 6c326c7209 compute price according to prepaid hours
Also: handle prepaid hours decreasing when used
2021-06-30 10:53:05 +02:00

157 lines
5.1 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import _ from 'lodash';
import { Machine } from '../../models/machine';
import { User } from '../../models/user';
import { UserPack } from '../../models/user-pack';
import UserPackAPI from '../../api/user-pack';
import SettingAPI from '../../api/setting';
import { SettingName } from '../../models/setting';
import { FabButton } from '../base/fab-button';
import { useTranslation } from 'react-i18next';
import { ProposePacksModal } from './propose-packs-modal';
import { Loader } from '../base/loader';
import { react2angular } from 'react2angular';
import { IApplication } from '../../models/application';
declare var Application: IApplication;
type PackableItem = Machine;
interface PacksSummaryProps {
item: PackableItem,
itemType: 'Machine',
customer?: User,
operator: User,
onError: (message: string) => void,
onSuccess: (message: string) => void,
refresh?: Promise<void>
}
const PacksSummaryComponent: React.FC<PacksSummaryProps> = ({ item, itemType, customer, operator, onError, onSuccess, refresh }) => {
const { t } = useTranslation('logged');
const [userPacks, setUserPacks] = useState<Array<UserPack>>(null);
const [threshold, setThreshold] = useState<number>(null);
const [packsModal, setPacksModal] = useState<boolean>(false);
useEffect(() => {
SettingAPI.get(SettingName.RenewPackThreshold)
.then(data => setThreshold(parseFloat(data.value)))
.catch(error => onError(error));
}, []);
useEffect(() => {
if (_.isEmpty(customer)) return;
getUserPacksData();
}, [item, itemType, customer]);
useEffect(() => {
if (refresh instanceof Promise) {
refresh.then(getUserPacksData);
}
}, [refresh]);
/**
* Fetch the user packs data from the API
*/
const getUserPacksData = (): void => {
UserPackAPI.index({ user_id: customer.id, priceable_type: itemType, priceable_id: item.id })
.then(data => setUserPacks(data))
.catch(error => onError(error));
}
/**
* Total of minutes used by the customer
*/
const totalUsed = (): number => {
if (!userPacks) return 0;
return userPacks.map(up => up.minutes_used).reduce((acc, curr) => acc + curr, 0);
}
/**
* Total of minutes available is the packs bought by the customer
*/
const totalAvailable = (): number => {
if (!userPacks) return 0;
return userPacks.map(up => up.prepaid_pack.minutes).reduce((acc, curr) => acc + curr, 0);
}
/**
* Total prepaid hours remaining for the current customer
*/
const totalHours = (): number => {
return (totalAvailable() - totalUsed()) / 60;
}
/**
* Do we need to display the "buy new pack" button?
*/
const shouldDisplayButton = (): boolean => {
if (threshold < 1) {
return totalAvailable() - totalUsed() <= totalAvailable() * threshold;
}
return totalAvailable() - totalUsed() <= threshold * 60;
}
/**
* Open/closes the prepaid-pack buying modal
*/
const togglePacksModal = (): void => {
setPacksModal(!packsModal);
}
/**
* Callback triggered when the customer has successfully bought a prepaid-pack
*/
const handlePackBoughtSuccess = (message: string): void => {
onSuccess(message);
togglePacksModal();
UserPackAPI.index({ user_id: customer.id, priceable_type: itemType, priceable_id: item.id })
.then(data => setUserPacks(data))
.catch(error => onError(error));
}
// prevent component rendering if no customer selected
if (_.isEmpty(customer)) return <div />;
return (
<div className="packs-summary">
<h3>{t('app.logged.packs_summary.prepaid_hours')}</h3>
<div className="content">
<span className="remaining-hours">
{totalHours() > 0 && t('app.logged.packs_summary.remaining_HOURS', { HOURS: totalHours(), ITEM: itemType })}
{totalHours() === 0 && t('app.logged.packs_summary.no_hours', { ITEM: itemType })}
</span>
{shouldDisplayButton() && <div className="button-wrapper">
<FabButton className="buy-button" onClick={togglePacksModal} icon={<i className="fa fa-shopping-cart"/>}>
{t('app.logged.packs_summary.buy_a_new_pack')}
</FabButton>
<ProposePacksModal isOpen={packsModal}
toggleModal={togglePacksModal}
item={item}
itemType={itemType}
customer={customer}
operator={operator}
onError={onError}
onDecline={togglePacksModal}
onSuccess={handlePackBoughtSuccess} />
</div>}
</div>
</div>
);
}
export const PacksSummary: React.FC<PacksSummaryProps> = ({ item, itemType, customer, operator, onError, onSuccess, refresh }) => {
return (
<Loader>
<PacksSummaryComponent item={item} itemType={itemType} customer={customer} operator={operator} onError={onError} onSuccess={onSuccess} refresh={refresh} />
</Loader>
);
}
Application.Components.component('packsSummary', react2angular(PacksSummary, ['item', 'itemType', 'customer', 'operator', 'onError', 'onSuccess', 'refresh']));