From 17e6c5f23a0d1582375ddb851a3b52b6ded6ab9a Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Sat, 1 Mar 2025 17:05:27 +0400 Subject: [PATCH] feat: a few shipping products in box --- src/client/index.ts | 5 +- src/client/models/BoxSchema.ts | 5 +- ...pdateBoxRequest.ts => CreateBoxRequest.ts} | 5 +- ...ateBoxResponse.ts => CreateBoxResponse.ts} | 2 +- .../models/CreateShippingProductSchema.ts | 3 +- src/client/models/ShippingProductSchema.ts | 3 +- src/client/models/UpdateBoxSchema.ts | 10 - src/client/services/ShippingService.ts | 14 +- .../utils/getAttributesFromCard.ts | 6 +- src/components/InlineButton/InlineButton.tsx | 2 +- .../tabs/ShippingTab/ShippingTab.module.css | 18 ++ .../ShippingTab/components/BoxesTable.tsx | 151 +++++++++----- .../components/InlineShippingButton.tsx | 26 +++ .../components/ShippingProductsTable.tsx | 89 ++------- .../ShippingTab/components/ShippingTree.tsx | 189 +++++++++--------- .../hooks/shippingTableColumns.tsx | 119 +++++++---- .../tabs/ShippingTab/hooks/useShipping.tsx | 30 ++- .../modals/ShippingProductModal.tsx | 36 +--- .../ShippingTab/types/ShippingProductData.tsx | 17 +- .../ShippingTab/utils/getRestProducts.tsx | 31 ++- 20 files changed, 405 insertions(+), 356 deletions(-) rename src/client/models/{UpdateBoxRequest.ts => CreateBoxRequest.ts} (62%) rename src/client/models/{UpdateBoxResponse.ts => CreateBoxResponse.ts} (83%) delete mode 100644 src/client/models/UpdateBoxSchema.ts create mode 100644 src/pages/CardsPage/tabs/ShippingTab/ShippingTab.module.css create mode 100644 src/pages/CardsPage/tabs/ShippingTab/components/InlineShippingButton.tsx diff --git a/src/client/index.ts b/src/client/index.ts index 2eb2b8b..ddff108 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -132,6 +132,8 @@ export type { CreateBoardRequest } from './models/CreateBoardRequest'; export type { CreateBoardResponse } from './models/CreateBoardResponse'; export type { CreateBoxInCardSchema } from './models/CreateBoxInCardSchema'; export type { CreateBoxInPalletSchema } from './models/CreateBoxInPalletSchema'; +export type { CreateBoxRequest } from './models/CreateBoxRequest'; +export type { CreateBoxResponse } from './models/CreateBoxResponse'; export type { CreateCardBillRequest } from './models/CreateCardBillRequest'; export type { CreateCardBillResponse } from './models/CreateCardBillResponse'; export type { CreateCardGroupRequest } from './models/CreateCardGroupRequest'; @@ -354,9 +356,6 @@ export type { UpdateBoardOrderRequest } from './models/UpdateBoardOrderRequest'; export type { UpdateBoardOrderResponse } from './models/UpdateBoardOrderResponse'; export type { UpdateBoardRequest } from './models/UpdateBoardRequest'; export type { UpdateBoardResponse } from './models/UpdateBoardResponse'; -export type { UpdateBoxRequest } from './models/UpdateBoxRequest'; -export type { UpdateBoxResponse } from './models/UpdateBoxResponse'; -export type { UpdateBoxSchema } from './models/UpdateBoxSchema'; export type { UpdateDepartmentRequest } from './models/UpdateDepartmentRequest'; export type { UpdateDepartmentResponse } from './models/UpdateDepartmentResponse'; export type { UpdateDepartmentSectionRequest } from './models/UpdateDepartmentSectionRequest'; diff --git a/src/client/models/BoxSchema.ts b/src/client/models/BoxSchema.ts index a4e63f7..f147881 100644 --- a/src/client/models/BoxSchema.ts +++ b/src/client/models/BoxSchema.ts @@ -2,12 +2,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ProductSchema } from './ProductSchema'; +import type { ShippingProductSchema } from './ShippingProductSchema'; export type BoxSchema = { id: number; - quantity: number; - product: (ProductSchema | null); palletId: (number | null); cardId: (number | null); + shippingProducts: Array; }; diff --git a/src/client/models/UpdateBoxRequest.ts b/src/client/models/CreateBoxRequest.ts similarity index 62% rename from src/client/models/UpdateBoxRequest.ts rename to src/client/models/CreateBoxRequest.ts index 5af81f0..d008f49 100644 --- a/src/client/models/UpdateBoxRequest.ts +++ b/src/client/models/CreateBoxRequest.ts @@ -4,8 +4,7 @@ /* eslint-disable */ import type { CreateBoxInCardSchema } from './CreateBoxInCardSchema'; import type { CreateBoxInPalletSchema } from './CreateBoxInPalletSchema'; -import type { UpdateBoxSchema } from './UpdateBoxSchema'; -export type UpdateBoxRequest = { - data: (CreateBoxInCardSchema | CreateBoxInPalletSchema | UpdateBoxSchema); +export type CreateBoxRequest = { + data: (CreateBoxInCardSchema | CreateBoxInPalletSchema); }; diff --git a/src/client/models/UpdateBoxResponse.ts b/src/client/models/CreateBoxResponse.ts similarity index 83% rename from src/client/models/UpdateBoxResponse.ts rename to src/client/models/CreateBoxResponse.ts index da73fca..fd8d25d 100644 --- a/src/client/models/UpdateBoxResponse.ts +++ b/src/client/models/CreateBoxResponse.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type UpdateBoxResponse = { +export type CreateBoxResponse = { ok: boolean; message: string; }; diff --git a/src/client/models/CreateShippingProductSchema.ts b/src/client/models/CreateShippingProductSchema.ts index 6ebe1b5..062b4d0 100644 --- a/src/client/models/CreateShippingProductSchema.ts +++ b/src/client/models/CreateShippingProductSchema.ts @@ -5,6 +5,7 @@ export type CreateShippingProductSchema = { productId: (number | null); quantity: (number | null); - palletId: number; + palletId?: (number | null); + boxId?: (number | null); }; diff --git a/src/client/models/ShippingProductSchema.ts b/src/client/models/ShippingProductSchema.ts index 858c323..41b9e6d 100644 --- a/src/client/models/ShippingProductSchema.ts +++ b/src/client/models/ShippingProductSchema.ts @@ -7,6 +7,7 @@ export type ShippingProductSchema = { id: number; quantity: number; product: ProductSchema; - palletId: number; + palletId: (number | null); + boxId: (number | null); }; diff --git a/src/client/models/UpdateBoxSchema.ts b/src/client/models/UpdateBoxSchema.ts deleted file mode 100644 index 6870bbd..0000000 --- a/src/client/models/UpdateBoxSchema.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do not edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type UpdateBoxSchema = { - productId: (number | null); - quantity: (number | null); - boxId: (number | null); -}; - diff --git a/src/client/services/ShippingService.ts b/src/client/services/ShippingService.ts index 304e767..1575657 100644 --- a/src/client/services/ShippingService.ts +++ b/src/client/services/ShippingService.ts @@ -2,12 +2,12 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { CreateBoxRequest } from '../models/CreateBoxRequest'; +import type { CreateBoxResponse } from '../models/CreateBoxResponse'; import type { CreatePalletResponse } from '../models/CreatePalletResponse'; import type { DeleteBoxResponse } from '../models/DeleteBoxResponse'; import type { DeletePalletResponse } from '../models/DeletePalletResponse'; import type { DeleteShippingProductResponse } from '../models/DeleteShippingProductResponse'; -import type { UpdateBoxRequest } from '../models/UpdateBoxRequest'; -import type { UpdateBoxResponse } from '../models/UpdateBoxResponse'; import type { UpdateShippingProductRequest } from '../models/UpdateShippingProductRequest'; import type { UpdateShippingProductResponse } from '../models/UpdateShippingProductResponse'; import type { CancelablePromise } from '../core/CancelablePromise'; @@ -98,15 +98,15 @@ export class ShippingService { }); } /** - * Update Box - * @returns UpdateBoxResponse Successful Response + * Create Box + * @returns CreateBoxResponse Successful Response * @throws ApiError */ - public static updateBox({ + public static createBox({ requestBody, }: { - requestBody: UpdateBoxRequest, - }): CancelablePromise { + requestBody: CreateBoxRequest, + }): CancelablePromise { return __request(OpenAPI, { method: 'POST', url: '/shipping/box', diff --git a/src/components/CardAttributeFields/utils/getAttributesFromCard.ts b/src/components/CardAttributeFields/utils/getAttributesFromCard.ts index 098a474..f55b4a6 100644 --- a/src/components/CardAttributeFields/utils/getAttributesFromCard.ts +++ b/src/components/CardAttributeFields/utils/getAttributesFromCard.ts @@ -3,18 +3,14 @@ import { CardSchema } from "../../../client"; const DATETIME_TYPES = ["datetime", "date"]; const getAttributesFromCard = (card: CardSchema) => { - console.log("getAttributesFromCard"); - return card.attributes.reduce( (values, cardAttribute) => { let value: boolean | number | string | null | Date = cardAttribute.value; - console.log(cardAttribute.attribute.type.type); + if (DATETIME_TYPES.includes(cardAttribute.attribute.type.type) && value !== null) { value = new Date(value as string); } - console.log("cardAttrValue", value); - console.log("value type", typeof value); return { ...values, [cardAttribute.attribute.name]: value, diff --git a/src/components/InlineButton/InlineButton.tsx b/src/components/InlineButton/InlineButton.tsx index e1dac23..be89720 100644 --- a/src/components/InlineButton/InlineButton.tsx +++ b/src/components/InlineButton/InlineButton.tsx @@ -13,7 +13,7 @@ const InlineButton = ({ children, onClick, ...props }: Props) => { onClick={onClick} {...props} > - + {children} diff --git a/src/pages/CardsPage/tabs/ShippingTab/ShippingTab.module.css b/src/pages/CardsPage/tabs/ShippingTab/ShippingTab.module.css new file mode 100644 index 0000000..70ae7c9 --- /dev/null +++ b/src/pages/CardsPage/tabs/ShippingTab/ShippingTab.module.css @@ -0,0 +1,18 @@ +.icon { + width: rem(13px); + height: auto; + vertical-align: rem(-1px); + margin-right: rem(8px); +} + +.expandIcon { + transition: transform 0.2s; +} + +.expandIconRotated { + transform: rotate(90deg); +} + +.productsTableBorder { + border-bottom: solid 1px var(--mantine-color-dark-5); +} diff --git a/src/pages/CardsPage/tabs/ShippingTab/components/BoxesTable.tsx b/src/pages/CardsPage/tabs/ShippingTab/components/BoxesTable.tsx index 1e3e458..798c495 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/components/BoxesTable.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/components/BoxesTable.tsx @@ -1,27 +1,31 @@ -import useShippingTableColumns from "../hooks/shippingTableColumns.tsx"; -import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx"; import { BoxSchema, ShippingService } from "../../../../../client"; -import { ActionIcon, Flex, Tooltip } from "@mantine/core"; -import { IconEdit, IconTrash } from "@tabler/icons-react"; -import { MRT_TableOptions } from "mantine-react-table"; -import { modals } from "@mantine/modals"; -import { useCardPageContext } from "../../../contexts/CardPageContext.tsx"; +import { IconBox, IconChevronRight, IconPlus, IconTrash } from "@tabler/icons-react"; import useUpdateCard from "../hooks/useUpdateCard.tsx"; import { notifications } from "../../../../../shared/lib/notifications.ts"; +import { DataTable } from "mantine-datatable"; +import clsx from "clsx"; +import classes from "../ShippingTab.module.css"; +import "mantine-datatable/styles.css"; +import { useState } from "react"; +import ShippingProductsTable from "./ShippingProductsTable.tsx"; +import { Group, rem, Text } from "@mantine/core"; +import { ShippingProductParentData } from "../types/ShippingProductData.tsx"; +import { modals } from "@mantine/modals"; +import InlineShippingButton from "./InlineShippingButton.tsx"; type Props = { items: BoxSchema[]; + onCreateShippingProduct: (values: ShippingProductParentData) => void; } -const BoxesTable = ({ items }: Props) => { - const columns = useShippingTableColumns({ isBox: true }); +const BoxesTable = ({ items, onCreateShippingProduct }: Props) => { const { update } = useUpdateCard(); - const { selectedCard: card } = useCardPageContext(); + const [boxIds, setBoxIds] = useState([]); - const onDeleteClick = (box: BoxSchema) => { + const onDeleteBox = (boxId: number) => { ShippingService.deleteBox({ - boxId: box.id, + boxId, }) .then(({ ok, message }) => { notifications.guess(ok, { message }); @@ -30,55 +34,92 @@ const BoxesTable = ({ items }: Props) => { .catch(err => console.log(err)); }; - const onEditClick = (box: BoxSchema) => { - if (!card) return; - modals.openContextModal({ - modal: "shippingProductModal", - title: "Редактирование короба", - withCloseButton: false, - innerProps: { - card, - updateOnSubmit: update, - isBox: true, - shippingData: { - boxId: box.id, - productId: box.product?.id, - quantity: box.quantity, - }, - }, + const onDeleteBoxClick = (box: BoxSchema) => { + if (box.shippingProducts.length === 0) { + onDeleteBox(box.id); + return; + } + + modals.openConfirmModal({ + title: "Удаление короба", + children: Вы уверены что хотите удалить короб?, + labels: { confirm: "Да", cancel: "Нет" }, + confirmProps: { color: "red" }, + onConfirm: () => onDeleteBox(box.id), }); }; + const getBoxContent = (box: BoxSchema) => { + if (box.shippingProducts.length === 0) { + return ( + Пустой + ); + } + + return ( + + ); + }; + + const getBoxActions = (box: BoxSchema) => { + return ( + + onCreateShippingProduct({ boxId: box.id })}> + + Товар + + onDeleteBoxClick(box)}> + + + + ); + }; + + const isBoxExpandable = (box: BoxSchema) => { + const isExpandable = box.shippingProducts.length > 0; + if (!isExpandable && boxIds.includes(box.id)) { + setBoxIds(boxIds.filter(boxId => boxId !== box.id)); + } + return isExpandable; + }; + return ( - ( - - - onDeleteClick(row.original)} - variant={"default"}> - - - - - onEditClick(row.original)} - variant={"default"}> - - - - + accessor: "id", + title: "Короб", + noWrap: true, + render: (box) => ( + <> + {isBoxExpandable(box) && ( + + )} + + Короб К{box.id} + ), - } as MRT_TableOptions - } + }, + { + accessor: "actions", + title: "", + width: "0%", + render: getBoxActions, + }, + ]} + records={items?.sort((a, b) => a.id - b.id)} + rowExpansion={{ + allowMultiple: true, + expanded: { recordIds: boxIds, onRecordIdsChange: setBoxIds }, + expandable: ({ record }) => isBoxExpandable(record), + content: ({ record }) => getBoxContent(record), + }} /> ); }; diff --git a/src/pages/CardsPage/tabs/ShippingTab/components/InlineShippingButton.tsx b/src/pages/CardsPage/tabs/ShippingTab/components/InlineShippingButton.tsx new file mode 100644 index 0000000..ab70091 --- /dev/null +++ b/src/pages/CardsPage/tabs/ShippingTab/components/InlineShippingButton.tsx @@ -0,0 +1,26 @@ +import React, { ReactNode } from "react"; +import { Button, ButtonProps, Group } from "@mantine/core"; + +interface Props extends ButtonProps { + children?: ReactNode; + onClick?: () => void; +} + +const InlineShippingButton = ({ children, onClick, ...props }: Props) => { + return ( + + ); +}; + +export default InlineShippingButton; diff --git a/src/pages/CardsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx b/src/pages/CardsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx index b919c43..ee8485d 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx @@ -1,13 +1,10 @@ import useShippingTableColumns from "../hooks/shippingTableColumns.tsx"; -import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx"; -import { ShippingProductSchema, ShippingService } from "../../../../../client"; -import { ActionIcon, Flex, Tooltip } from "@mantine/core"; -import { IconEdit, IconTrash } from "@tabler/icons-react"; -import { MRT_TableOptions } from "mantine-react-table"; -import { notifications } from "../../../../../shared/lib/notifications.ts"; -import useUpdateCard from "../hooks/useUpdateCard.tsx"; -import { modals } from "@mantine/modals"; -import { useCardPageContext } from "../../../contexts/CardPageContext.tsx"; +import { ShippingProductSchema } from "../../../../../client"; +import { Box } from "@mantine/core"; +import { DataTable } from "mantine-datatable"; +import clsx from "clsx"; +import "mantine-datatable/styles.css"; +import classes from "../ShippingTab.module.css"; type Props = { @@ -15,72 +12,18 @@ type Props = { } const ShippingProductsTable = ({ items }: Props) => { - const columns = useShippingTableColumns({ isBox: false }); - const { update } = useUpdateCard(); - const { selectedCard: card } = useCardPageContext(); - - const onDeleteClick = (shippingProduct: ShippingProductSchema) => { - ShippingService.deleteShippingProduct({ - shippingProductId: shippingProduct.id, - }) - .then(({ ok, message }) => { - notifications.guess(ok, { message }); - update(); - }) - .catch(err => console.log(err)); - }; - - const onEditClick = (shippingProduct: ShippingProductSchema) => { - if (!card) return; - modals.openContextModal({ - modal: "shippingProductModal", - title: "Редактирование товара на паллете", - withCloseButton: false, - innerProps: { - card, - updateOnSubmit: update, - isBox: false, - shippingData: { - shippingProductId: shippingProduct.id, - productId: shippingProduct.product.id, - quantity: shippingProduct.quantity, - }, - }, - }); - }; + const columns = useShippingTableColumns(); return ( - ( - - - onDeleteClick(row.original)} - variant={"default"}> - - - - - onEditClick(row.original)} - variant={"default"}> - - - - - ), - } as MRT_TableOptions - } - /> + + + ); }; diff --git a/src/pages/CardsPage/tabs/ShippingTab/components/ShippingTree.tsx b/src/pages/CardsPage/tabs/ShippingTab/components/ShippingTree.tsx index 885d25d..8b0c3be 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/components/ShippingTree.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/components/ShippingTree.tsx @@ -1,10 +1,15 @@ import { useCardPageContext } from "../../../contexts/CardPageContext.tsx"; -import { Accordion, ActionIcon, Button, Center, Group, rem, Stack, Title, Tooltip } from "@mantine/core"; +import { Flex, rem, Stack } from "@mantine/core"; import { BoxSchema, PalletSchema, ShippingProductSchema } from "../../../../../client"; import ShippingProductsTable from "./ShippingProductsTable.tsx"; import BoxesTable from "./BoxesTable.tsx"; -import { IconBox, IconPlus, IconSpace, IconTrash } from "@tabler/icons-react"; +import { IconChevronRight, IconPlus, IconSpace, IconTrash } from "@tabler/icons-react"; import useShipping from "../hooks/useShipping.tsx"; +import { DataTable } from "mantine-datatable"; +import clsx from "clsx"; +import "mantine-datatable/styles.css"; +import classes from "../ShippingTab.module.css"; +import InlineShippingButton from "./InlineShippingButton.tsx"; const ShippingTree = () => { const { selectedCard: card } = useCardPageContext(); @@ -14,91 +19,59 @@ const ShippingTree = () => { onCreateShippingProduct, onDeletePalletClick, palletIds, + setPalletIds, } = useShipping(); const sortById = (data?: PalletSchema[] | BoxSchema[] | ShippingProductSchema[]) => { return data?.sort((a, b) => a.id - b.id); }; - const getPallets = () => { - const sortedPallets = sortById(card?.pallets) as PalletSchema[]; - const pallets = sortedPallets?.map((pallet => { - palletIds.push(pallet.id.toString()); - return ( - -
- }> - Паллет - П{pallet.id} - - {removePalletButton(pallet.id)} -
- - {getPalletContent(pallet)} - -
- ); - })) ?? []; - - if (card?.boxes && card?.boxes.length > 0) { - const boxes = card?.boxes.sort((b1, b2) => (b1.id - b2.id)); - const itemValue = "noPallets"; - const boxesWithoutPallet = ( - - }> - Короба без паллетов - - - - - - ); - pallets.unshift(boxesWithoutPallet); - palletIds.push(itemValue); - } - - return pallets; - }; - - const removePalletButton = (palletId: number) => { + const removePalletButton = (pallet: PalletSchema) => { return ( - - onDeletePalletClick(palletId)} - mx={"md"} - > - - - + onDeletePalletClick(pallet)}> + + ); }; const createBoxOrShippingProductButton = (palletId: number, isBox: boolean) => { - const createButtonLabel = isBox ? "Добавить короб" : "Добавить товар"; + const createButtonLabel = isBox ? "Короб" : "Товар"; return ( - + + {createButtonLabel} + ); }; const getPalletContent = (pallet: PalletSchema) => { + const isBox = pallet.boxes.length > 0; + + const boxes = sortById(pallet.boxes) as BoxSchema[]; + const shippingProducts = sortById(pallet.shippingProducts) as ShippingProductSchema[]; + + if (isBox) { + return ( + + ); + } + return ( + + ); + }; + + const getPalletActions = (pallet: PalletSchema) => { const isEmpty = pallet.boxes.length === 0 && pallet.shippingProducts.length === 0; const isBox = pallet.boxes.length > 0; - const title = isEmpty ? "Пустой" : isBox ? "Короба" : "Товары"; let palletButtons; if (isEmpty) { @@ -112,39 +85,77 @@ const ShippingTree = () => { ]; } - const boxes = sortById(pallet.boxes) as BoxSchema[]; - const shippingProducts = sortById(pallet.shippingProducts) as ShippingProductSchema[]; - - let table; - if (!isEmpty) { - if (isBox) { - table = (); - } else { - table = (); - } - } - return ( - - - {title} - - {...palletButtons} - - - {table} - + + {removePalletButton(pallet)} + {...palletButtons} + ); }; + const isPalletExpandable = (pallet: PalletSchema) => { + const isExpandable = pallet.boxes.length !== 0 || pallet.shippingProducts.length !== 0; + if (!isExpandable && palletIds.includes(pallet.id)) { + setPalletIds(palletIds.filter(palletId => palletId !== pallet.id)); + } + return isExpandable; + }; + + if (card?.boxes?.length === 0 && card?.pallets?.length === 0) { + return; + } + return ( - - {getPallets()} - + + {card?.boxes && ( + + )} + { + const isExpandable = isPalletExpandable(pallet); + + return ( + <> + {isExpandable && ( + + )} + + Паллет П{pallet.id} + + ); + }, + }, + { + accessor: "actions", + title: "", + width: "0%", + render: getPalletActions, + }, + ]} + records={card?.pallets?.sort((a, b) => a.id - b.id)} + rowExpansion={{ + allowMultiple: true, + expanded: { recordIds: palletIds, onRecordIdsChange: setPalletIds }, + expandable: ({ record }) => isPalletExpandable(record), + content: ({ record }) => getPalletContent(record), + }} + /> + ); }; diff --git a/src/pages/CardsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx b/src/pages/CardsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx index ec38504..a2e9cbb 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx @@ -1,44 +1,89 @@ -import { useMemo } from "react"; -import { MRT_ColumnDef, MRT_RowData } from "mantine-react-table"; +import { DataTableColumn } from "mantine-datatable"; +import { ShippingProductSchema, ShippingService } from "../../../../../client"; +import { ActionIcon, Flex, Tooltip } from "@mantine/core"; +import { IconEdit, IconTrash } from "@tabler/icons-react"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; +import { modals } from "@mantine/modals"; +import useUpdateCard from "./useUpdateCard.tsx"; +import { useCardPageContext } from "../../../contexts/CardPageContext.tsx"; -type Props = { - isBox: boolean; -} +const useShippingTableColumns = () => { + const { update } = useUpdateCard(); + const { selectedCard: card } = useCardPageContext(); -const useShippingTableColumns = ({ isBox }: Props) => { - const hideBoxColumns = ["id"]; + const onDeleteClick = (shippingProduct: ShippingProductSchema) => { + ShippingService.deleteShippingProduct({ + shippingProductId: shippingProduct.id, + }) + .then(({ ok, message }) => { + notifications.guess(ok, { message }); + update(); + }) + .catch(err => console.log(err)); + }; - return useMemo[]>( - () => [ - { - header: "ID", - accessorKey: "id", - Cell: ({ row }) => `K${row.original.id}`, + const onEditClick = (shippingProduct: ShippingProductSchema) => { + if (!card) return; + modals.openContextModal({ + modal: "shippingProductModal", + title: "Редактирование товара", + withCloseButton: false, + innerProps: { + card, + updateOnSubmit: update, + shippingData: { + shippingProductId: shippingProduct.id, + productId: shippingProduct.product.id, + quantity: shippingProduct.quantity, + }, }, - { - header: "Название", - accessorKey: "product.name", - Cell: ({ row }) => row.original.product?.name ?? "-", - }, - { - header: "Артикул", - accessorKey: "product.article", - Cell: ({ row }) => row.original.product?.article ?? "-", - }, - { - header: "Размер", - accessorKey: "product.size", - Cell: ({ row }) => row.original.product?.size ?? "-", - }, - { - header: "Количество", - accessorKey: "quantity", - }, - ], - [], - ).filter( - columnDef => isBox || !hideBoxColumns.includes(columnDef.accessorKey || ""), - ); + }); + }; + + return [ + { + title: "Название", + accessor: "product.name", + render: shippingProduct => shippingProduct.product?.name ?? "-", + }, + { + title: "Артикул", + accessor: "product.article", + render: shippingProduct => shippingProduct.product?.article ?? "-", + }, + { + title: "Размер", + accessor: "product.size", + render: shippingProduct => shippingProduct.product?.size ?? "-", + }, + { + title: "Количество", + accessor: "quantity", + }, + { + accessor: "actions", + title: "", + width: "0%", + render: shippingProduct => ( + + + onDeleteClick(shippingProduct)} + variant={"default"}> + + + + + onEditClick(shippingProduct)} + variant={"default"}> + + + + + ), + }, + ] as DataTableColumn[]; }; export default useShippingTableColumns; diff --git a/src/pages/CardsPage/tabs/ShippingTab/hooks/useShipping.tsx b/src/pages/CardsPage/tabs/ShippingTab/hooks/useShipping.tsx index cae08d5..d1864f4 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/hooks/useShipping.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/hooks/useShipping.tsx @@ -1,14 +1,20 @@ import { useCardPageContext } from "../../../contexts/CardPageContext.tsx"; -import { CreateBoxInCardSchema, CreateBoxInPalletSchema, ShippingService } from "../../../../../client"; +import { + CreateBoxInCardSchema, + CreateBoxInPalletSchema, PalletSchema, + ShippingService, +} from "../../../../../client"; import { notifications } from "../../../../../shared/lib/notifications.ts"; import { modals } from "@mantine/modals"; import { Text } from "@mantine/core"; import useUpdateCard from "./useUpdateCard.tsx"; +import { useState } from "react"; +import { ShippingProductParentData } from "../types/ShippingProductData.tsx"; const useShipping = () => { const { selectedCard: card } = useCardPageContext(); const { update } = useUpdateCard(); - const palletIds: string[] = []; + const [palletIds, setPalletIds] = useState([]); const onCreatePalletClick = () => { if (!card) return; @@ -34,19 +40,24 @@ const useShipping = () => { .catch(err => console.log(err)); }; - const onDeletePalletClick = (palletId: number) => { + const onDeletePalletClick = (pallet: PalletSchema) => { if (!card) return; + if (pallet.shippingProducts.length === 0 && pallet.boxes.length === 0) { + onDeletePallet(pallet.id); + return; + } + modals.openConfirmModal({ title: "Удаление паллета", children: Вы уверены что хотите удалить паллет?, labels: { confirm: "Да", cancel: "Нет" }, confirmProps: { color: "red" }, - onConfirm: () => onDeletePallet(palletId), + onConfirm: () => onDeletePallet(pallet.id), }); }; const onCreateBox = (data: CreateBoxInPalletSchema | CreateBoxInCardSchema) => { - ShippingService.updateBox({ + ShippingService.createBox({ requestBody: { data, }, @@ -66,18 +77,20 @@ const useShipping = () => { onCreateBox({ palletId }); }; - const onCreateShippingProduct = (palletId: number) => { + const onCreateShippingProduct = ({ palletId, boxId }: ShippingProductParentData) => { if (!card) return; + const postfix = palletId ? "на паллет" : "в короб"; + modals.openContextModal({ modal: "shippingProductModal", - title: "Добавление товара на паллет", + title: "Добавление товара " + postfix, withCloseButton: false, innerProps: { card, updateOnSubmit: update, - isBox: false, shippingData: { palletId, + boxId, productId: null, quantity: null, }, @@ -92,6 +105,7 @@ const useShipping = () => { onCreatePalletClick, onDeletePalletClick, palletIds, + setPalletIds, }; }; diff --git a/src/pages/CardsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx b/src/pages/CardsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx index 1225cf7..192eb82 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx @@ -3,14 +3,11 @@ import { ContextModalProps } from "@mantine/modals"; import { Button, Flex, NumberInput, rem, Text } from "@mantine/core"; import getRestProducts from "../utils/getRestProducts.tsx"; import { - CreateBoxInCardSchema, - CreateBoxInPalletSchema, - CreateShippingProductSchema, CardProductSchema, CardSchema, + CreateShippingProductSchema, ProductSchema, ShippingService, - UpdateBoxSchema, UpdateShippingProductSchema, } from "../../../../../client"; import { notifications } from "../../../../../shared/lib/notifications.ts"; @@ -22,7 +19,6 @@ import ShippingProductSelect from "../components/ShippingProductSelect.tsx"; type Props = { updateOnSubmit: () => void; card: CardSchema; - isBox: boolean; shippingData: Partial; } @@ -65,31 +61,13 @@ const ShippingProductModal = ({ useEffect(() => { const data = getRestProducts({ card: innerProps.card, - unaccountedValues: innerProps.shippingData as UpdateShippingProductSchema | UpdateBoxSchema, + shippingProductId: (innerProps.shippingData as UpdateShippingProductSchema).shippingProductId, }); setRestProducts(data.restProducts); setRestProductSelectData(data.restProductsSelectData); }, [innerProps.card]); - const updateBox = () => { - const data = { - ...innerProps.shippingData, - ...form.values, - productId: form.values.product?.id, - } as CreateBoxInPalletSchema | CreateBoxInCardSchema | UpdateBoxSchema; - - ShippingService.updateBox({ - requestBody: { data }, - }) - .then(({ ok, message }) => { - notifications.guess(ok, { message: message }); - innerProps.updateOnSubmit(); - if (ok) context.closeContextModal(id); - }) - .catch(err => console.log(err)); - }; - - const updateShippingProduct = () => { + const onSubmit = () => { const data = { ...innerProps.shippingData, ...form.values, @@ -107,14 +85,6 @@ const ShippingProductModal = ({ .catch(err => console.log(err)); }; - const onSubmit = () => { - if (innerProps.isBox) { - updateBox(); - } else { - updateShippingProduct(); - } - }; - const getRestQuantityText = () => { if (!form.values.product) return; diff --git a/src/pages/CardsPage/tabs/ShippingTab/types/ShippingProductData.tsx b/src/pages/CardsPage/tabs/ShippingTab/types/ShippingProductData.tsx index 5c1944f..4570c69 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/types/ShippingProductData.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/types/ShippingProductData.tsx @@ -1,16 +1,13 @@ -import { - CreateShippingProductSchema, - ProductSchema, - UpdateBoxSchema, - UpdateShippingProductSchema, -} from "../../../../../client"; +import { CreateShippingProductSchema, ProductSchema, UpdateShippingProductSchema } from "../../../../../client"; export type ShippingModalForm = { quantity: number; product?: ProductSchema | null; } -export type ShippingData = - UpdateBoxSchema - | CreateShippingProductSchema - | UpdateShippingProductSchema; \ No newline at end of file +export type ShippingData = CreateShippingProductSchema | UpdateShippingProductSchema; + +export type ShippingProductParentData = { + palletId?: number; + boxId?: number; +} \ No newline at end of file diff --git a/src/pages/CardsPage/tabs/ShippingTab/utils/getRestProducts.tsx b/src/pages/CardsPage/tabs/ShippingTab/utils/getRestProducts.tsx index e801c7e..baddca2 100644 --- a/src/pages/CardsPage/tabs/ShippingTab/utils/getRestProducts.tsx +++ b/src/pages/CardsPage/tabs/ShippingTab/utils/getRestProducts.tsx @@ -1,18 +1,14 @@ -import { CardProductSchema, CardSchema, ProductSchema } from "../../../../../client"; +import { BoxSchema, CardProductSchema, CardSchema, ProductSchema } from "../../../../../client"; -type UnaccountedValues = { - boxId?: number | null; - shippingProductId?: number | null; -} type Props = { card?: CardSchema; - unaccountedValues: UnaccountedValues; + shippingProductId?: number | null; } const getRestProducts = ({ card, - unaccountedValues, + shippingProductId, }: Props) => { const totalProducts = new Map( card?.products.map(product => product && [product.product.id, product]), @@ -30,20 +26,23 @@ const getRestProducts = ({ } }; - card?.boxes?.forEach((box) => { - if (!box.product || box.id === unaccountedValues.boxId) return; - accountProduct(box.product, box.quantity); - }); + const accountBoxes = (boxes?: BoxSchema[]) => { + boxes?.forEach((box) => { + box.shippingProducts.forEach((shippingProduct) => { + if (!shippingProduct.product || shippingProduct.id === shippingProductId) return; + accountProduct(shippingProduct.product, shippingProduct.quantity); + }); + }); + }; + + accountBoxes(card?.boxes); card?.pallets?.forEach(pallet => { pallet.shippingProducts.forEach(shippingProduct => { - if (shippingProduct.id === unaccountedValues.shippingProductId) return; + if (shippingProduct.id === shippingProductId) return; accountProduct(shippingProduct.product, shippingProduct.quantity); }); - pallet.boxes.forEach((box) => { - if (!box.product || box.id === unaccountedValues.boxId) return; - accountProduct(box.product, box.quantity); - }); + accountBoxes(pallet.boxes); }); const restProducts = new Map();