mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) add order action ready/in_progress/canceled
This commit is contained in:
parent
f015e23a85
commit
53004767bf
129
app/frontend/src/javascript/components/store/order-actions.tsx
Normal file
129
app/frontend/src/javascript/components/store/order-actions.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
import React, { useState, BaseSyntheticEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Select from 'react-select';
|
||||
import { FabModal } from '../base/fab-modal';
|
||||
import OrderAPI from '../../api/order';
|
||||
import { Order } from '../../models/order';
|
||||
|
||||
interface OrderActionsProps {
|
||||
order: Order,
|
||||
onSuccess: (order: Order, message: string) => void,
|
||||
onError: (message: string) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* Option format, expected by react-select
|
||||
* @see https://github.com/JedWatson/react-select
|
||||
*/
|
||||
type selectOption = { value: string, label: string };
|
||||
|
||||
/**
|
||||
* Actions for an order
|
||||
*/
|
||||
export const OrderActions: React.FC<OrderActionsProps> = ({ order, onSuccess, onError }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
const [currentAction, setCurrentAction] = useState<selectOption>();
|
||||
const [modalIsOpen, setModalIsOpen] = useState<boolean>(false);
|
||||
const [readyNote, setReadyNote] = useState<string>('');
|
||||
|
||||
// Styles the React-select component
|
||||
const customStyles = {
|
||||
control: base => ({
|
||||
...base,
|
||||
width: '20ch',
|
||||
backgroundColor: 'transparent'
|
||||
}),
|
||||
indicatorSeparator: () => ({
|
||||
display: 'none'
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the action confirmation modal
|
||||
*/
|
||||
const closeModal = (): void => {
|
||||
setModalIsOpen(false);
|
||||
setCurrentAction(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates sorting options to the react-select format
|
||||
*/
|
||||
const buildOptions = (): Array<selectOption> => {
|
||||
let actions = [];
|
||||
switch (order.state) {
|
||||
case 'paid':
|
||||
actions = actions.concat(['in_progress', 'ready', 'canceled', 'refunded']);
|
||||
break;
|
||||
case 'payment_failed':
|
||||
actions = actions.concat(['canceled']);
|
||||
break;
|
||||
case 'in_progress':
|
||||
actions = actions.concat(['ready', 'canceled', 'refunded']);
|
||||
break;
|
||||
case 'ready':
|
||||
actions = actions.concat(['canceled', 'refunded']);
|
||||
break;
|
||||
case 'canceled':
|
||||
actions = actions.concat(['refunded']);
|
||||
break;
|
||||
default:
|
||||
actions = [];
|
||||
}
|
||||
return actions.map(action => {
|
||||
return { value: action, label: t(`app.shared.store.order_actions.state.${action}`) };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback after selecting an action
|
||||
*/
|
||||
const handleAction = (action: selectOption) => {
|
||||
setCurrentAction(action);
|
||||
setModalIsOpen(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback after confirm an action
|
||||
*/
|
||||
const handleActionConfirmation = () => {
|
||||
OrderAPI.updateState(order, currentAction.value, readyNote).then(data => {
|
||||
onSuccess(data, t(`app.shared.store.order_actions.order_${currentAction.value}_success`));
|
||||
setCurrentAction(null);
|
||||
setModalIsOpen(false);
|
||||
}).catch((e) => {
|
||||
onError(e);
|
||||
setCurrentAction(null);
|
||||
setModalIsOpen(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
options={buildOptions()}
|
||||
onChange={option => handleAction(option)}
|
||||
value={currentAction}
|
||||
styles={customStyles}
|
||||
/>
|
||||
<FabModal title={t('app.shared.store.order_actions.confirmation_required')}
|
||||
isOpen={modalIsOpen}
|
||||
toggleModal={closeModal}
|
||||
closeButton={true}
|
||||
confirmButton={t('app.shared.store.order_actions.confirm')}
|
||||
onConfirm={handleActionConfirmation}
|
||||
className="order-actions-confirmation-modal">
|
||||
<p>{t(`app.shared.store.order_actions.confirm_order_${currentAction?.value}`)}</p>
|
||||
{currentAction?.value === 'ready' &&
|
||||
<textarea
|
||||
id="order-ready-note"
|
||||
value={readyNote}
|
||||
placeholder={t('app.shared.store.order_actions.order_ready_note')}
|
||||
onChange={(e: BaseSyntheticEvent) => setReadyNote(e.target.value)}
|
||||
style={{ width: '100%' }}
|
||||
rows={5} />
|
||||
}
|
||||
</FabModal>
|
||||
</>
|
||||
);
|
||||
};
|
@ -6,36 +6,28 @@ import { react2angular } from 'react2angular';
|
||||
import { Loader } from '../base/loader';
|
||||
import noImage from '../../../../images/no_image.png';
|
||||
import { FabStateLabel } from '../base/fab-state-label';
|
||||
import Select from 'react-select';
|
||||
import OrderAPI from '../../api/order';
|
||||
import { Order } from '../../models/order';
|
||||
import FormatLib from '../../lib/format';
|
||||
import OrderLib from '../../lib/order';
|
||||
import { OrderActions } from './order-actions';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface ShowOrderProps {
|
||||
orderId: string,
|
||||
currentUser?: User,
|
||||
onSuccess: (message: string) => void,
|
||||
onError: (message: string) => void,
|
||||
onSuccess: (message: string) => void
|
||||
}
|
||||
/**
|
||||
* Option format, expected by react-select
|
||||
* @see https://github.com/JedWatson/react-select
|
||||
*/
|
||||
type selectOption = { value: string, label: string };
|
||||
|
||||
/**
|
||||
* This component shows an order details
|
||||
*/
|
||||
// TODO: delete next eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onError, onSuccess }) => {
|
||||
export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onSuccess, onError }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
const [order, setOrder] = useState<Order>();
|
||||
const [currentAction, setCurrentAction] = useState<selectOption>();
|
||||
|
||||
useEffect(() => {
|
||||
OrderAPI.get(orderId).then(data => {
|
||||
@ -50,61 +42,6 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onEr
|
||||
return (currentUser?.role === 'admin' || currentUser?.role === 'manager');
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates sorting options to the react-select format
|
||||
*/
|
||||
const buildOptions = (): Array<selectOption> => {
|
||||
let actions = [];
|
||||
switch (order.state) {
|
||||
case 'paid':
|
||||
actions = actions.concat(['in_progress', 'ready', 'canceled', 'refunded']);
|
||||
break;
|
||||
case 'payment_failed':
|
||||
actions = actions.concat(['canceled']);
|
||||
break;
|
||||
case 'in_progress':
|
||||
actions = actions.concat(['ready', 'canceled', 'refunded']);
|
||||
break;
|
||||
case 'ready':
|
||||
actions = actions.concat(['canceled', 'refunded']);
|
||||
break;
|
||||
case 'canceled':
|
||||
actions = actions.concat(['refunded']);
|
||||
break;
|
||||
default:
|
||||
actions = [];
|
||||
}
|
||||
return actions.map(action => {
|
||||
return { value: action, label: t(`app.shared.store.show_order.state.${action}`) };
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback after selecting an action
|
||||
*/
|
||||
const handleAction = (action: selectOption) => {
|
||||
setCurrentAction(action);
|
||||
OrderAPI.updateState(order, action.value, action.value).then(data => {
|
||||
setOrder(data);
|
||||
setCurrentAction(null);
|
||||
}).catch((e) => {
|
||||
onError(e);
|
||||
setCurrentAction(null);
|
||||
});
|
||||
};
|
||||
|
||||
// Styles the React-select component
|
||||
const customStyles = {
|
||||
control: base => ({
|
||||
...base,
|
||||
width: '20ch',
|
||||
backgroundColor: 'transparent'
|
||||
}),
|
||||
indicatorSeparator: () => ({
|
||||
display: 'none'
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns order's payment info
|
||||
*/
|
||||
@ -135,6 +72,14 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onEr
|
||||
return paymentVerbose;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback after action success
|
||||
*/
|
||||
const handleActionSuccess = (data: Order, message: string) => {
|
||||
setOrder(data);
|
||||
onSuccess(message);
|
||||
};
|
||||
|
||||
if (!order) {
|
||||
return null;
|
||||
}
|
||||
@ -145,12 +90,7 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderId, currentUser, onEr
|
||||
<h2>[{order.reference}]</h2>
|
||||
<div className="grpBtn">
|
||||
{isPrivileged() &&
|
||||
<Select
|
||||
options={buildOptions()}
|
||||
onChange={option => handleAction(option)}
|
||||
value={currentAction}
|
||||
styles={customStyles}
|
||||
/>
|
||||
<OrderActions order={order} onSuccess={handleActionSuccess} onError={onError} />
|
||||
}
|
||||
{order?.invoice_id && (
|
||||
<a href={`/api/invoices/${order?.invoice_id}/download`}
|
||||
|
@ -8,6 +8,9 @@ class Orders::CancelOrderService
|
||||
order.state = 'canceled'
|
||||
ActiveRecord::Base.transaction do
|
||||
activity = order.order_activities.create(activity_type: 'canceled', operator_profile_id: current_user.invoicing_profile.id)
|
||||
order.order_items.each do |item|
|
||||
ProductService.update_stock(item.orderable, 'external', 'cancelled_by_customer', item.quantity, item.id)
|
||||
end
|
||||
order.save
|
||||
NotificationCenter.call type: 'notify_user_order_is_canceled',
|
||||
receiver: order.statistic_profile.user,
|
||||
|
@ -605,3 +605,21 @@ en:
|
||||
on_DATE_at_TIME: "on {DATE} at {TIME},"
|
||||
for_an_amount_of_AMOUNT: "for an amount of {AMOUNT}"
|
||||
and: 'and'
|
||||
order_actions:
|
||||
state:
|
||||
cart: 'Cart'
|
||||
in_progress: 'In progress'
|
||||
paid: "Paid"
|
||||
payment_failed: "Payment error"
|
||||
canceled: "Canceled"
|
||||
ready: "Ready"
|
||||
refunded: "Refunded"
|
||||
confirm: 'Confirm'
|
||||
confirmation_required: "Confirmation required"
|
||||
confirm_order_in_progress: "This order is in the process of being prepared ?"
|
||||
order_in_progress_success: "Order is under preparation"
|
||||
confirm_order_ready: "This order is ready ?"
|
||||
order_ready_note: ''
|
||||
order_ready_success: "Order is ready"
|
||||
confirm_order_canceled: "Do you want to cancel this order ?"
|
||||
order_canceled_success: "Order is canceled"
|
||||
|
Loading…
x
Reference in New Issue
Block a user