saleor-dashboard/src/orders/components/OrderRefundPage/form.tsx
2021-01-25 15:16:43 +01:00

205 lines
5.8 KiB
TypeScript

import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
import useFormset, {
FormsetChange,
FormsetData
} from "@saleor/hooks/useFormset";
import { OrderRefundData_order } from "@saleor/orders/types/OrderRefundData";
import { FulfillmentStatus } from "@saleor/types/globalTypes";
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
import React from "react";
import { refundFulfilledStatuses } from "./OrderRefundPage";
export enum OrderRefundType {
MISCELLANEOUS = "miscellaneous",
PRODUCTS = "products"
}
export enum OrderRefundAmountCalculationMode {
AUTOMATIC = "automatic",
MANUAL = "manual",
NONE = "none"
}
export interface OrderRefundData {
amount: number | string;
type: OrderRefundType;
refundShipmentCosts: boolean;
amountCalculationMode: OrderRefundAmountCalculationMode;
}
export interface OrderRefundHandlers {
changeRefundedProductQuantity: FormsetChange<string>;
setMaximalRefundedProductQuantities: () => void;
changeRefundedFulfilledProductQuantity: FormsetChange<string>;
setMaximalRefundedFulfilledProductQuantities: (fulfillmentId: string) => void;
}
export interface OrderRefundFormData extends OrderRefundData {
refundedProductQuantities: FormsetData<null, string>;
refundedFulfilledProductQuantities: FormsetData<null, string>;
}
export type OrderRefundSubmitData = OrderRefundFormData;
export interface UseOrderRefundFormResult {
change: FormChange;
data: OrderRefundFormData;
disabled: boolean;
handlers: OrderRefundHandlers;
hasChanged: boolean;
submit: () => Promise<boolean>;
}
interface OrderRefundFormProps {
children: (props: UseOrderRefundFormResult) => React.ReactNode;
order: OrderRefundData_order;
defaultType: OrderRefundType;
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise;
}
function getOrderRefundPageFormData(
defaultType: OrderRefundType
): OrderRefundData {
return {
amount: undefined,
amountCalculationMode: OrderRefundAmountCalculationMode.AUTOMATIC,
refundShipmentCosts: false,
type: defaultType
};
}
function useOrderRefundForm(
order: OrderRefundData_order,
defaultType: OrderRefundType,
onSubmit: (data: OrderRefundSubmitData) => SubmitPromise
): UseOrderRefundFormResult {
const [changed, setChanged] = React.useState(false);
const triggerChange = () => setChanged(true);
const form = useForm(getOrderRefundPageFormData(defaultType));
const refundedProductQuantities = useFormset<null, string>(
order?.lines
.filter(line => line.quantityFulfilled !== line.quantity)
.map(line => ({
data: null,
id: line.id,
label: null,
value: "0"
}))
);
const refundedFulfilledProductQuantities = useFormset<null, string>(
order?.fulfillments
.filter(({ status }) => refundFulfilledStatuses.includes(status))
.reduce(
(linesQty, fulfillemnt) =>
linesQty.concat(
fulfillemnt.lines.map(fulfillmentLine => ({
data: null,
id: fulfillmentLine.id,
label: null,
value: "0"
}))
),
[]
)
);
const handleChange: FormChange = (event, cb) => {
form.change(event, cb);
triggerChange();
};
const handleRefundedProductQuantityChange: FormsetChange<string> = (
id,
value
) => {
triggerChange();
refundedProductQuantities.change(id, value);
};
const handleRefundedFulFilledProductQuantityChange = (
id: string,
value: string
) => {
triggerChange();
refundedFulfilledProductQuantities.change(id, value);
};
const handleMaximalRefundedProductQuantitiesSet = () => {
const newQuantities: FormsetData<
null,
string
> = refundedProductQuantities.data.map(selectedLine => {
const line = order.lines.find(line => line.id === selectedLine.id);
return {
data: null,
id: line.id,
label: null,
value: (line.quantity - line.quantityFulfilled).toString()
};
});
refundedProductQuantities.set(newQuantities);
triggerChange();
};
const handleMaximalRefundedFulfilledProductQuantitiesSet = (
fulfillmentId: string
) => {
const fulfillment = order.fulfillments.find(
fulfillment => fulfillment.id === fulfillmentId
);
const newQuantities: FormsetData<
null,
string
> = refundedFulfilledProductQuantities.data.map(selectedLine => {
const line = fulfillment.lines.find(line => line.id === selectedLine.id);
if (line) {
return {
data: null,
id: line.id,
label: null,
value: line.quantity.toString()
};
}
return selectedLine;
});
refundedFulfilledProductQuantities.set(newQuantities);
triggerChange();
};
const data: OrderRefundFormData = {
...form.data,
refundedFulfilledProductQuantities: refundedFulfilledProductQuantities.data,
refundedProductQuantities: refundedProductQuantities.data
};
const submit = () => handleFormSubmit(data, onSubmit, setChanged);
const disabled = !order;
return {
change: handleChange,
data,
disabled,
handlers: {
changeRefundedFulfilledProductQuantity: handleRefundedFulFilledProductQuantityChange,
changeRefundedProductQuantity: handleRefundedProductQuantityChange,
setMaximalRefundedFulfilledProductQuantities: handleMaximalRefundedFulfilledProductQuantitiesSet,
setMaximalRefundedProductQuantities: handleMaximalRefundedProductQuantitiesSet
},
hasChanged: changed,
submit
};
}
const OrderRefundForm: React.FC<OrderRefundFormProps> = ({
children,
order,
defaultType,
onSubmit
}) => {
const props = useOrderRefundForm(order, defaultType, onSubmit);
return <form onSubmit={props.submit}>{children(props)}</form>;
};
OrderRefundForm.displayName = "OrderRefundForm";
export default OrderRefundForm;