Files
Fulfillment-Frontend/src/pages/CardsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx

298 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { FC } from "react";
import styles from "./ProductAndServiceTab.module.css";
import ProductView from "./components/ProductView/ProductView.tsx";
import {
Button,
Divider,
Flex,
rem,
ScrollArea,
Text,
Title,
} from "@mantine/core";
import CardServicesTable from "./components/DealServicesTable/CardServicesTable.tsx";
import useCardProductAndServiceTabState from "./hooks/useProductAndServiceTabState.tsx";
import { modals } from "@mantine/modals";
import {
BillingService,
CardProductSchema,
CardService,
GetServiceKitSchema,
ProductSchema,
ProductService,
} from "../../../../client";
import { notifications } from "../../../../shared/lib/notifications.ts";
import { CreateProductRequest } from "../../../ProductsPage/types.ts";
import classNames from "classnames";
const ProductAndServiceTab: FC = () => {
const { cardState, cardServicesState, cardProductsState } =
useCardProductAndServiceTabState();
const isLocked = Boolean(cardState.card?.billRequest || cardState.card?.group?.billRequest);
const onAddProductClick = () => {
if (!cardProductsState.onCreate || !cardState.card || !cardState.card.clientId) return;
const productIds = cardState.card.products.map(
product => product.product.id
);
modals.openContextModal({
modal: "addCardProduct",
innerProps: {
onCreate: cardProductsState.onCreate,
clientId: cardState.card.clientId,
productIds: productIds,
},
withCloseButton: false,
});
};
const getTotalPrice = () => {
if (!cardState.card) return 0;
const productServicesPrice = cardState.card.products.reduce(
(acc, row) =>
acc +
row.services.reduce(
(acc2, row2) => acc2 + row2.price * row.quantity,
0
),
0
);
const cardServicesPrice = cardState.card.services.reduce(
(acc, row) => acc + row.price * row.quantity,
0
);
return cardServicesPrice + productServicesPrice;
};
const onCopyServices = (
sourceProduct: CardProductSchema,
destinationProducts: CardProductSchema[]
) => {
if (!cardState.card) return;
CardService.copyProductServices({
requestBody: {
cardId: cardState.card.id,
destinationProductIds: destinationProducts.map(
product => product.product.id
),
sourceProductId: sourceProduct.product.id,
},
}).then(async ({ ok, message }) => {
notifications.guess(ok, { message });
if (!ok) return;
await cardState.refetch();
});
};
const onCopyServicesClick = (product: CardProductSchema) => {
modals.openContextModal({
modal: "selectCardProductsModal",
title: "Дублирование услуг",
size: "lg",
innerProps: {
cardProducts: cardState.card?.products || [],
cardProduct: product,
onSelect: onCopyServices,
},
withCloseButton: false,
});
};
const onKitAdd = (item: CardProductSchema, kit: GetServiceKitSchema) => {
if (!cardState.card) return;
CardService.addKitToCardProduct({
requestBody: {
cardId: cardState.card.id,
kitId: kit.id,
productId: item.product.id,
},
}).then(async ({ ok, message }) => {
notifications.guess(ok, { message });
if (!ok) return;
await cardState.refetch();
});
};
const onCardKitAdd = (kit: GetServiceKitSchema) => {
if (!cardState.card) return;
CardService.addKitToCard({
requestBody: {
cardId: cardState.card.id,
kitId: kit.id,
},
}).then(async ({ ok, message }) => {
notifications.guess(ok, { message });
if (!ok) return;
await cardState.refetch();
});
};
const onCreateProduct = (newProduct: CreateProductRequest) => {
ProductService.createProduct({
requestBody: newProduct,
}).then(({ ok, message }) => {
notifications.guess(ok, { message: message });
});
};
const onCreateProductClick = () => {
if (!cardState.card || !cardState.card.clientId) return;
modals.openContextModal({
modal: "createProduct",
title: "Создание товара",
withCloseButton: false,
innerProps: {
clientId: cardState.card.clientId,
onCreate: onCreateProduct,
},
});
};
const onProductEdit = (product: ProductSchema) => {
ProductService.updateProduct({ requestBody: { product } }).then(
async ({ ok, message }) => {
notifications.guess(ok, { message });
if (!ok) return;
await cardState.refetch();
}
);
};
const onCreateBillClick = () => {
if (!cardState.card) return;
const cardId = cardState.card.id;
modals.openConfirmModal({
withCloseButton: false,
size: "xl",
children: (
<Text style={{ textAlign: "justify" }}>
Создание заявки на выставление счета, подтвержденное
нажатием кнопки "Выставить", заблокирует возможность
редактирования товаров и услуг сделки. Пожалуйста, проверьте
всю информацию на точность и полноту перед подтверждением.
</Text>
),
onConfirm: () => {
BillingService.createDealBill({
requestBody: {
cardId,
},
}).then(async ({ ok, message }) => {
notifications.guess(ok, { message });
if (ok)
notifications.success({
message:
"Ссылка на оплату доступна во вкладе общее",
});
await cardState.refetch();
});
},
labels: {
confirm: "Выставить",
cancel: "Отмена",
},
});
};
const onCancelBillClick = () => {
if (!cardState.card) return;
const cardId = cardState.card.id;
modals.openConfirmModal({
withCloseButton: false,
children: (
<Text style={{ textAlign: "justify" }}>
Вы уверены что хотите отозвать заявку на оплату?
</Text>
),
onConfirm: () => {
BillingService.cancelDealBill({
requestBody: {
cardId,
},
}).then(async ({ ok, message }) => {
notifications.guess(ok, { message });
await cardState.refetch();
});
},
labels: {
confirm: "Отозвать",
cancel: "Отмена",
},
});
};
return (
<div
className={classNames(
styles["container"],
cardState.card?.billRequest && styles["container-disabled"]
)}>
<div className={styles["products-list"]}>
<ScrollArea offsetScrollbars>
{cardState.card?.products.map(product => (
<ProductView
onProductEdit={onProductEdit}
onKitAdd={onKitAdd}
onCopyServices={onCopyServicesClick}
key={product.product.id}
product={product}
onChange={cardProductsState.onChange}
onDelete={cardProductsState.onDelete}
/>
))}
</ScrollArea>
</div>
<div className={styles["card-container"]}>
<ScrollArea offsetScrollbars>
<Flex
direction={"column"}
className={styles["card-container-wrapper"]}>
<CardServicesTable
onKitAdd={onCardKitAdd}
{...cardServicesState}
/>
<Divider my={rem(15)} />
<div className={styles["card-container-buttons"]}>
<Button
disabled={isLocked}
variant={"default"}
fullWidth
onClick={onCreateProductClick}>
Создать товар
</Button>
<Button
disabled={isLocked}
onClick={onAddProductClick}
variant={"default"}
fullWidth>
Добавить товар
</Button>
</div>
<Divider my={rem(15)} />
<div className={styles["card-container-buttons"]}>
{isLocked ? (
<Button
onClick={onCancelBillClick}
color={"red"}>
Отозвать счет
</Button>
) : (
<Button
disabled={isLocked}
onClick={onCreateBillClick}
variant={"default"}
fullWidth>
Выставить счет
</Button>
)}
</div>
</Flex>
<Flex
direction={"column"}
className={styles["card-container-wrapper"]}>
<Title order={3}>
Общая стоимость всех услуг:{" "}
{getTotalPrice().toLocaleString("ru")}
</Title>
</Flex>
</ScrollArea>
</div>
</div>
);
};
export default ProductAndServiceTab;