1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

UI to confirm check cashing

This commit is contained in:
Sylvain 2021-02-04 17:00:02 +01:00
parent d22d011a10
commit d54846c349
8 changed files with 92 additions and 35 deletions

View File

@ -1,6 +1,6 @@
import apiClient from './api-client';
import { AxiosResponse } from 'axios';
import { PaymentSchedule, PaymentScheduleIndexRequest } from '../models/payment-schedule';
import { PaymentSchedule, PaymentScheduleIndexRequest, PaymentScheduleItem } from '../models/payment-schedule';
import wrapPromise, { IWrapPromise } from '../lib/wrap-promise';
export default class PaymentScheduleAPI {
@ -9,6 +9,11 @@ export default class PaymentScheduleAPI {
return res?.data;
}
async cashCheck(paymentScheduleItemId: number) {
const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/cash_check`);
return res?.data;
}
static list (query: PaymentScheduleIndexRequest): IWrapPromise<Array<PaymentSchedule>> {
const api = new PaymentScheduleAPI();
return wrapPromise(api.list(query));

View File

@ -29,7 +29,7 @@ export const FabButton: React.FC<FabButtonProps> = ({ onClick, icon, className,
}
return (
<button onClick={handleClick} className={`fab-button ${className}`}>
<button onClick={handleClick} className={`fab-button ${className ? className : ''}`}>
{hasIcon() && <span className="fab-button--icon">{icon}</span>}
{children}
</button>

View File

@ -2,12 +2,13 @@
* This component is a template for a modal dialog that wraps the application style
*/
import React, { ReactNode } from 'react';
import React, { ReactNode, SyntheticEvent } from 'react';
import Modal from 'react-modal';
import { useTranslation } from 'react-i18next';
import { Loader } from './loader';
import CustomAssetAPI from '../api/custom-asset';
import { CustomAssetName } from '../models/custom-asset';
import { FabButton } from './fab-button';
Modal.setAppElement('body');
@ -25,12 +26,13 @@ interface FabModalProps {
closeButton?: boolean,
className?: string,
width?: ModalSize,
customFooter?: ReactNode
customFooter?: ReactNode,
onConfirm?: (event: SyntheticEvent) => void
}
const blackLogoFile = CustomAssetAPI.get(CustomAssetName.LogoBlackFile);
export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal, children, confirmButton, className, width = 'sm', closeButton, customFooter }) => {
export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal, children, confirmButton, className, width = 'sm', closeButton, customFooter, onConfirm }) => {
const { t } = useTranslation('shared');
const blackLogo = blackLogoFile.read();
@ -56,7 +58,7 @@ export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal,
}
return (
<Modal isOpen={isOpen}
<Modal isOpen={isOpen}onConfirm
className={`fab-modal fab-modal-${width} ${className}`}
overlayClassName="fab-modal-overlay"
onRequestClose={toggleModal}>
@ -73,8 +75,8 @@ export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal,
</div>
<div className="fab-modal-footer">
<Loader>
{hasCloseButton() &&<button className="modal-btn--close" onClick={toggleModal}>{t('app.shared.buttons.close')}</button>}
{hasConfirmButton() && <span className="modal-btn--confirm">{confirmButton}</span>}
{hasCloseButton() &&<FabButton className="modal-btn--close" onClick={toggleModal}>{t('app.shared.buttons.close')}</FabButton>}
{hasConfirmButton() && <FabButton className="modal-btn--confirm" onClick={onConfirm}>{confirmButton}</FabButton>}
{hasCustomFooter() && customFooter}
</Loader>
</div>

View File

@ -2,7 +2,7 @@
* This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices
*/
import React, { ReactEventHandler, useState } from 'react';
import React, { ReactEventHandler, ReactNode, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Loader } from './loader';
import moment from 'moment';
@ -10,6 +10,8 @@ import { IFablab } from '../models/fablab';
import _ from 'lodash';
import { PaymentSchedule, PaymentScheduleItem, PaymentScheduleItemState } from '../models/payment-schedule';
import { FabButton } from './fab-button';
import { FabModal } from './fab-modal';
import PaymentScheduleAPI from '../api/payment-schedule';
declare var Fablab: IFablab;
@ -21,13 +23,15 @@ interface PaymentSchedulesTableProps {
const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({ paymentSchedules, showCustomer }) => {
const { t } = useTranslation('admin');
const [showExpanded, setShowExpanded] = useState({});
const [showExpanded, setShowExpanded] = useState<Map<number, boolean>>(new Map());
const [showConfirmCashing, setShowConfirmCashing] = useState<boolean>(false);
const [tempDeadline, setTempDeadline] = useState<PaymentScheduleItem>(null);
/**
* Check if the requested payment schedule is displayed with its deadlines (PaymentScheduleItem) or without them
*/
const isExpanded = (paymentScheduleId: number): boolean => {
return showExpanded[paymentScheduleId];
return showExpanded.get(paymentScheduleId);
}
/**
@ -71,9 +75,9 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
const togglePaymentScheduleDetails = (paymentScheduleId: number): ReactEventHandler => {
return (): void => {
if (isExpanded(paymentScheduleId)) {
setShowExpanded(Object.assign({}, showExpanded, { [paymentScheduleId]: false }));
setShowExpanded((prev) => new Map(prev).set(paymentScheduleId, false));
} else {
setShowExpanded(Object.assign({}, showExpanded, { [paymentScheduleId]: true }));
setShowExpanded((prev) => new Map(prev).set(paymentScheduleId, true));
}
}
}
@ -146,14 +150,42 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
const handleConfirmCheckPayment = (item: PaymentScheduleItem): ReactEventHandler => {
return (): void => {
/*
TODO
- display confirmation modal
- create /api/payment_schedule/item/confirm_check endpoint and post to it
*/
setTempDeadline(item);
toggleConfirmCashingModal();
}
}
const onCheckCashingConfirmed = (): void => {
const api = new PaymentScheduleAPI();
api.cashCheck(tempDeadline.id).then(res => {
// TODO refresh display
});
// TODO create /api/payment_schedule/item/confirm_check endpoint and post to it
}
/**
* Show/hide the modal dialog that enable to confirm the cashing of the check for a given deadline.
*/
const toggleConfirmCashingModal = (): void => {
setShowConfirmCashing(!showConfirmCashing);
}
/**
* Dynamically build the content of the modal depending on the currently selected deadline
*/
const cashingModalContent = (): ReactNode => {
if (tempDeadline) {
return (
<span>{t('app.admin.invoices.schedules_table.confirm_check_cashing_body', {
AMOUNT: formatPrice(tempDeadline.amount),
DATE: formatDate(tempDeadline.due_date)
})}</span>
);
}
return <span />;
}
const handleSolveAction = (item: PaymentScheduleItem): ReactEventHandler => {
return (): void => {
/*
@ -239,6 +271,16 @@ const PaymentSchedulesTableComponent: React.FC<PaymentSchedulesTableProps> = ({
</tr>)}
</tbody>
</table>
<div className="modals">
<FabModal title={t('app.admin.invoices.schedules_table.confirm_check_cashing')}
isOpen={showConfirmCashing}
toggleModal={toggleConfirmCashingModal}
onConfirm={onCheckCashingConfirmed}
closeButton={true}
confirmButton={t('app.admin.invoices.schedules_table.confirm_button')}>
{cashingModalContent()}
</FabModal>
</div>
</div>
);
};

View File

@ -69,23 +69,7 @@
border-top: 1px solid #e5e5e5;
.modal-btn {
margin-bottom: 0;
margin-left: 5px;
display: inline-block;
font-weight: normal;
text-align: center;
white-space: nowrap;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
padding: 6px 12px;
font-size: 16px;
line-height: 1.5;
border-radius: 4px;
&--close {
@extend .modal-btn;
color: black;
background-color: #fbfbfb;
border: 1px solid #c9c9c9;
@ -96,7 +80,7 @@
}
&--confirm {
@extend .modal-btn;
margin-left: 0.5em;
}
}
}

View File

@ -309,3 +309,21 @@ section#cookies-modal div.cookies-consent .cookies-actions button.accept {
}
}
}
.fab-modal {
.fab-modal-footer {
.modal-btn--confirm {
& {
background-color: $secondary;
color: $secondary-text-color;
border-color: $secondary
}
&:hover {
background-color: $secondary-dark !important;
border-color: $secondary-dark !important;
color: $secondary-text-color;
}
}
}
}

View File

@ -664,6 +664,9 @@ en:
confirm_payment: "Confirm payment"
solve: "Solve"
update_card: "Update the card"
confirm_check_cashing: "Confirm the cashing of the check"
confirm_check_cashing_body: "You must cash a check of {AMOUNT} for the deadline of {DATE}. By confirming the cashing of the check, an invoice will be generated for this due date."
confirm_button: "Confirm"
document_filters:
reference: "Reference"
customer: "Customer"

View File

@ -664,6 +664,9 @@ fr:
confirm_payment: "Confirmer l'encaissement"
solve: "Résoudre"
update_card: "Mettre à jour la carte"
confirm_check_cashing: "Confirmer l'encaissement du chèque"
confirm_check_cashing_body: "Vous devez encaisser un chèque de {AMOUNT} pour l'échéance du {DATE}. En confirmant l'encaissement du chèque, une facture sera générée pour cette échéance."
confirm_button: "Confirmer"
document_filters:
reference: "Référence"
customer: "Client"