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:
parent
d22d011a10
commit
d54846c349
@ -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));
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user