From 580552bd472723a067df24d2c0823f70df9cd9bd Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Fri, 7 Feb 2025 20:07:10 +0400 Subject: [PATCH] feat: projects and boards --- src/client/index.ts | 33 +- src/client/models/BaseBoardSchema.ts | 9 + ...lCreateRequest.ts => BaseProjectSchema.ts} | 2 +- src/client/models/BaseStatusSchema.ts | 9 + src/client/models/BoardSchema.ts | 15 + src/client/models/CreateBoardRequest.ts | 9 + src/client/models/CreateBoardResponse.ts | 9 + .../models/CreateDealsFromExcelRequest.ts | 1 + src/client/models/CreateProjectRequest.ts | 9 + src/client/models/CreateProjectResponse.ts | 9 + src/client/models/CreateStatusRequest.ts | 9 + src/client/models/CreateStatusResponse.ts | 9 + src/client/models/DealGeneralInfoSchema.ts | 4 + src/client/models/DealQuickCreateRequest.ts | 1 + src/client/models/DealSchema.ts | 5 +- src/client/models/DealStatusHistorySchema.ts | 5 +- src/client/models/DealSummary.ts | 7 +- .../models/DealSummaryReorderRequest.ts | 2 +- src/client/models/DeleteBoardResponse.ts | 9 + src/client/models/DeleteProjectResponse.ts | 9 + src/client/models/DeleteStatusResponse.ts | 9 + src/client/models/GetBoardsResponse.ts | 9 + .../models/GetProfitChartDataRequest.ts | 3 + .../models/GetProfitTableDataRequest.ts | 3 + src/client/models/GetProjectsResponse.ts | 9 + src/client/models/ProfitTableGroupBy.ts | 2 +- src/client/models/ProjectSchema.ts | 9 + src/client/models/StatusSchema.ts | 12 + src/client/models/UpdateBoardOrderRequest.ts | 10 + src/client/models/UpdateBoardOrderResponse.ts | 9 + src/client/models/UpdateBoardRequest.ts | 9 + src/client/models/UpdateBoardResponse.ts | 9 + src/client/models/UpdateProjectRequest.ts | 9 + src/client/models/UpdateProjectResponse.ts | 9 + src/client/models/UpdateStatusOrderRequest.ts | 10 + .../models/UpdateStatusOrderResponse.ts | 9 + src/client/models/UpdateStatusRequest.ts | 9 + src/client/models/UpdateStatusResponse.ts | 9 + src/client/services/BoardService.ts | 119 ++++ src/client/services/DealGroupService.ts | 119 ++++ src/client/services/DealService.ts | 131 ----- src/client/services/ProjectService.ts | 87 +++ src/client/services/StatusService.ts | 97 ++++ src/components/BoardSelect/BoardSelect.tsx | 54 ++ .../DealStatusSelect/DealStatusSelect.tsx | 40 ++ .../Dnd/Boards/Board/Board.module.scss | 37 ++ src/components/Dnd/Boards/Board/Board.tsx | 97 ++++ src/components/Dnd/Boards/Boards/Boards.tsx | 90 ++++ .../Dnd/Boards/Boards/hooks/useBoards.tsx | 83 +++ .../Dnd/Boards/Boards/hooks/useBoardsDnd.tsx | 53 ++ .../Dnd/DealSummaryCard/DealSummaryCard.tsx | 226 -------- .../CreateDealButton.module.css | 0 .../CreateDealButton/CreateDealButton.tsx | 13 +- .../CreateDealForm/CreateDealForm.module.css | 0 .../CreateDealForm/CreateDealFrom.tsx | 12 +- .../CreateDealsFromFileButton.module.css | 0 .../CreateDealsFromFileButton.tsx | 2 +- .../DealGroupView/DealGroupView.tsx | 6 +- .../DealSummaryCard.module.css | 0 .../Deals/DealSummaryCard/DealSummaryCard.tsx | 173 ++++++ .../DealSummaryCard/useDealSummaryState.tsx | 8 +- .../DealsDndColumn/DealsDndColumn.module.css} | 9 - .../DealsDndColumn/DealsDndColumn.tsx} | 194 +++---- .../DealsDndColumn/hooks/useDealsDnd.tsx | 213 ++++++++ .../DealsDndColumn/utils/getColumnColor.ts | 20 + .../Deals/DealsDndFooter/DealsDndFooter.tsx | 66 +++ src/components/Dnd/Statuses/Status/Status.tsx | 104 ++++ .../Dnd/Statuses/Status/hooks/useStatus.tsx | 57 ++ .../Dnd/Statuses/Statuses/Statuses.tsx | 86 +++ .../Statuses/hooks/useStatusesDnd.tsx | 50 ++ .../ManagerSelect/ManagerSelect.tsx | 3 +- .../ProjectSelect/ProjectSelect.tsx | 43 ++ .../EmployeeTableModal/EmployeeTableModal.tsx | 2 +- src/modals/modals.ts | 18 +- src/pages/DealPage/ui/DealPage.tsx | 4 +- .../DealProductServiceTable.tsx | 0 .../DealProductsTable/DealProductsTable.tsx | 0 .../components/DealProductsTable/columns.tsx | 0 .../DealServicesTable/DealServicesTable.tsx | 0 .../components/DealServicesTable/columns.tsx | 0 .../DealStatusChangeTable.tsx | 0 .../DealStatusChangeTable/columns.tsx | 12 +- .../DealStatusSelect/DealStatusSelect.tsx | 22 - .../components/DealsTable/DealsTable.tsx | 2 +- .../components/DealsTable/columns.tsx | 9 - .../LeadsPageHeader/LeadsPageHeader.tsx | 127 +++++ .../SimpleUsersTable/SimpleUsersTable.tsx | 0 .../components/SimpleUsersTable/columns.tsx | 0 .../contexts/DealPageContext.tsx | 0 .../contexts/PrefillDealContext.tsx | 0 .../contexts/PrefillDealsWithExcelContext.tsx | 8 +- .../DealEditDrawer/DealEditDrawer.module.css | 0 .../drawers/DealEditDrawer/DealEditDrawer.tsx | 0 .../drawers/DealEditDrawer/tabs/ClientTab.tsx | 0 .../tabs/DealEditDrawerGeneralTab.tsx | 43 +- .../DealPrefillDrawer.module.css | 0 .../DealPrefillDrawer/DealPrefillDrawer.tsx | 0 .../components/Preview/Preview.module.css | 0 .../components/Preview/Preview.tsx | 0 .../ProductPreview/ProductPreview.module.css | 0 .../ProductPreview/ProductPreview.tsx | 0 .../DealServicesTable/DealServicesTable.tsx | 0 .../tables/DealServicesTable/columns.tsx | 0 .../tables/DealsTable/DealsTable.tsx | 0 .../components/tables/DealsTable/columns.tsx | 0 .../ProductServicesTable.tsx | 0 .../tables/ProductServicesTable/columns.tsx | 0 .../hooks/usePrefillDeal.tsx | 0 .../PrefillDealsWithExcelDrawer.module.css | 0 .../PrefillDealsWithExcelDrawer.tsx | 11 +- .../components/BreakdownByCityTable.tsx | 0 .../components/ParsingResultsTooltip.tsx | 0 .../components/ProductsPreview.tsx | 9 +- .../components/ProductsTable.tsx | 0 .../hooks/useBreakdownByCityTableColumns.tsx | 0 .../hooks/useProductsTableColumns.tsx | 0 .../PrefillDealWithExcelDrawer/types.tsx | 0 src/pages/DealsPage/enums/DisplayMode.ts | 6 + src/pages/DealsPage/enums/DragState.ts | 7 + src/pages/DealsPage/hooks/useBoards.tsx | 33 ++ .../hooks/useDealSummaries.tsx | 0 .../DealsPage/hooks/useDealsPageState.tsx | 63 ++- src/pages/DealsPage/hooks/useDnd.tsx | 63 +++ .../hooks/useManagersList.tsx | 0 src/pages/DealsPage/hooks/useProjects.tsx | 26 + .../modals/AddDealProductModal.tsx | 0 .../modals/AddDealServiceModal.tsx | 0 .../modals/BoardModal/BoardModal.tsx | 46 ++ .../modals/BoardModal/hooks/useBoardModal.tsx | 87 +++ .../modals/DealsTableFiltersModal.tsx | 78 +++ .../modals/ProductServiceFormModal.tsx | 0 .../modals/ProjectsModal/ProjectsModal.tsx | 85 +++ .../hooks/projectsTableColumns.tsx | 46 ++ .../ProjectsModal/hooks/useProjectModal.tsx | 100 ++++ .../modals/SelectDealProductsModal.tsx | 0 .../modals/StatusModal/StatusModal.tsx | 46 ++ .../StatusModal/hooks/useStatusModal.tsx | 88 +++ .../tabs/EmployeesTab/EmployeesTab.tsx | 0 .../components/AvailableEmployeesSelect.tsx | 0 .../EmployeesTab/components/EmployeeInput.tsx | 0 .../components/EmployeesTable.tsx | 0 .../hooks/useAvailableEmployeesList.tsx | 0 .../EmployeesTab/hooks/useEmployeesTab.tsx | 0 .../hooks/useEmployeesTableColumns.tsx | 0 .../EmployeesTab/modals/AssignUserModal.tsx | 0 .../types/AssignUserModalForm.tsx | 0 .../ProductAndServiceTab.module.css | 0 .../ProductAndServiceTab.tsx | 0 .../DealServicesTable/DealServicesTable.tsx | 0 .../ProductServicesTable.tsx | 0 .../ProductServicesTable/columns.tsx | 0 .../ProductView/ProductView.module.css | 0 .../components/ProductView/ProductView.tsx | 0 .../hooks/useProductAndServiceTabState.tsx | 0 .../tabs/ShippingTab/ShippingTab.tsx | 0 .../ShippingTab/components/BoxesTable.tsx | 0 .../components/ShippingProductSelect.tsx | 0 .../components/ShippingProductsTable.tsx | 0 .../ShippingTab/components/ShippingTree.tsx | 0 .../hooks/shippingTableColumns.tsx | 0 .../tabs/ShippingTab/hooks/useShipping.tsx | 0 .../tabs/ShippingTab/hooks/useShippingQrs.tsx | 0 .../tabs/ShippingTab/hooks/useUpdateDeal.tsx | 0 .../modals/ShippingProductModal.tsx | 0 .../ShippingTab/types/ShippingProductData.tsx | 0 .../ShippingTab/utils/getRestProducts.tsx | 0 src/pages/DealsPage/ui/DealsPage.module.css | 49 +- src/pages/DealsPage/ui/DealsPage.tsx | 153 ++++-- src/pages/LeadsPage/index.ts | 1 - src/pages/LeadsPage/ui/LeadsPage.module.css | 44 -- src/pages/LeadsPage/ui/LeadsPage.tsx | 508 ------------------ .../modals/ShippingWarehouseForm.tsx | 4 +- .../ui/ShippingWarehousesPage.tsx | 2 +- .../ProfitTab/components/Filters/Filters.tsx | 52 +- .../components/ProfitTable/hooks/columns.tsx | 12 +- .../ProfitTable/hooks/useProfitTable.tsx | 1 + .../ProfitTableSegmentedControl.tsx | 96 +++- .../ProfitTab/contexts/ProfitTabContext.tsx | 9 +- .../ProfitTab/modals/ProfitFiltersModal.tsx | 4 +- src/pages/StatisticsPage/types/FormFilters.ts | 15 +- .../utils/defaultFilterValues.ts | 6 - src/routeTree.gen.ts | 24 +- src/routes/leads.$dealId.tsx | 4 +- src/routes/leads.lazy.tsx | 4 +- src/types/utils.ts | 2 +- 185 files changed, 3352 insertions(+), 1284 deletions(-) create mode 100644 src/client/models/BaseBoardSchema.ts rename src/client/models/{DealCreateRequest.ts => BaseProjectSchema.ts} (82%) create mode 100644 src/client/models/BaseStatusSchema.ts create mode 100644 src/client/models/BoardSchema.ts create mode 100644 src/client/models/CreateBoardRequest.ts create mode 100644 src/client/models/CreateBoardResponse.ts create mode 100644 src/client/models/CreateProjectRequest.ts create mode 100644 src/client/models/CreateProjectResponse.ts create mode 100644 src/client/models/CreateStatusRequest.ts create mode 100644 src/client/models/CreateStatusResponse.ts create mode 100644 src/client/models/DeleteBoardResponse.ts create mode 100644 src/client/models/DeleteProjectResponse.ts create mode 100644 src/client/models/DeleteStatusResponse.ts create mode 100644 src/client/models/GetBoardsResponse.ts create mode 100644 src/client/models/GetProjectsResponse.ts create mode 100644 src/client/models/ProjectSchema.ts create mode 100644 src/client/models/StatusSchema.ts create mode 100644 src/client/models/UpdateBoardOrderRequest.ts create mode 100644 src/client/models/UpdateBoardOrderResponse.ts create mode 100644 src/client/models/UpdateBoardRequest.ts create mode 100644 src/client/models/UpdateBoardResponse.ts create mode 100644 src/client/models/UpdateProjectRequest.ts create mode 100644 src/client/models/UpdateProjectResponse.ts create mode 100644 src/client/models/UpdateStatusOrderRequest.ts create mode 100644 src/client/models/UpdateStatusOrderResponse.ts create mode 100644 src/client/models/UpdateStatusRequest.ts create mode 100644 src/client/models/UpdateStatusResponse.ts create mode 100644 src/client/services/BoardService.ts create mode 100644 src/client/services/DealGroupService.ts create mode 100644 src/client/services/ProjectService.ts create mode 100644 src/client/services/StatusService.ts create mode 100644 src/components/BoardSelect/BoardSelect.tsx create mode 100644 src/components/DealStatusSelect/DealStatusSelect.tsx create mode 100644 src/components/Dnd/Boards/Board/Board.module.scss create mode 100644 src/components/Dnd/Boards/Board/Board.tsx create mode 100644 src/components/Dnd/Boards/Boards/Boards.tsx create mode 100644 src/components/Dnd/Boards/Boards/hooks/useBoards.tsx create mode 100644 src/components/Dnd/Boards/Boards/hooks/useBoardsDnd.tsx delete mode 100644 src/components/Dnd/DealSummaryCard/DealSummaryCard.tsx rename src/components/Dnd/{ => Deals}/CreateDealButton/CreateDealButton.module.css (100%) rename src/components/Dnd/{ => Deals}/CreateDealButton/CreateDealButton.tsx (88%) rename src/components/Dnd/{ => Deals}/CreateDealForm/CreateDealForm.module.css (100%) rename src/components/Dnd/{ => Deals}/CreateDealForm/CreateDealFrom.tsx (87%) rename src/components/Dnd/{ => Deals}/CreateDealsFromFileButton/CreateDealsFromFileButton.module.css (100%) rename src/components/Dnd/{ => Deals}/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx (79%) rename src/components/Dnd/{ => Deals}/DealGroupView/DealGroupView.tsx (94%) rename src/components/Dnd/{ => Deals}/DealSummaryCard/DealSummaryCard.module.css (100%) create mode 100644 src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.tsx rename src/components/Dnd/{ => Deals}/DealSummaryCard/useDealSummaryState.tsx (91%) rename src/components/Dnd/{Board/Board.module.css => Deals/DealsDndColumn/DealsDndColumn.module.css} (67%) rename src/components/Dnd/{Board/Board.tsx => Deals/DealsDndColumn/DealsDndColumn.tsx} (55%) create mode 100644 src/components/Dnd/Deals/DealsDndColumn/hooks/useDealsDnd.tsx create mode 100644 src/components/Dnd/Deals/DealsDndColumn/utils/getColumnColor.ts create mode 100644 src/components/Dnd/Deals/DealsDndFooter/DealsDndFooter.tsx create mode 100644 src/components/Dnd/Statuses/Status/Status.tsx create mode 100644 src/components/Dnd/Statuses/Status/hooks/useStatus.tsx create mode 100644 src/components/Dnd/Statuses/Statuses/Statuses.tsx create mode 100644 src/components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx create mode 100644 src/components/ProjectSelect/ProjectSelect.tsx rename src/pages/{LeadsPage => DealsPage}/components/DealProductsTable/DealProductServiceTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealProductsTable/DealProductsTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealProductsTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealServicesTable/DealServicesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealServicesTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealStatusChangeTable/DealStatusChangeTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/DealStatusChangeTable/columns.tsx (81%) delete mode 100644 src/pages/DealsPage/components/DealStatusSelect/DealStatusSelect.tsx create mode 100644 src/pages/DealsPage/components/LeadsPageHeader/LeadsPageHeader.tsx rename src/pages/{LeadsPage => DealsPage}/components/SimpleUsersTable/SimpleUsersTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/components/SimpleUsersTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/contexts/DealPageContext.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/contexts/PrefillDealContext.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/contexts/PrefillDealsWithExcelContext.tsx (95%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealEditDrawer/DealEditDrawer.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealEditDrawer/DealEditDrawer.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealEditDrawer/tabs/ClientTab.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx (92%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/DealPrefillDrawer.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/DealPrefillDrawer.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/Preview/Preview.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/Preview/Preview.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/ProductPreview/ProductPreview.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/ProductPreview/ProductPreview.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/DealServicesTable/DealServicesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/DealServicesTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/DealsTable/DealsTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/DealsTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/ProductServicesTable/ProductServicesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/components/tables/ProductServicesTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/DealPrefillDrawer/hooks/usePrefillDeal.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.tsx (83%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/components/BreakdownByCityTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/components/ParsingResultsTooltip.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx (94%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/components/ProductsTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/hooks/useBreakdownByCityTableColumns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/hooks/useProductsTableColumns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/drawers/PrefillDealWithExcelDrawer/types.tsx (100%) create mode 100644 src/pages/DealsPage/enums/DisplayMode.ts create mode 100644 src/pages/DealsPage/enums/DragState.ts create mode 100644 src/pages/DealsPage/hooks/useBoards.tsx rename src/pages/{LeadsPage => DealsPage}/hooks/useDealSummaries.tsx (100%) create mode 100644 src/pages/DealsPage/hooks/useDnd.tsx rename src/pages/{LeadsPage => DealsPage}/hooks/useManagersList.tsx (100%) create mode 100644 src/pages/DealsPage/hooks/useProjects.tsx rename src/pages/{LeadsPage => DealsPage}/modals/AddDealProductModal.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/modals/AddDealServiceModal.tsx (100%) create mode 100644 src/pages/DealsPage/modals/BoardModal/BoardModal.tsx create mode 100644 src/pages/DealsPage/modals/BoardModal/hooks/useBoardModal.tsx create mode 100644 src/pages/DealsPage/modals/DealsTableFiltersModal.tsx rename src/pages/{LeadsPage => DealsPage}/modals/ProductServiceFormModal.tsx (100%) create mode 100644 src/pages/DealsPage/modals/ProjectsModal/ProjectsModal.tsx create mode 100644 src/pages/DealsPage/modals/ProjectsModal/hooks/projectsTableColumns.tsx create mode 100644 src/pages/DealsPage/modals/ProjectsModal/hooks/useProjectModal.tsx rename src/pages/{LeadsPage => DealsPage}/modals/SelectDealProductsModal.tsx (100%) create mode 100644 src/pages/DealsPage/modals/StatusModal/StatusModal.tsx create mode 100644 src/pages/DealsPage/modals/StatusModal/hooks/useStatusModal.tsx rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/EmployeesTab.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/components/AvailableEmployeesSelect.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/components/EmployeeInput.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/components/EmployeesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/hooks/useAvailableEmployeesList.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/hooks/useEmployeesTab.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/hooks/useEmployeesTableColumns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/modals/AssignUserModal.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/EmployeesTab/types/AssignUserModalForm.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/ProductAndServiceTab.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/components/ProductServicesTable/columns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/components/ProductView/ProductView.module.css (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ProductAndServiceTab/hooks/useProductAndServiceTabState.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/ShippingTab.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/components/BoxesTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/components/ShippingProductSelect.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/components/ShippingProductsTable.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/components/ShippingTree.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/hooks/shippingTableColumns.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/hooks/useShipping.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/hooks/useShippingQrs.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/hooks/useUpdateDeal.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/modals/ShippingProductModal.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/types/ShippingProductData.tsx (100%) rename src/pages/{LeadsPage => DealsPage}/tabs/ShippingTab/utils/getRestProducts.tsx (100%) delete mode 100644 src/pages/LeadsPage/index.ts delete mode 100644 src/pages/LeadsPage/ui/LeadsPage.module.css delete mode 100644 src/pages/LeadsPage/ui/LeadsPage.tsx delete mode 100644 src/pages/StatisticsPage/utils/defaultFilterValues.ts diff --git a/src/client/index.ts b/src/client/index.ts index b410d97..7f087ff 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -23,13 +23,17 @@ export type { BarcodeTemplateSchema } from './models/BarcodeTemplateSchema'; export type { BarcodeTemplateSizeSchema } from './models/BarcodeTemplateSizeSchema'; export type { BarcodeTemplateUpdateRequest } from './models/BarcodeTemplateUpdateRequest'; export type { BarcodeTemplateUpdateResponse } from './models/BarcodeTemplateUpdateResponse'; +export type { BaseBoardSchema } from './models/BaseBoardSchema'; export type { BaseEnumListSchema } from './models/BaseEnumListSchema'; export type { BaseEnumSchema } from './models/BaseEnumSchema'; export type { BaseMarketplaceSchema } from './models/BaseMarketplaceSchema'; +export type { BaseProjectSchema } from './models/BaseProjectSchema'; export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema'; +export type { BaseStatusSchema } from './models/BaseStatusSchema'; export type { BaseTransactionTagSchema } from './models/BaseTransactionTagSchema'; export type { BillPaymentStatus } from './models/BillPaymentStatus'; export type { BillStatusUpdateRequest } from './models/BillStatusUpdateRequest'; +export type { BoardSchema } from './models/BoardSchema'; export type { Body_parse_deals_excel } from './models/Body_parse_deals_excel'; export type { Body_upload_passport_image } from './models/Body_upload_passport_image'; export type { Body_upload_product_barcode_image } from './models/Body_upload_product_barcode_image'; @@ -52,6 +56,8 @@ export type { ClientUpdateRequest } from './models/ClientUpdateRequest'; export type { ClientUpdateResponse } from './models/ClientUpdateResponse'; export type { CreateBarcodeTemplateAttributeRequest } from './models/CreateBarcodeTemplateAttributeRequest'; export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse'; +export type { CreateBoardRequest } from './models/CreateBoardRequest'; +export type { CreateBoardResponse } from './models/CreateBoardResponse'; export type { CreateBoxInDealSchema } from './models/CreateBoxInDealSchema'; export type { CreateBoxInPalletSchema } from './models/CreateBoxInPalletSchema'; export type { CreateDealBillRequest } from './models/CreateDealBillRequest'; @@ -73,6 +79,8 @@ export type { CreatePositionRequest } from './models/CreatePositionRequest'; export type { CreatePositionResponse } from './models/CreatePositionResponse'; export type { CreatePriceCategoryRequest } from './models/CreatePriceCategoryRequest'; export type { CreatePriceCategoryResponse } from './models/CreatePriceCategoryResponse'; +export type { CreateProjectRequest } from './models/CreateProjectRequest'; +export type { CreateProjectResponse } from './models/CreateProjectResponse'; export type { CreateResidualBoxRequest } from './models/CreateResidualBoxRequest'; export type { CreateResidualBoxResponse } from './models/CreateResidualBoxResponse'; export type { CreateResidualPalletRequest } from './models/CreateResidualPalletRequest'; @@ -86,6 +94,8 @@ export type { CreateServicesKitResponse } from './models/CreateServicesKitRespon export type { CreateShippingProductSchema } from './models/CreateShippingProductSchema'; export type { CreateShippingWarehouseRequest } from './models/CreateShippingWarehouseRequest'; export type { CreateShippingWarehouseResponse } from './models/CreateShippingWarehouseResponse'; +export type { CreateStatusRequest } from './models/CreateStatusRequest'; +export type { CreateStatusResponse } from './models/CreateStatusResponse'; export type { CreateTaskResponse } from './models/CreateTaskResponse'; export type { CreateTransactionTagRequest } from './models/CreateTransactionTagRequest'; export type { CreateUserRequest } from './models/CreateUserRequest'; @@ -109,7 +119,6 @@ export type { DealCreateGroupRequest } from './models/DealCreateGroupRequest'; export type { DealCreateGroupResponse } from './models/DealCreateGroupResponse'; export type { DealCreateGuestUrlRequest } from './models/DealCreateGuestUrlRequest'; export type { DealCreateGuestUrlResponse } from './models/DealCreateGuestUrlResponse'; -export type { DealCreateRequest } from './models/DealCreateRequest'; export type { DealDeleteProductRequest } from './models/DealDeleteProductRequest'; export type { DealDeleteProductResponse } from './models/DealDeleteProductResponse'; export type { DealDeleteProductsRequest } from './models/DealDeleteProductsRequest'; @@ -158,6 +167,7 @@ export type { DealUpdateServiceQuantityRequest } from './models/DealUpdateServic export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse'; export type { DealUpdateServiceRequest } from './models/DealUpdateServiceRequest'; export type { DealUpdateServiceResponse } from './models/DealUpdateServiceResponse'; +export type { DeleteBoardResponse } from './models/DeleteBoardResponse'; export type { DeleteBoxResponse } from './models/DeleteBoxResponse'; export type { DeleteDepartmentResponse } from './models/DeleteDepartmentResponse'; export type { DeleteDepartmentSectionResponse } from './models/DeleteDepartmentSectionResponse'; @@ -172,6 +182,7 @@ export type { DeletePositionRequest } from './models/DeletePositionRequest'; export type { DeletePositionResponse } from './models/DeletePositionResponse'; export type { DeletePriceCategoryRequest } from './models/DeletePriceCategoryRequest'; export type { DeletePriceCategoryResponse } from './models/DeletePriceCategoryResponse'; +export type { DeleteProjectResponse } from './models/DeleteProjectResponse'; export type { DeleteResidualBoxResponse } from './models/DeleteResidualBoxResponse'; export type { DeleteResidualPalletResponse } from './models/DeleteResidualPalletResponse'; export type { DeleteResidualProductResponse } from './models/DeleteResidualProductResponse'; @@ -179,6 +190,7 @@ export type { DeleteShiftResponse } from './models/DeleteShiftResponse'; export type { DeleteShippingProductResponse } from './models/DeleteShippingProductResponse'; export type { DeleteShippingWarehouseRequest } from './models/DeleteShippingWarehouseRequest'; export type { DeleteShippingWarehouseResponse } from './models/DeleteShippingWarehouseResponse'; +export type { DeleteStatusResponse } from './models/DeleteStatusResponse'; export type { DeleteTransactionResponse } from './models/DeleteTransactionResponse'; export type { DeleteTransactionTagResponse } from './models/DeleteTransactionTagResponse'; export type { DeleteUserRequest } from './models/DeleteUserRequest'; @@ -211,6 +223,7 @@ export type { GetAvailableEmployeesToAssignResponse } from './models/GetAvailabl export type { GetAvailableUsersForDepartmentSectionResponse } from './models/GetAvailableUsersForDepartmentSectionResponse'; export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest'; export type { GetBarcodeTemplateByIdResponse } from './models/GetBarcodeTemplateByIdResponse'; +export type { GetBoardsResponse } from './models/GetBoardsResponse'; export type { GetClientMarketplacesRequest } from './models/GetClientMarketplacesRequest'; export type { GetClientMarketplacesResponse } from './models/GetClientMarketplacesResponse'; export type { GetDealBillById } from './models/GetDealBillById'; @@ -229,6 +242,7 @@ export type { GetProfitChartDataRequest } from './models/GetProfitChartDataReque export type { GetProfitChartDataResponse } from './models/GetProfitChartDataResponse'; export type { GetProfitTableDataRequest } from './models/GetProfitTableDataRequest'; export type { GetProfitTableDataResponse } from './models/GetProfitTableDataResponse'; +export type { GetProjectsResponse } from './models/GetProjectsResponse'; export type { GetResidualBoxResponse } from './models/GetResidualBoxResponse'; export type { GetResidualPalletResponse } from './models/GetResidualPalletResponse'; export type { GetServiceKitSchema } from './models/GetServiceKitSchema'; @@ -285,6 +299,8 @@ export type { ProductUploadImageResponse } from './models/ProductUploadImageResp export type { ProfitChartDataItem } from './models/ProfitChartDataItem'; export type { ProfitTableDataItem } from './models/ProfitTableDataItem'; export type { ProfitTableGroupBy } from './models/ProfitTableGroupBy'; +export type { ProjectSchema } from './models/ProjectSchema'; +export type { ProjectSchemaWithCount } from './models/ProjectSchemaWithCount'; export type { ReceiptBoxSchema } from './models/ReceiptBoxSchema'; export type { ReceiptPalletSchema } from './models/ReceiptPalletSchema'; export type { ResidualBoxSchema } from './models/ResidualBoxSchema'; @@ -319,12 +335,17 @@ export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema'; export type { StartPauseByShiftIdResponse } from './models/StartPauseByShiftIdResponse'; export type { StartPauseByUserIdResponse } from './models/StartPauseByUserIdResponse'; export type { StartShiftResponse } from './models/StartShiftResponse'; +export type { StatusSchema } from './models/StatusSchema'; export type { SynchronizeMarketplaceRequest } from './models/SynchronizeMarketplaceRequest'; export type { TaskInfoResponse } from './models/TaskInfoResponse'; export type { TimeTrackingData } from './models/TimeTrackingData'; export type { TimeTrackingRecord } from './models/TimeTrackingRecord'; export type { TransactionSchemaBase } from './models/TransactionSchemaBase'; export type { TransactionTagSchema } from './models/TransactionTagSchema'; +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'; @@ -340,6 +361,8 @@ export type { UpdatePlanningWorkShiftRequest } from './models/UpdatePlanningWork export type { UpdatePlanningWorkShiftResponse } from './models/UpdatePlanningWorkShiftResponse'; export type { UpdatePriceCategoryRequest } from './models/UpdatePriceCategoryRequest'; export type { UpdatePriceCategoryResponse } from './models/UpdatePriceCategoryResponse'; +export type { UpdateProjectRequest } from './models/UpdateProjectRequest'; +export type { UpdateProjectResponse } from './models/UpdateProjectResponse'; export type { UpdateResidualProductRequest } from './models/UpdateResidualProductRequest'; export type { UpdateResidualProductResponse } from './models/UpdateResidualProductResponse'; export type { UpdateResidualProductSchema } from './models/UpdateResidualProductSchema'; @@ -351,6 +374,10 @@ export type { UpdateShippingProductResponse } from './models/UpdateShippingProdu export type { UpdateShippingProductSchema } from './models/UpdateShippingProductSchema'; export type { UpdateShippingWarehouseRequest } from './models/UpdateShippingWarehouseRequest'; export type { UpdateShippingWarehouseResponse } from './models/UpdateShippingWarehouseResponse'; +export type { UpdateStatusOrderRequest } from './models/UpdateStatusOrderRequest'; +export type { UpdateStatusOrderResponse } from './models/UpdateStatusOrderResponse'; +export type { UpdateStatusRequest } from './models/UpdateStatusRequest'; +export type { UpdateStatusResponse } from './models/UpdateStatusResponse'; export type { UpdateTimeTrackingRecordRequest } from './models/UpdateTimeTrackingRecordRequest'; export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse'; export type { UpdateTransactionRequest } from './models/UpdateTransactionRequest'; @@ -375,19 +402,23 @@ export type { WorkShiftSchema } from './models/WorkShiftSchema'; export { AuthService } from './services/AuthService'; export { BarcodeService } from './services/BarcodeService'; export { BillingService } from './services/BillingService'; +export { BoardService } from './services/BoardService'; export { ClientService } from './services/ClientService'; export { DealService } from './services/DealService'; +export { DealGroupService } from './services/DealGroupService'; export { DepartmentService } from './services/DepartmentService'; export { MarketplaceService } from './services/MarketplaceService'; export { PayrollService } from './services/PayrollService'; export { PositionService } from './services/PositionService'; export { ProductService } from './services/ProductService'; +export { ProjectService } from './services/ProjectService'; export { ResiduesService } from './services/ResiduesService'; export { RoleService } from './services/RoleService'; export { ServiceService } from './services/ServiceService'; export { ShippingService } from './services/ShippingService'; export { ShippingWarehouseService } from './services/ShippingWarehouseService'; export { StatisticsService } from './services/StatisticsService'; +export { StatusService } from './services/StatusService'; export { TaskService } from './services/TaskService'; export { TimeTrackingService } from './services/TimeTrackingService'; export { TransactionService } from './services/TransactionService'; diff --git a/src/client/models/BaseBoardSchema.ts b/src/client/models/BaseBoardSchema.ts new file mode 100644 index 0000000..2877bfb --- /dev/null +++ b/src/client/models/BaseBoardSchema.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type BaseBoardSchema = { + name: string; + projectId: number; +}; + diff --git a/src/client/models/DealCreateRequest.ts b/src/client/models/BaseProjectSchema.ts similarity index 82% rename from src/client/models/DealCreateRequest.ts rename to src/client/models/BaseProjectSchema.ts index d5f8b37..37159f1 100644 --- a/src/client/models/DealCreateRequest.ts +++ b/src/client/models/BaseProjectSchema.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type DealCreateRequest = { +export type BaseProjectSchema = { name: string; }; diff --git a/src/client/models/BaseStatusSchema.ts b/src/client/models/BaseStatusSchema.ts new file mode 100644 index 0000000..9ee3f33 --- /dev/null +++ b/src/client/models/BaseStatusSchema.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type BaseStatusSchema = { + name: string; + boardId: number; +}; + diff --git a/src/client/models/BoardSchema.ts b/src/client/models/BoardSchema.ts new file mode 100644 index 0000000..431cff3 --- /dev/null +++ b/src/client/models/BoardSchema.ts @@ -0,0 +1,15 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ProjectSchema } from './ProjectSchema'; +import type { StatusSchema } from './StatusSchema'; +export type BoardSchema = { + name: string; + projectId: number; + id: number; + ordinalNumber: number; + dealStatuses: Array; + project: ProjectSchema; +}; + diff --git a/src/client/models/CreateBoardRequest.ts b/src/client/models/CreateBoardRequest.ts new file mode 100644 index 0000000..055ad7f --- /dev/null +++ b/src/client/models/CreateBoardRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseBoardSchema } from './BaseBoardSchema'; +export type CreateBoardRequest = { + board: BaseBoardSchema; +}; + diff --git a/src/client/models/CreateBoardResponse.ts b/src/client/models/CreateBoardResponse.ts new file mode 100644 index 0000000..023ea80 --- /dev/null +++ b/src/client/models/CreateBoardResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateBoardResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/CreateDealsFromExcelRequest.ts b/src/client/models/CreateDealsFromExcelRequest.ts index cbfe3fe..538d5f6 100644 --- a/src/client/models/CreateDealsFromExcelRequest.ts +++ b/src/client/models/CreateDealsFromExcelRequest.ts @@ -5,6 +5,7 @@ import type { ProductFromExcelSchema } from './ProductFromExcelSchema'; export type CreateDealsFromExcelRequest = { clientId: number; + statusId: number; products: Array; }; diff --git a/src/client/models/CreateProjectRequest.ts b/src/client/models/CreateProjectRequest.ts new file mode 100644 index 0000000..e73afee --- /dev/null +++ b/src/client/models/CreateProjectRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseProjectSchema } from './BaseProjectSchema'; +export type CreateProjectRequest = { + project: BaseProjectSchema; +}; + diff --git a/src/client/models/CreateProjectResponse.ts b/src/client/models/CreateProjectResponse.ts new file mode 100644 index 0000000..03acf3b --- /dev/null +++ b/src/client/models/CreateProjectResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateProjectResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/CreateStatusRequest.ts b/src/client/models/CreateStatusRequest.ts new file mode 100644 index 0000000..54e6f02 --- /dev/null +++ b/src/client/models/CreateStatusRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseStatusSchema } from './BaseStatusSchema'; +export type CreateStatusRequest = { + status: BaseStatusSchema; +}; + diff --git a/src/client/models/CreateStatusResponse.ts b/src/client/models/CreateStatusResponse.ts new file mode 100644 index 0000000..7c6b012 --- /dev/null +++ b/src/client/models/CreateStatusResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateStatusResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DealGeneralInfoSchema.ts b/src/client/models/DealGeneralInfoSchema.ts index e468086..95157b9 100644 --- a/src/client/models/DealGeneralInfoSchema.ts +++ b/src/client/models/DealGeneralInfoSchema.ts @@ -2,6 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { BoardSchema } from './BoardSchema'; +import type { StatusSchema } from './StatusSchema'; import type { UserSchema } from './UserSchema'; export type DealGeneralInfoSchema = { name: string; @@ -13,5 +15,7 @@ export type DealGeneralInfoSchema = { deliveryDate?: (string | null); receivingSlotDate?: (string | null); manager?: (UserSchema | null); + board: BoardSchema; + status: StatusSchema; }; diff --git a/src/client/models/DealQuickCreateRequest.ts b/src/client/models/DealQuickCreateRequest.ts index 692714d..ffe1bda 100644 --- a/src/client/models/DealQuickCreateRequest.ts +++ b/src/client/models/DealQuickCreateRequest.ts @@ -12,5 +12,6 @@ export type DealQuickCreateRequest = { shippingWarehouse: string; baseMarketplace: BaseMarketplaceSchema; category?: (ServicePriceCategorySchema | null); + statusId: number; }; diff --git a/src/client/models/DealSchema.ts b/src/client/models/DealSchema.ts index d486c74..c159f94 100644 --- a/src/client/models/DealSchema.ts +++ b/src/client/models/DealSchema.ts @@ -2,6 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { BoardSchema } from './BoardSchema'; import type { BoxSchema } from './BoxSchema'; import type { ClientSchema } from './ClientSchema'; import type { DealBillRequestSchema } from './DealBillRequestSchema'; @@ -13,13 +14,15 @@ import type { DealStatusHistorySchema } from './DealStatusHistorySchema'; import type { PalletSchema } from './PalletSchema'; import type { ServicePriceCategorySchema } from './ServicePriceCategorySchema'; import type { ShippingWarehouseSchema } from './ShippingWarehouseSchema'; +import type { StatusSchema } from './StatusSchema'; import type { UserSchema } from './UserSchema'; export type DealSchema = { id: number; name: string; clientId: number; createdAt: string; - currentStatus: number; + status: StatusSchema; + board: BoardSchema; services: Array; products: Array; statusHistory: Array; diff --git a/src/client/models/DealStatusHistorySchema.ts b/src/client/models/DealStatusHistorySchema.ts index 295176a..0fd15e9 100644 --- a/src/client/models/DealStatusHistorySchema.ts +++ b/src/client/models/DealStatusHistorySchema.ts @@ -2,12 +2,13 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { StatusSchema } from './StatusSchema'; import type { UserSchema } from './UserSchema'; export type DealStatusHistorySchema = { user: UserSchema; changedAt: string; - fromStatus: number; - toStatus: number; + fromStatus: StatusSchema; + toStatus: StatusSchema; nextStatusDeadline: (string | null); comment?: (string | null); }; diff --git a/src/client/models/DealSummary.ts b/src/client/models/DealSummary.ts index a5e75a5..f7e0330 100644 --- a/src/client/models/DealSummary.ts +++ b/src/client/models/DealSummary.ts @@ -3,16 +3,17 @@ /* tslint:disable */ /* eslint-disable */ import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema'; +import type { BoardSchema } from './BoardSchema'; import type { DealBillRequestSchema } from './DealBillRequestSchema'; import type { DealGroupSchema } from './DealGroupSchema'; +import type { StatusSchema } from './StatusSchema'; export type DealSummary = { id: number; name: string; clientName: string; - changedAt: string; createdAt: string; - deadline?: (string | null); - status: number; + status: StatusSchema; + board: BoardSchema; totalPrice: number; rank: number; baseMarketplace?: (BaseMarketplaceSchema | null); diff --git a/src/client/models/DealSummaryReorderRequest.ts b/src/client/models/DealSummaryReorderRequest.ts index ff04276..9e760cc 100644 --- a/src/client/models/DealSummaryReorderRequest.ts +++ b/src/client/models/DealSummaryReorderRequest.ts @@ -4,7 +4,7 @@ /* eslint-disable */ export type DealSummaryReorderRequest = { dealId: number; - status: number; + statusId: number; index: number; deadline?: (string | null); comment?: (string | null); diff --git a/src/client/models/DeleteBoardResponse.ts b/src/client/models/DeleteBoardResponse.ts new file mode 100644 index 0000000..1d06e1b --- /dev/null +++ b/src/client/models/DeleteBoardResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DeleteBoardResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DeleteProjectResponse.ts b/src/client/models/DeleteProjectResponse.ts new file mode 100644 index 0000000..4fa40d4 --- /dev/null +++ b/src/client/models/DeleteProjectResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DeleteProjectResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/DeleteStatusResponse.ts b/src/client/models/DeleteStatusResponse.ts new file mode 100644 index 0000000..52dd1ab --- /dev/null +++ b/src/client/models/DeleteStatusResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DeleteStatusResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/GetBoardsResponse.ts b/src/client/models/GetBoardsResponse.ts new file mode 100644 index 0000000..5f71686 --- /dev/null +++ b/src/client/models/GetBoardsResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BoardSchema } from './BoardSchema'; +export type GetBoardsResponse = { + boards: Array; +}; + diff --git a/src/client/models/GetProfitChartDataRequest.ts b/src/client/models/GetProfitChartDataRequest.ts index 928008a..82037ea 100644 --- a/src/client/models/GetProfitChartDataRequest.ts +++ b/src/client/models/GetProfitChartDataRequest.ts @@ -6,9 +6,12 @@ export type GetProfitChartDataRequest = { dateRange: any[]; clientId: number; baseMarketplaceKey: string; + projectId: number; + boardId: number; dealStatusId: number; managerId: number; expenseTagId: number; incomeTagId: number; + isCompletedOnly: boolean; }; diff --git a/src/client/models/GetProfitTableDataRequest.ts b/src/client/models/GetProfitTableDataRequest.ts index 1a7c874..38b12e3 100644 --- a/src/client/models/GetProfitTableDataRequest.ts +++ b/src/client/models/GetProfitTableDataRequest.ts @@ -7,10 +7,13 @@ export type GetProfitTableDataRequest = { dateRange: any[]; clientId: number; baseMarketplaceKey: string; + projectId: number; + boardId: number; dealStatusId: number; managerId: number; expenseTagId: number; incomeTagId: number; + isCompletedOnly: boolean; groupTableBy: ProfitTableGroupBy; }; diff --git a/src/client/models/GetProjectsResponse.ts b/src/client/models/GetProjectsResponse.ts new file mode 100644 index 0000000..c4346fd --- /dev/null +++ b/src/client/models/GetProjectsResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ProjectSchemaWithCount } from './ProjectSchemaWithCount'; +export type GetProjectsResponse = { + projects: Array; +}; + diff --git a/src/client/models/ProfitTableGroupBy.ts b/src/client/models/ProfitTableGroupBy.ts index f56c4c7..6abd188 100644 --- a/src/client/models/ProfitTableGroupBy.ts +++ b/src/client/models/ProfitTableGroupBy.ts @@ -2,4 +2,4 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type ProfitTableGroupBy = 0 | 1 | 2 | 3 | 4 | 5; +export type ProfitTableGroupBy = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; diff --git a/src/client/models/ProjectSchema.ts b/src/client/models/ProjectSchema.ts new file mode 100644 index 0000000..b51bfc8 --- /dev/null +++ b/src/client/models/ProjectSchema.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type ProjectSchema = { + name: string; + id: number; +}; + diff --git a/src/client/models/StatusSchema.ts b/src/client/models/StatusSchema.ts new file mode 100644 index 0000000..f653b24 --- /dev/null +++ b/src/client/models/StatusSchema.ts @@ -0,0 +1,12 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type StatusSchema = { + name: string; + boardId: number; + id: number; + ordinalNumber: number; + isDeleted?: boolean; +}; + diff --git a/src/client/models/UpdateBoardOrderRequest.ts b/src/client/models/UpdateBoardOrderRequest.ts new file mode 100644 index 0000000..2e56132 --- /dev/null +++ b/src/client/models/UpdateBoardOrderRequest.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateBoardOrderRequest = { + projectId: number; + boardId: number; + newOrdinalNumber: number; +}; + diff --git a/src/client/models/UpdateBoardOrderResponse.ts b/src/client/models/UpdateBoardOrderResponse.ts new file mode 100644 index 0000000..0cb79f8 --- /dev/null +++ b/src/client/models/UpdateBoardOrderResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateBoardOrderResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/UpdateBoardRequest.ts b/src/client/models/UpdateBoardRequest.ts new file mode 100644 index 0000000..a93b5a2 --- /dev/null +++ b/src/client/models/UpdateBoardRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BoardSchema } from './BoardSchema'; +export type UpdateBoardRequest = { + board: BoardSchema; +}; + diff --git a/src/client/models/UpdateBoardResponse.ts b/src/client/models/UpdateBoardResponse.ts new file mode 100644 index 0000000..3b704e0 --- /dev/null +++ b/src/client/models/UpdateBoardResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateBoardResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/UpdateProjectRequest.ts b/src/client/models/UpdateProjectRequest.ts new file mode 100644 index 0000000..eb9e41f --- /dev/null +++ b/src/client/models/UpdateProjectRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ProjectSchema } from './ProjectSchema'; +export type UpdateProjectRequest = { + project: ProjectSchema; +}; + diff --git a/src/client/models/UpdateProjectResponse.ts b/src/client/models/UpdateProjectResponse.ts new file mode 100644 index 0000000..083a2db --- /dev/null +++ b/src/client/models/UpdateProjectResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateProjectResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/UpdateStatusOrderRequest.ts b/src/client/models/UpdateStatusOrderRequest.ts new file mode 100644 index 0000000..58be3a7 --- /dev/null +++ b/src/client/models/UpdateStatusOrderRequest.ts @@ -0,0 +1,10 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateStatusOrderRequest = { + boardId: number; + statusId: number; + newOrdinalNumber: number; +}; + diff --git a/src/client/models/UpdateStatusOrderResponse.ts b/src/client/models/UpdateStatusOrderResponse.ts new file mode 100644 index 0000000..6a83362 --- /dev/null +++ b/src/client/models/UpdateStatusOrderResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateStatusOrderResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/UpdateStatusRequest.ts b/src/client/models/UpdateStatusRequest.ts new file mode 100644 index 0000000..5f3241f --- /dev/null +++ b/src/client/models/UpdateStatusRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { StatusSchema } from './StatusSchema'; +export type UpdateStatusRequest = { + status: StatusSchema; +}; + diff --git a/src/client/models/UpdateStatusResponse.ts b/src/client/models/UpdateStatusResponse.ts new file mode 100644 index 0000000..dc9fc46 --- /dev/null +++ b/src/client/models/UpdateStatusResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateStatusResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/services/BoardService.ts b/src/client/services/BoardService.ts new file mode 100644 index 0000000..8cc7d59 --- /dev/null +++ b/src/client/services/BoardService.ts @@ -0,0 +1,119 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { CreateBoardRequest } from '../models/CreateBoardRequest'; +import type { CreateBoardResponse } from '../models/CreateBoardResponse'; +import type { DeleteBoardResponse } from '../models/DeleteBoardResponse'; +import type { GetBoardsResponse } from '../models/GetBoardsResponse'; +import type { UpdateBoardOrderRequest } from '../models/UpdateBoardOrderRequest'; +import type { UpdateBoardOrderResponse } from '../models/UpdateBoardOrderResponse'; +import type { UpdateBoardRequest } from '../models/UpdateBoardRequest'; +import type { UpdateBoardResponse } from '../models/UpdateBoardResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; +export class BoardService { + /** + * Get Boards + * @returns GetBoardsResponse Successful Response + * @throws ApiError + */ + public static getBoards({ + projectId, + }: { + projectId: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/board/{project_id}', + path: { + 'project_id': projectId, + }, + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Create Board + * @returns CreateBoardResponse Successful Response + * @throws ApiError + */ + public static createBoard({ + requestBody, + }: { + requestBody: CreateBoardRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/board/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Board + * @returns UpdateBoardResponse Successful Response + * @throws ApiError + */ + public static updateBoard({ + requestBody, + }: { + requestBody: UpdateBoardRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/board/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Board Order + * @returns UpdateBoardOrderResponse Successful Response + * @throws ApiError + */ + public static updateBoardOrder({ + requestBody, + }: { + requestBody: UpdateBoardOrderRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/board/order', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Delete Board + * @returns DeleteBoardResponse Successful Response + * @throws ApiError + */ + public static deleteBoard({ + boardId, + }: { + boardId: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/board/{board_id}', + path: { + 'board_id': boardId, + }, + errors: { + 422: `Validation Error`, + }, + }); + } +} diff --git a/src/client/services/DealGroupService.ts b/src/client/services/DealGroupService.ts new file mode 100644 index 0000000..4b0b5e8 --- /dev/null +++ b/src/client/services/DealGroupService.ts @@ -0,0 +1,119 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { DealAddToGroupRequest } from '../models/DealAddToGroupRequest'; +import type { DealAddToGroupResponse } from '../models/DealAddToGroupResponse'; +import type { DealCreateGroupRequest } from '../models/DealCreateGroupRequest'; +import type { DealCreateGroupResponse } from '../models/DealCreateGroupResponse'; +import type { DealGroupChangeStatusRequest } from '../models/DealGroupChangeStatusRequest'; +import type { DealGroupChangeStatusResponse } from '../models/DealGroupChangeStatusResponse'; +import type { DealGroupUpdateRequest } from '../models/DealGroupUpdateRequest'; +import type { DealGroupUpdateResponse } from '../models/DealGroupUpdateResponse'; +import type { DealRemoveFromGroupRequest } from '../models/DealRemoveFromGroupRequest'; +import type { DealRemoveFromGroupResponse } from '../models/DealRemoveFromGroupResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; +export class DealGroupService { + /** + * Create Group + * @returns DealCreateGroupResponse Successful Response + * @throws ApiError + */ + public static createDealGroup({ + requestBody, + }: { + requestBody: DealCreateGroupRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal-group/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Group + * @returns DealGroupUpdateResponse Successful Response + * @throws ApiError + */ + public static updateDealGroup({ + requestBody, + }: { + requestBody: DealGroupUpdateRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/deal-group/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Change Status + * @returns DealGroupChangeStatusResponse Successful Response + * @throws ApiError + */ + public static changeStatus({ + requestBody, + }: { + requestBody: DealGroupChangeStatusRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/deal-group/change-status', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Add Deal + * @returns DealAddToGroupResponse Successful Response + * @throws ApiError + */ + public static addDeal({ + requestBody, + }: { + requestBody: DealAddToGroupRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/deal-group/deal', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Remove Deal + * @returns DealRemoveFromGroupResponse Successful Response + * @throws ApiError + */ + public static removeDeal({ + requestBody, + }: { + requestBody: DealRemoveFromGroupRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/deal-group/deal', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } +} diff --git a/src/client/services/DealService.ts b/src/client/services/DealService.ts index 6687887..cda8a32 100644 --- a/src/client/services/DealService.ts +++ b/src/client/services/DealService.ts @@ -13,17 +13,12 @@ import type { DealAddServiceRequest } from '../models/DealAddServiceRequest'; import type { DealAddServiceResponse } from '../models/DealAddServiceResponse'; import type { DealAddServicesRequest } from '../models/DealAddServicesRequest'; import type { DealAddServicesResponse } from '../models/DealAddServicesResponse'; -import type { DealAddToGroupRequest } from '../models/DealAddToGroupRequest'; -import type { DealAddToGroupResponse } from '../models/DealAddToGroupResponse'; import type { DealChangeStatusRequest } from '../models/DealChangeStatusRequest'; import type { DealChangeStatusResponse } from '../models/DealChangeStatusResponse'; import type { DealCompleteRequest } from '../models/DealCompleteRequest'; import type { DealCompleteResponse } from '../models/DealCompleteResponse'; -import type { DealCreateGroupRequest } from '../models/DealCreateGroupRequest'; -import type { DealCreateGroupResponse } from '../models/DealCreateGroupResponse'; import type { DealCreateGuestUrlRequest } from '../models/DealCreateGuestUrlRequest'; import type { DealCreateGuestUrlResponse } from '../models/DealCreateGuestUrlResponse'; -import type { DealCreateRequest } from '../models/DealCreateRequest'; import type { DealDeleteProductRequest } from '../models/DealDeleteProductRequest'; import type { DealDeleteProductResponse } from '../models/DealDeleteProductResponse'; import type { DealDeleteProductsRequest } from '../models/DealDeleteProductsRequest'; @@ -35,10 +30,6 @@ import type { DealDeleteServiceResponse } from '../models/DealDeleteServiceRespo import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest'; import type { DealDeleteServicesResponse } from '../models/DealDeleteServicesResponse'; import type { DealGetAllResponse } from '../models/DealGetAllResponse'; -import type { DealGroupChangeStatusRequest } from '../models/DealGroupChangeStatusRequest'; -import type { DealGroupChangeStatusResponse } from '../models/DealGroupChangeStatusResponse'; -import type { DealGroupUpdateRequest } from '../models/DealGroupUpdateRequest'; -import type { DealGroupUpdateResponse } from '../models/DealGroupUpdateResponse'; import type { DealPrefillRequest } from '../models/DealPrefillRequest'; import type { DealPrefillResponse } from '../models/DealPrefillResponse'; import type { DealProductAddKitRequest } from '../models/DealProductAddKitRequest'; @@ -47,8 +38,6 @@ import type { DealQuickCreateRequest } from '../models/DealQuickCreateRequest'; import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse'; import type { DealRecalculatePriceRequest } from '../models/DealRecalculatePriceRequest'; import type { DealRecalculatePriceResponse } from '../models/DealRecalculatePriceResponse'; -import type { DealRemoveFromGroupRequest } from '../models/DealRemoveFromGroupRequest'; -import type { DealRemoveFromGroupResponse } from '../models/DealRemoveFromGroupResponse'; import type { DealSchema } from '../models/DealSchema'; import type { DealServicesCopyRequest } from '../models/DealServicesCopyRequest'; import type { DealServicesCopyResponse } from '../models/DealServicesCopyResponse'; @@ -74,26 +63,6 @@ import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; export class DealService { - /** - * Create - * @returns any Successful Response - * @throws ApiError - */ - public static createDealCreatePost({ - requestBody, - }: { - requestBody: DealCreateRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/create', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } /** * Delete * @returns DealDeleteResponse Successful Response @@ -750,104 +719,4 @@ export class DealService { }, }); } - /** - * Add To Group - * @returns DealAddToGroupResponse Successful Response - * @throws ApiError - */ - public static addDealToGroup({ - requestBody, - }: { - requestBody: DealAddToGroupRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/add-to-group', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * Create Group - * @returns DealCreateGroupResponse Successful Response - * @throws ApiError - */ - public static createDealGroup({ - requestBody, - }: { - requestBody: DealCreateGroupRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/create-group', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * Remove From Group - * @returns DealRemoveFromGroupResponse Successful Response - * @throws ApiError - */ - public static removeDealFromGroup({ - requestBody, - }: { - requestBody: DealRemoveFromGroupRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/remove-from-group', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * Update Group - * @returns DealGroupUpdateResponse Successful Response - * @throws ApiError - */ - public static updateDealGroup({ - requestBody, - }: { - requestBody: DealGroupUpdateRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/group/update', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * Change Group Status - * @returns DealGroupChangeStatusResponse Successful Response - * @throws ApiError - */ - public static changeDealGroupStatus({ - requestBody, - }: { - requestBody: DealGroupChangeStatusRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/deal/group/change-status', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } } diff --git a/src/client/services/ProjectService.ts b/src/client/services/ProjectService.ts new file mode 100644 index 0000000..c05dfc4 --- /dev/null +++ b/src/client/services/ProjectService.ts @@ -0,0 +1,87 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { CreateProjectRequest } from '../models/CreateProjectRequest'; +import type { CreateProjectResponse } from '../models/CreateProjectResponse'; +import type { DeleteProjectResponse } from '../models/DeleteProjectResponse'; +import type { GetProjectsResponse } from '../models/GetProjectsResponse'; +import type { UpdateProjectRequest } from '../models/UpdateProjectRequest'; +import type { UpdateProjectResponse } from '../models/UpdateProjectResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; +export class ProjectService { + /** + * Get Projects + * @returns GetProjectsResponse Successful Response + * @throws ApiError + */ + public static getProjects(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/project/', + }); + } + /** + * Create Project + * @returns CreateProjectResponse Successful Response + * @throws ApiError + */ + public static createProject({ + requestBody, + }: { + requestBody: CreateProjectRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/project/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Project + * @returns UpdateProjectResponse Successful Response + * @throws ApiError + */ + public static updateProject({ + requestBody, + }: { + requestBody: UpdateProjectRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/project/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Delete Project + * @returns DeleteProjectResponse Successful Response + * @throws ApiError + */ + public static deleteProject({ + projectId, + }: { + projectId: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/project/{project_id}', + path: { + 'project_id': projectId, + }, + errors: { + 422: `Validation Error`, + }, + }); + } +} diff --git a/src/client/services/StatusService.ts b/src/client/services/StatusService.ts new file mode 100644 index 0000000..fe1a8e3 --- /dev/null +++ b/src/client/services/StatusService.ts @@ -0,0 +1,97 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { CreateStatusRequest } from '../models/CreateStatusRequest'; +import type { CreateStatusResponse } from '../models/CreateStatusResponse'; +import type { DeleteStatusResponse } from '../models/DeleteStatusResponse'; +import type { UpdateStatusOrderRequest } from '../models/UpdateStatusOrderRequest'; +import type { UpdateStatusOrderResponse } from '../models/UpdateStatusOrderResponse'; +import type { UpdateStatusRequest } from '../models/UpdateStatusRequest'; +import type { UpdateStatusResponse } from '../models/UpdateStatusResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; +export class StatusService { + /** + * Create Status + * @returns CreateStatusResponse Successful Response + * @throws ApiError + */ + public static createStatus({ + requestBody, + }: { + requestBody: CreateStatusRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/status/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Status + * @returns UpdateStatusResponse Successful Response + * @throws ApiError + */ + public static updateStatus({ + requestBody, + }: { + requestBody: UpdateStatusRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/status/', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update Status Order + * @returns UpdateStatusOrderResponse Successful Response + * @throws ApiError + */ + public static updateStatusOrder({ + requestBody, + }: { + requestBody: UpdateStatusOrderRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/status/order', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Delete Status + * @returns DeleteStatusResponse Successful Response + * @throws ApiError + */ + public static deleteStatus({ + statusId, + }: { + statusId: number, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/status/{status_id}', + path: { + 'status_id': statusId, + }, + errors: { + 422: `Validation Error`, + }, + }); + } +} diff --git a/src/components/BoardSelect/BoardSelect.tsx b/src/components/BoardSelect/BoardSelect.tsx new file mode 100644 index 0000000..4d2ae72 --- /dev/null +++ b/src/components/BoardSelect/BoardSelect.tsx @@ -0,0 +1,54 @@ +import ObjectSelect, { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx"; +import { FC, useEffect, useState } from "react"; +import { BoardSchema, BoardService, ProjectSchema } from "../../client"; + +type OtherProps = { + project: ProjectSchema | null; +} + +type SelectProps = Omit, "data" | "getLabelFn" | "getValueFn">; + +type Props = OtherProps & SelectProps; + +const BoardSelect: FC = ({ project, ...props }) => { + const [boards, setBoards] = useState([]); + const [isInitial, setIsInitial] = useState(true); + + const onClear = () => props.onChange(null); + + const fetchBoards = () => { + if (!project?.id) { + setBoards([]); + return; + } + + BoardService.getBoards({ + projectId: project?.id, + }) + .then(({ boards }) => { + setBoards(boards); + }) + .catch(err => console.log(err)); + }; + + useEffect(() => { + fetchBoards(); + if (isInitial) { + setIsInitial(false); + } else { + onClear(); + } + }, [project?.id]); + + return ( + + ); +}; + +export default BoardSelect; diff --git a/src/components/DealStatusSelect/DealStatusSelect.tsx b/src/components/DealStatusSelect/DealStatusSelect.tsx new file mode 100644 index 0000000..fcc9c6b --- /dev/null +++ b/src/components/DealStatusSelect/DealStatusSelect.tsx @@ -0,0 +1,40 @@ +import ObjectSelect, { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx"; +import { FC, useEffect, useState } from "react"; +import { BoardSchema, StatusSchema } from "../../client"; + +type OtherProps = { + board: BoardSchema | null; +} + +type SelectProps = Omit, "data" | "getLabelFn" | "getValueFn">; + +type Props = OtherProps & SelectProps; + +const DealStatusSelect: FC = ({ board, ...props}) => { + const [isInitial, setIsInitial] = useState(true); + + const filteredData = board?.dealStatuses.filter( + status => !status.isDeleted, + ) ?? []; + + const onClear = () => props.onChange(null); + + useEffect(() => { + if (isInitial) { + setIsInitial(false); + } else { + onClear(); + } + }, [board?.id]); + + return ( + + ); +}; +export default DealStatusSelect; diff --git a/src/components/Dnd/Boards/Board/Board.module.scss b/src/components/Dnd/Boards/Board/Board.module.scss new file mode 100644 index 0000000..e3063e1 --- /dev/null +++ b/src/components/Dnd/Boards/Board/Board.module.scss @@ -0,0 +1,37 @@ +.boards-select-element { + border-bottom: solid gray 1px; +} + +.board { + padding: 0.5em 1em 0.3em 1em; + text-wrap: nowrap; + cursor: pointer !important; +} + +.selected-board { + padding: 0.5em 1em 0.3em 1em; + text-wrap: nowrap; + border-radius: var(--item-border-radius); + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border: solid gray 1px; + border-bottom: none; +} + +.board-during-dnd { + background-color: var(--color-gray-10); +} + +.board::after { + content: ""; +} + +.board-drag-over { + @mixin light { + background-color: var(--mantine-color-gray-1); + } + @mixin dark { + background-color: var(--mantine-color-dark-5); + } + border-radius: var(--item-border-radius); +} diff --git a/src/components/Dnd/Boards/Board/Board.tsx b/src/components/Dnd/Boards/Board/Board.tsx new file mode 100644 index 0000000..8205b91 --- /dev/null +++ b/src/components/Dnd/Boards/Board/Board.tsx @@ -0,0 +1,97 @@ +import { Draggable, Droppable } from "@hello-pangea/dnd"; +import { BoardSchema } from "../../../../client"; +import { useContextMenu } from "mantine-contextmenu"; +import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react"; +import classNames from "classnames"; +import styles from "./Board.module.scss"; +import useStatus from "../../Statuses/Status/hooks/useStatus.tsx"; + + +type Props = { + board: BoardSchema; + selectedBoard: BoardSchema | null; + setSelectedBoard: (board: BoardSchema) => void; + onEditBoardClick: (board: BoardSchema) => void; + onDeleteBoardClick: (board: BoardSchema) => void; + isBoardDragEnded: boolean; + refetch: () => void; +} + +const Board = ({ + board, + selectedBoard, + setSelectedBoard, + onEditBoardClick, + onDeleteBoardClick, + isBoardDragEnded, + refetch, + }: Props) => { + + const { showContextMenu } = useContextMenu(); + + const { onCreateStatusClick } = useStatus({ refetch }); + + const contextMenu = (board: BoardSchema) => showContextMenu([ + { + key: "complete", + onClick: () => onEditBoardClick(board), + title: "Переименовать", + icon: , + }, + { + key: "add-status", + onClick: () => onCreateStatusClick(board), + title: "Новый статус", + icon: , + }, + { + key: "delete", + onClick: () => onDeleteBoardClick(board), + title: "Удалить", + icon: , + }, + ]); + + return ( + + {provided => ( +
+ + {(provided) => ( +
setSelectedBoard(board)} + onContextMenu={contextMenu(board)} + > + {board.name} +
+ )} +
+ {provided.placeholder} +
+ )} +
+ ); +}; + +export default Board; diff --git a/src/components/Dnd/Boards/Boards/Boards.tsx b/src/components/Dnd/Boards/Boards/Boards.tsx new file mode 100644 index 0000000..8414fc0 --- /dev/null +++ b/src/components/Dnd/Boards/Boards/Boards.tsx @@ -0,0 +1,90 @@ +import { Box, Center, Group, Stack } from "@mantine/core"; +import { DragDropContext } from "@hello-pangea/dnd"; +import { BoardSchema, DealSummary, ProjectSchema } from "../../../../client"; +import { IconPlus } from "@tabler/icons-react"; +import useBoards from "./hooks/useBoards.tsx"; +import Statuses from "../../Statuses/Statuses/Statuses.tsx"; +import Board from "../Board/Board.tsx"; +import useBoardsDnd from "./hooks/useBoardsDnd.tsx"; +import PrefillDealsWithExcelDrawer + from "../../../../pages/DealsPage/drawers/PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.tsx"; + + +type Props = { + project: ProjectSchema | null; + summariesRaw: DealSummary[]; + refetchSummaries: () => void; + boards: BoardSchema[]; + refetchBoards: () => void; +} + +const Boards = (props: Props) => { + const { + selectedBoard, + setSelectedBoard, + onCreateBoardClick, + onEditBoardClick, + onDeleteBoardClick, + } = useBoards(props); + + const { + onBoardDragEnd, + isBoardDragEnded, + setIsBoardDragEnded, + } = useBoardsDnd(props); + + const getBoardsTabs = () => { + return ( + { + setIsBoardDragEnded(false); + }} + onDragEnd={onBoardDragEnd} + > + + {props.boards.map((board: BoardSchema) => ( + + ))} +
+ +
+ +
+
+ ); + }; + + return ( + + {getBoardsTabs()} + + + + ); +}; + +export default Boards; diff --git a/src/components/Dnd/Boards/Boards/hooks/useBoards.tsx b/src/components/Dnd/Boards/Boards/hooks/useBoards.tsx new file mode 100644 index 0000000..d0d7e53 --- /dev/null +++ b/src/components/Dnd/Boards/Boards/hooks/useBoards.tsx @@ -0,0 +1,83 @@ +import { useEffect, useState } from "react"; +import { BoardSchema, BoardService, ProjectSchema } from "../../../../../client"; +import { modals } from "@mantine/modals"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; + +type Props = { + boards: BoardSchema[]; + refetchBoards: () => void; + project: ProjectSchema | null; +} + +const useBoards = ({ boards, refetchBoards, project }: Props) => { + const [selectedBoard, setSelectedBoard] = useState(null); + + useEffect(() => { + if (boards.length > 0 && selectedBoard === null) { + setSelectedBoard(boards[0]); + return; + } + + if (selectedBoard) { + // Update selected board after changing all boards + let newBoard = boards.find(board => board.id === selectedBoard.id); + + if (!newBoard && boards.length > 0) { + newBoard = boards[0] + } + setSelectedBoard(newBoard ?? null); + } + }, [boards]); + + const onEditBoardClick = (board: BoardSchema) => { + if (!project) return; + modals.openContextModal({ + modal: "boardModal", + title: "Редактирование доски", + withCloseButton: false, + innerProps: { + projectId: project.id, + board, + refetchBoards, + }, + }); + }; + + const onCreateBoardClick = () => { + if (!project) return; + modals.openContextModal({ + modal: "boardModal", + title: "Добавление доски", + withCloseButton: false, + innerProps: { + projectId: project.id, + refetchBoards, + }, + }); + }; + + const onDeleteBoardClick = (board: BoardSchema) => { + if (!board) return; + BoardService.deleteBoard({ + boardId: board.id, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetchBoards(); + }) + .catch(err => console.log(err)); + }; + + return { + selectedBoard, + setSelectedBoard, + onCreateBoardClick, + onEditBoardClick, + onDeleteBoardClick, + }; +}; + +export default useBoards; diff --git a/src/components/Dnd/Boards/Boards/hooks/useBoardsDnd.tsx b/src/components/Dnd/Boards/Boards/hooks/useBoardsDnd.tsx new file mode 100644 index 0000000..e018fdf --- /dev/null +++ b/src/components/Dnd/Boards/Boards/hooks/useBoardsDnd.tsx @@ -0,0 +1,53 @@ +import { DropResult } from "@hello-pangea/dnd"; +import { BoardSchema, BoardService } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; +import { useState } from "react"; + + +type Props = { + boards: BoardSchema[]; + refetchBoards: () => void; +} + +const useBoardsDnd = ({ boards, refetchBoards }: Props) => { + const [isBoardDragEnded, setIsBoardDragEnded] = useState(true); + + const updateBoardOrder = (board: BoardSchema, newOrdinalNumber: number) => { + BoardService.updateBoardOrder({ + requestBody: { + projectId: board.projectId, + boardId: board.id, + newOrdinalNumber, + } + }) + .then(({ ok, message }) => { + if (!ok) notifications.error({ message }); + refetchBoards(); + }) + }; + + const onBoardDragEnd = async (result: DropResult) => { + setIsBoardDragEnded(true); + + // If there is no changes + if (!result.destination || result.destination == result.source) return; + + // Checking for valid dealId + const boardId = parseInt(result.draggableId); + if (isNaN(boardId)) return; + + // Checking for valid deal + const board = boards.find(board => board.id == boardId); + if (!board) return; + + updateBoardOrder(board, result.destination.index); + }; + + return { + onBoardDragEnd, + isBoardDragEnded, + setIsBoardDragEnded, + }; +}; + +export default useBoardsDnd; diff --git a/src/components/Dnd/DealSummaryCard/DealSummaryCard.tsx b/src/components/Dnd/DealSummaryCard/DealSummaryCard.tsx deleted file mode 100644 index 1b61ae0..0000000 --- a/src/components/Dnd/DealSummaryCard/DealSummaryCard.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { FC } from "react"; -import { DealService, DealSummary } from "../../../client"; -import styles from "./DealSummaryCard.module.css"; - -import { - ActionIcon, - Badge, - CopyButton, - Flex, - Image, - Indicator, - IndicatorProps, - Popover, - rem, - Text, - ThemeIcon, - Tooltip, -} from "@mantine/core"; -import { useDealPageContext } from "../../../pages/LeadsPage/contexts/DealPageContext.tsx"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCheck } from "@fortawesome/free-solid-svg-icons"; -import { DealStatus } from "../../../shared/enums/DealStatus.ts"; -import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react"; -import { useContextMenu } from "mantine-contextmenu"; -import useDealSummaryState from "./useDealSummaryState.tsx"; - -type Props = { - dealSummary: DealSummary; - color?: string -}; - -const DealSummaryCard: FC = ({ dealSummary, color }) => { - const { showContextMenu } = useContextMenu(); - const { setSelectedDeal } = useDealPageContext(); - const { onDelete, onComplete, onDeleteFromGroup } = useDealSummaryState(); - - const onDealSummaryClick = () => { - DealService.getDealById({ dealId: dealSummary.id }).then(deal => { - setSelectedDeal(deal); - }); - }; - const getIndicatorProps = (): IndicatorProps => { - if (!dealSummary.deliveryDate) - return { disabled: true }; - - const deliveryDate = new Date(dealSummary.deliveryDate); - const currentDate = new Date(); - const diff = deliveryDate.getTime() - currentDate.getTime(); - const diffDays = Math.ceil(diff / (1000 * 3600 * 24)); - - if (dealSummary.status < DealStatus.IN_DELIVERY) { - if (diffDays <= 2 && diffDays > 1) { - return { - color: "yellow", - }; - } - if (diffDays <= 1) { - return { - color: "red", - }; - } - - return { - disabled: false, - }; - } - return { disabled: true }; - }; - const isPaid = () => { - return dealSummary.billRequest?.paid || dealSummary.group?.billRequest?.paid; - } - const isLockedInsideGroup = () => { - return dealSummary.group && !dealSummary.group.billRequest; - } - return ( - - -
onDeleteFromGroup(dealSummary), - title: "Убрать из группы", - icon: , - }] : [], - { - key: "complete", - onClick: () => onComplete(dealSummary), - title: "Завершить", - icon: , - }, - { - key: "delete", - onClick: () => onDelete(dealSummary), - title: "Удалить", - icon: , - }, - ])} - onClick={() => onDealSummaryClick()} - className={styles["container"]} - style={{ backgroundColor: color }} - > - - - - - {dealSummary.clientName} - - - - - {dealSummary.name} - - - - {dealSummary.shipmentWarehouseName || "Склад не указан"} - - - {dealSummary.totalPrice.toLocaleString("ru-RU")} руб,{" "} - - - {dealSummary.totalProducts.toLocaleString("ru-RU")} тов. - - - - {dealSummary.deliveryDate && ( - - Доставка: {(new Date(dealSummary.deliveryDate)).toLocaleDateString("ru-RU")} - - )} - {dealSummary.receivingSlotDate && ( - - Слот: {(new Date(dealSummary.receivingSlotDate)).toLocaleDateString("ru-RU")} - - )} - - - - - {({ copy, copied }) => ( - - -
{ - e.stopPropagation(); - copy(); - }} - className={styles["flex-item"]}> - - ID: {dealSummary.id} - -
-
- - - - - ID сделки скопирован - - - -
- )} -
- {isPaid() && ( - - - - - - )} -
- - - - -
- -
- -
-
- - ); -}; -export default DealSummaryCard; diff --git a/src/components/Dnd/CreateDealButton/CreateDealButton.module.css b/src/components/Dnd/Deals/CreateDealButton/CreateDealButton.module.css similarity index 100% rename from src/components/Dnd/CreateDealButton/CreateDealButton.module.css rename to src/components/Dnd/Deals/CreateDealButton/CreateDealButton.module.css diff --git a/src/components/Dnd/CreateDealButton/CreateDealButton.tsx b/src/components/Dnd/Deals/CreateDealButton/CreateDealButton.tsx similarity index 88% rename from src/components/Dnd/CreateDealButton/CreateDealButton.tsx rename to src/components/Dnd/Deals/CreateDealButton/CreateDealButton.tsx index 7a29c6e..8c4eec1 100644 --- a/src/components/Dnd/CreateDealButton/CreateDealButton.tsx +++ b/src/components/Dnd/Deals/CreateDealButton/CreateDealButton.tsx @@ -3,12 +3,16 @@ import { useState } from "react"; import styles from "./CreateDealButton.module.css"; import { Text, Transition } from "@mantine/core"; import CreateDealFrom from "../CreateDealForm/CreateDealFrom.tsx"; -import { DealService } from "../../../client"; +import { DealService, StatusSchema } from "../../../../client"; import { useQueryClient } from "@tanstack/react-query"; -import { dateWithoutTimezone } from "../../../shared/lib/date.ts"; -import { usePrefillDealContext } from "../../../pages/LeadsPage/contexts/PrefillDealContext.tsx"; +import { dateWithoutTimezone } from "../../../../shared/lib/date.ts"; +import { usePrefillDealContext } from "../../../../pages/DealsPage/contexts/PrefillDealContext.tsx"; -const CreateDealButton = () => { +type Props = { + status: StatusSchema; +} + +const CreateDealButton = ({ status }: Props) => { const [isCreating, setIsCreating] = useState(false); const [isTransitionEnded, setIsTransitionEnded] = useState(true); const queryClient = useQueryClient(); @@ -43,6 +47,7 @@ const CreateDealButton = () => { acceptanceDate: dateWithoutTimezone( quickDeal.acceptanceDate, ), + statusId: status.id, }, }).then(async (result) => { if (prefillDeal) { diff --git a/src/components/Dnd/CreateDealForm/CreateDealForm.module.css b/src/components/Dnd/Deals/CreateDealForm/CreateDealForm.module.css similarity index 100% rename from src/components/Dnd/CreateDealForm/CreateDealForm.module.css rename to src/components/Dnd/Deals/CreateDealForm/CreateDealForm.module.css diff --git a/src/components/Dnd/CreateDealForm/CreateDealFrom.tsx b/src/components/Dnd/Deals/CreateDealForm/CreateDealFrom.tsx similarity index 87% rename from src/components/Dnd/CreateDealForm/CreateDealFrom.tsx rename to src/components/Dnd/Deals/CreateDealForm/CreateDealFrom.tsx index 6dad008..97f30b4 100644 --- a/src/components/Dnd/CreateDealForm/CreateDealFrom.tsx +++ b/src/components/Dnd/Deals/CreateDealForm/CreateDealFrom.tsx @@ -1,15 +1,15 @@ import { Button, rem, Textarea, TextInput } from "@mantine/core"; -import { QuickDeal } from "../../../types/QuickDeal.ts"; +import { QuickDeal } from "../../../../types/QuickDeal.ts"; import { FC } from "react"; import { useForm } from "@mantine/form"; import styles from "./CreateDealForm.module.css"; -import ClientAutocomplete from "../../Selects/ClientAutocomplete/ClientAutocomplete.tsx"; +import ClientAutocomplete from "../../../Selects/ClientAutocomplete/ClientAutocomplete.tsx"; import { DateTimePicker } from "@mantine/dates"; import ShippingWarehouseAutocomplete - from "../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx"; -import BaseMarketplaceSelect from "../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; -import ServicePriceCategorySelect from "../../Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx"; -import { usePrefillDealContext } from "../../../pages/LeadsPage/contexts/PrefillDealContext.tsx"; + from "../../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx"; +import BaseMarketplaceSelect from "../../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; +import ServicePriceCategorySelect from "../../../Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx"; +import { usePrefillDealContext } from "../../../../pages/DealsPage/contexts/PrefillDealContext.tsx"; type Props = { onSubmit: (quickDeal: QuickDeal) => void; diff --git a/src/components/Dnd/CreateDealsFromFileButton/CreateDealsFromFileButton.module.css b/src/components/Dnd/Deals/CreateDealsFromFileButton/CreateDealsFromFileButton.module.css similarity index 100% rename from src/components/Dnd/CreateDealsFromFileButton/CreateDealsFromFileButton.module.css rename to src/components/Dnd/Deals/CreateDealsFromFileButton/CreateDealsFromFileButton.module.css diff --git a/src/components/Dnd/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx b/src/components/Dnd/Deals/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx similarity index 79% rename from src/components/Dnd/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx rename to src/components/Dnd/Deals/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx index d623427..2e258a4 100644 --- a/src/components/Dnd/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx +++ b/src/components/Dnd/Deals/CreateDealsFromFileButton/CreateDealsFromFileButton.tsx @@ -1,6 +1,6 @@ import styles from "./CreateDealsFromFileButton.module.css"; import { Text } from "@mantine/core"; -import { usePrefillDealsWithExcelContext } from "../../../pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx"; +import { usePrefillDealsWithExcelContext } from "../../../../pages/DealsPage/contexts/PrefillDealsWithExcelContext.tsx"; const CreateDealsFromFileButton = () => { const { prefillWithExcelOnOpen } = usePrefillDealsWithExcelContext(); diff --git a/src/components/Dnd/DealGroupView/DealGroupView.tsx b/src/components/Dnd/Deals/DealGroupView/DealGroupView.tsx similarity index 94% rename from src/components/Dnd/DealGroupView/DealGroupView.tsx rename to src/components/Dnd/Deals/DealGroupView/DealGroupView.tsx index 9705341..d6562f5 100644 --- a/src/components/Dnd/DealGroupView/DealGroupView.tsx +++ b/src/components/Dnd/Deals/DealGroupView/DealGroupView.tsx @@ -1,10 +1,10 @@ -import { DealGroupSchema, DealService, DealSummary } from "../../../client"; +import { DealGroupSchema, DealGroupService, DealSummary } from "../../../../client"; import { FC, useEffect, useMemo, useState } from "react"; import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx"; import { Flex, rem, Text, TextInput, useMantineColorScheme } from "@mantine/core"; import { IconGripHorizontal } from "@tabler/icons-react"; import { useDebouncedValue } from "@mantine/hooks"; -import { notifications } from "../../../shared/lib/notifications.ts"; +import { notifications } from "../../../../shared/lib/notifications.ts"; type Props = { deals: DealSummary[]; @@ -19,7 +19,7 @@ export const DealGroupView: FC = ({ deals, group }) => { const totalProducts = useMemo(() => deals.reduce((acc, deal) => acc + deal.totalProducts, 0), [deals]); const updateName = () => { if (debouncedName === group.name) return; - DealService.updateDealGroup({ + DealGroupService.updateDealGroup({ requestBody: { data: { ...group, diff --git a/src/components/Dnd/DealSummaryCard/DealSummaryCard.module.css b/src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.module.css similarity index 100% rename from src/components/Dnd/DealSummaryCard/DealSummaryCard.module.css rename to src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.module.css diff --git a/src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.tsx b/src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.tsx new file mode 100644 index 0000000..66d78d6 --- /dev/null +++ b/src/components/Dnd/Deals/DealSummaryCard/DealSummaryCard.tsx @@ -0,0 +1,173 @@ +import { FC } from "react"; +import { DealService, DealSummary } from "../../../../client"; +import styles from "./DealSummaryCard.module.css"; + +import { ActionIcon, Badge, CopyButton, Flex, Image, Popover, rem, Text, ThemeIcon, Tooltip } from "@mantine/core"; +import { useDealPageContext } from "../../../../pages/DealsPage/contexts/DealPageContext.tsx"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faCheck } from "@fortawesome/free-solid-svg-icons"; +import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react"; +import { useContextMenu } from "mantine-contextmenu"; +import useDealSummaryState from "./useDealSummaryState.tsx"; + +type Props = { + dealSummary: DealSummary; + color?: string +}; + +const DealSummaryCard: FC = ({ dealSummary, color }) => { + const { showContextMenu } = useContextMenu(); + const { setSelectedDeal } = useDealPageContext(); + const { onDelete, onComplete, onDeleteFromGroup } = useDealSummaryState(); + + const onDealSummaryClick = () => { + DealService.getDealById({ dealId: dealSummary.id }).then(deal => { + setSelectedDeal(deal); + }); + }; + const isPaid = () => { + return dealSummary.billRequest?.paid || dealSummary.group?.billRequest?.paid; + }; + const isLockedInsideGroup = () => { + return dealSummary.group && !dealSummary.group.billRequest; + }; + return ( +
onDeleteFromGroup(dealSummary), + title: "Убрать из группы", + icon: , + }] : [], + { + key: "complete", + onClick: () => onComplete(dealSummary), + title: "Завершить", + icon: , + }, + { + key: "delete", + onClick: () => onDelete(dealSummary), + title: "Удалить", + icon: , + }, + ])} + onClick={() => onDealSummaryClick()} + className={styles["container"]} + style={{ backgroundColor: color }} + > + + + + + {dealSummary.clientName} + + + + + {dealSummary.name} + + + + {dealSummary.shipmentWarehouseName || "Склад не указан"} + + + {dealSummary.totalPrice.toLocaleString("ru-RU")} руб,{" "} + + + {dealSummary.totalProducts.toLocaleString("ru-RU")} тов. + + + + {dealSummary.deliveryDate && ( + + Доставка: {(new Date(dealSummary.deliveryDate)).toLocaleDateString("ru-RU")} + + )} + {dealSummary.receivingSlotDate && ( + + Слот: {(new Date(dealSummary.receivingSlotDate)).toLocaleDateString("ru-RU")} + + )} + + + + + {({ copy, copied }) => ( + + +
{ + e.stopPropagation(); + copy(); + }} + className={styles["flex-item"]}> + + ID: {dealSummary.id} + +
+
+ + + + + ID сделки скопирован + + + +
+ )} +
+ {isPaid() && ( + + + + + + )} +
+ + + + +
+
+
+ ); +}; +export default DealSummaryCard; diff --git a/src/components/Dnd/DealSummaryCard/useDealSummaryState.tsx b/src/components/Dnd/Deals/DealSummaryCard/useDealSummaryState.tsx similarity index 91% rename from src/components/Dnd/DealSummaryCard/useDealSummaryState.tsx rename to src/components/Dnd/Deals/DealSummaryCard/useDealSummaryState.tsx index 730025c..80c4102 100644 --- a/src/components/Dnd/DealSummaryCard/useDealSummaryState.tsx +++ b/src/components/Dnd/Deals/DealSummaryCard/useDealSummaryState.tsx @@ -1,8 +1,8 @@ -import { DealService, DealSummary } from "../../../client"; -import { useDealPageContext } from "../../../pages/LeadsPage/contexts/DealPageContext.tsx"; +import { DealGroupService, DealService, DealSummary } from "../../../../client"; +import { useDealPageContext } from "../../../../pages/DealsPage/contexts/DealPageContext.tsx"; import { modals } from "@mantine/modals"; import { Text } from "@mantine/core"; -import { notifications } from "../../../shared/lib/notifications.ts"; +import { notifications } from "../../../../shared/lib/notifications.ts"; const useDealSummaryState = () => { const { refetchDeals } = useDealPageContext(); @@ -76,7 +76,7 @@ const useDealSummaryState = () => { labels: { confirm: "Да", cancel: "Нет" }, confirmProps: { color: "red" }, onConfirm: () => { - DealService.removeDealFromGroup({ + DealGroupService.removeDeal({ requestBody: { dealId: summary.id, }, diff --git a/src/components/Dnd/Board/Board.module.css b/src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.module.css similarity index 67% rename from src/components/Dnd/Board/Board.module.css rename to src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.module.css index e4a3bef..b65d20d 100644 --- a/src/components/Dnd/Board/Board.module.css +++ b/src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.module.css @@ -5,15 +5,6 @@ flex: 1; } -.header { - display: flex; - align-items: stretch; - text-align: center; - flex-direction: column; - /*border: solid var(--item-border-size) var(--mantine-color-default-border);*/ - /*border-radius: var(--item-border-radius);*/ -} - .items-list { gap: 0.5rem; display: flex; diff --git a/src/components/Dnd/Board/Board.tsx b/src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.tsx similarity index 55% rename from src/components/Dnd/Board/Board.tsx rename to src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.tsx index dce463d..faaf85a 100644 --- a/src/components/Dnd/Board/Board.tsx +++ b/src/components/Dnd/Deals/DealsDndColumn/DealsDndColumn.tsx @@ -1,46 +1,37 @@ import { FC } from "react"; -import styles from "./Board.module.css"; -import { Divider, Text, Title } from "@mantine/core"; +import styles from "./DealsDndColumn.module.css"; import { Draggable, Droppable } from "@hello-pangea/dnd"; import CreateDealButton from "../CreateDealButton/CreateDealButton.tsx"; -import { DealGroupSchema, DealSummary } from "../../../client"; +import { DealGroupSchema, DealSummary, StatusSchema } from "../../../../client"; import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx"; import classNames from "classnames"; -import { getPluralForm } from "../../../shared/lib/utils.ts"; -import { groupBy, has, sum, uniq } from "lodash"; +import { groupBy, has, uniq } from "lodash"; import { DealGroupView } from "../DealGroupView/DealGroupView.tsx"; import CreateDealsFromFileButton from "../CreateDealsFromFileButton/CreateDealsFromFileButton.tsx"; +import DragState from "../../../../pages/DealsPage/enums/DragState.ts"; type Props = { - droppableId: string; - title: string; + status: StatusSchema; withCreateButton?: boolean; summaries: DealSummary[]; - color: string; + dragState: DragState; }; + type GroupWithDeals = { group: DealGroupSchema, deals: DealSummary[] } -export const Board: FC = ({ - droppableId, - title, - summaries, - color, - withCreateButton = false, - }) => { - const getDealsText = () => { - const pluralForm = getPluralForm( - summaries.length, - "сделка", - "сделки", - "сделок", - ); - return `${summaries.length} ${pluralForm}: ${sum(summaries.map(summary => summary.totalPrice)).toLocaleString("ru-RU")}₽`; - }; +export const DealsDndColumn: FC = ({ + status, + summaries, + dragState, + withCreateButton = false, + }) => { + const isDropDisabled = dragState === DragState.DRAG_STATUS; + const droppableId = status.id.toString(); + const isGroup = (obj: GroupWithDeals | DealSummary): obj is GroupWithDeals => { return has(obj, "deals"); }; - const getDealGroups = (): GroupWithDeals[] => { const groups = uniq(summaries.filter(s => s.group).map(summary => summary.group) as DealGroupSchema[]); if (groups.length === 0) return []; @@ -110,96 +101,89 @@ export const Board: FC = ({ }; const renderDeal = (deal: DealSummary) => { - return ( - {(provided, snapshot) => ( -
+ return ( + + {(provided, snapshot) => (
- -
+ {...provided.draggableProps} + {...provided.dragHandleProps} + ref={provided.innerRef}> +
+ +
-
- )} -
); + + )} + + ); }; const renderGroup = (obj: GroupWithDeals) => { const { deals, group } = obj; - return ( - {(provided) => ( -
- -
- )} -
); - }; - return ( -
-
- {title} - {getDealsText()} - -
- - {(provided, snapshot) => ( + return ( + + {(provided) => (
- {withCreateButton && ( - <> - - - - )} - {getDealsAndGroups().map(obj => { - if (isGroup(obj)) { - return renderGroup(obj); - } - return renderDeal(obj); - })} - {provided.placeholder} + > +
)} -
-
+ + ); + }; + return ( + + {(provided, snapshot) => ( +
+ {withCreateButton && ( + <> + + + + )} + {getDealsAndGroups().map(obj => { + if (isGroup(obj)) { + return renderGroup(obj); + } + return renderDeal(obj); + })} + {provided.placeholder} +
+ )} +
); }; -export default Board; +export default DealsDndColumn; diff --git a/src/components/Dnd/Deals/DealsDndColumn/hooks/useDealsDnd.tsx b/src/components/Dnd/Deals/DealsDndColumn/hooks/useDealsDnd.tsx new file mode 100644 index 0000000..d5763f1 --- /dev/null +++ b/src/components/Dnd/Deals/DealsDndColumn/hooks/useDealsDnd.tsx @@ -0,0 +1,213 @@ +import { modals } from "@mantine/modals"; +import { Flex } from "@mantine/core"; +import { DropResult } from "@hello-pangea/dnd"; +import { useEffect, useState } from "react"; +import { DealGroupService, DealService, DealSummary, DealSummaryReorderRequest } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; +import { dateWithoutTimezone } from "../../../../../shared/lib/date.ts"; + + +type Props = { + summariesRaw: DealSummary[]; + refetchSummaries: () => void; +} + +const useDealsDnd = ({ + summariesRaw, + refetchSummaries, + }: Props) => { + const [summaries, setSummaries] = useState(summariesRaw); + + useEffect(() => { + setSummaries(summariesRaw); + }, [summariesRaw]); + + const recalculate = async (dealId: number) => { + return DealService.recalculateDealPrice({ + requestBody: { + dealId: dealId, + }, + }).then(({ ok, message }) => { + notifications.guess(ok, { message }); + }); + }; + + const onDelete = (dealId: number) => { + const summary = summaries.find(summary => summary.id == dealId); + if (!summary) return; + modals.openConfirmModal({ + title: "Удаление сделки", + children: ( + + Вы действительно хотите удалить сделку {summary.name}? + + ), + onConfirm: () => { + DealService.deleteDeal({ + requestBody: { dealId: dealId }, + }).then(async ({ ok, message }) => { + notifications.guess(ok, { message }); + if (!ok) return; + await refetchSummaries(); + }); + }, + labels: { + confirm: "Удалить", + cancel: "Отмена", + }, + }); + }; + + const onSuccess = (dealId: number) => { + const summary = summaries.find(summary => summary.id == dealId); + if (!summary) return; + modals.openConfirmModal({ + title: "Завершение сделки", + children: ( + + Вы действительно хотите завершить сделку {summary.name}? + + ), + onConfirm: () => { + DealService.completeDeal({ + requestBody: { dealId: dealId }, + }).then(async ({ ok, message }) => { + notifications.guess(ok, { message }); + if (!ok) return; + await refetchSummaries(); + }); + }, + labels: { + confirm: "Завершить", + cancel: "Отмена", + }, + }); + }; + const onCombine = async (result: DropResult) => { + if (!result.combine) return; + const destination = result.combine.draggableId; + const source = result.draggableId; + if (!destination || !source) return; + const sourceId = parseInt(source); + if (destination.includes("group")) { + const groupId = parseInt(destination.split("-")[1]); + DealGroupService.addDeal({ + requestBody: { + dealId: sourceId, + groupId: groupId, + }, + }).then(async response => { + if (!response.ok) { + notifications.error({ message: response.message }); + return; + } + await refetchSummaries(); + await recalculate(sourceId); + await refetchSummaries(); + }); + } else { + const destinationId = parseInt(destination); + // creating new group + DealGroupService.createDealGroup({ + requestBody: { + draggingDealId: sourceId, + hoveredDealId: destinationId, + }, + }).then(async response => { + if (!response.ok) { + notifications.error({ message: response.message }); + return; + } + await refetchSummaries(); + await recalculate(sourceId); + await refetchSummaries(); + }); + return; + } + }; + const moveGroup = async (result: DropResult) => { + const groupId = parseInt(result.draggableId.split("-")[1]); + const destination = result.destination?.droppableId; + if (!destination) return; + const statusId = parseInt(destination); + DealGroupService.changeStatus({ + requestBody: { + groupId: groupId, + newStatus: statusId, + }, + }).then(async response => { + if (!response.ok) { + notifications.error({ message: response.message }); + return; + } + await refetchSummaries(); + }); + }; + + const onDealDragEnd = async (result: DropResult) => { + if (result.combine) { + return onCombine(result); + } + + // If there is no changes + if (!result.destination || result.destination == result.source) return; + + // Checking for valid dealId + if (result.draggableId.includes("group")) { + return moveGroup(result); + } + const dealId = parseInt(result.draggableId); + if (isNaN(dealId)) return; + + // Checking for valid deal + const summary = summaries.find(summary => summary.id == dealId); + if (!summary) return; + + // Checking if it is custom actions + const droppableId = result.destination.droppableId; + if (droppableId === "DELETE") { + onDelete(dealId); + return; + } + if (droppableId === "SUCCESS") { + onSuccess(dealId); + return; + } + + const statusId = Number.parseInt(droppableId); + const request: Partial = { + dealId, + index: result.destination.index, + statusId, + }; + if (statusId == summary.status.id) { + DealService.reorderDealSummaries({ + requestBody: request as DealSummaryReorderRequest, + }).then(async response => { + setSummaries(response.summaries); + await refetchSummaries(); + }); + return; + } + + DealService.reorderDealSummaries({ + requestBody: { + dealId, + statusId, + index: result.destination.index, + comment: "", + deadline: dateWithoutTimezone(new Date()), + }, + }).then(async response => { + setSummaries(response.summaries); + await refetchSummaries(); + }); + }; + + return { + summaries, + onDealDragEnd, + }; +}; + +export default useDealsDnd; diff --git a/src/components/Dnd/Deals/DealsDndColumn/utils/getColumnColor.ts b/src/components/Dnd/Deals/DealsDndColumn/utils/getColumnColor.ts new file mode 100644 index 0000000..e80987c --- /dev/null +++ b/src/components/Dnd/Deals/DealsDndColumn/utils/getColumnColor.ts @@ -0,0 +1,20 @@ +const colors = [ + "#4A90E2", + "#D3D3D3", + "#F5A623", + "#7ED321", + "#6A0DAD", + "#D0021B", + "#417505", +]; + +const getColumnColor = (colIndex: number) => { + if (colIndex < 0) return ""; + + if (colIndex >= colors.length) { + colIndex %= colors.length; + } + return colors[colIndex]; +} + +export default getColumnColor; diff --git a/src/components/Dnd/Deals/DealsDndFooter/DealsDndFooter.tsx b/src/components/Dnd/Deals/DealsDndFooter/DealsDndFooter.tsx new file mode 100644 index 0000000..6f8ff3c --- /dev/null +++ b/src/components/Dnd/Deals/DealsDndFooter/DealsDndFooter.tsx @@ -0,0 +1,66 @@ +import { Flex, rem } from "@mantine/core"; +import classNames from "classnames"; +import styles from "../../../../pages/DealsPage/ui/DealsPage.module.css"; +import { Droppable } from "@hello-pangea/dnd"; +import DragState from "../../../../pages/DealsPage/enums/DragState.ts"; + +type Props = { + dragState: DragState; +} + +const DealsDndFooter = ({ dragState }: Props) => { + const isDealDragEnded = dragState === DragState.DRAG_ENDED; + + return ( + +
+ + {(provided, snapshot) => ( + <> +
+ {!isDealDragEnded && + !snapshot.isDraggingOver && ( + Удалить + )} +
+ {provided.placeholder} + + )} +
+
+
+ + {(provided, snapshot) => ( + <> +
+ {!isDealDragEnded && + !snapshot.isDraggingOver && ( + + Успешно завершена + + )} +
+ {provided.placeholder} + + )} +
+
+
+ ); +}; + +export default DealsDndFooter; diff --git a/src/components/Dnd/Statuses/Status/Status.tsx b/src/components/Dnd/Statuses/Status/Status.tsx new file mode 100644 index 0000000..b5c8163 --- /dev/null +++ b/src/components/Dnd/Statuses/Status/Status.tsx @@ -0,0 +1,104 @@ +import styles from "../../../../pages/DealsPage/ui/DealsPage.module.css"; +import { Divider, Text, Title } from "@mantine/core"; +import getColumnColor from "../../Deals/DealsDndColumn/utils/getColumnColor.ts"; +import { DealSummary, StatusSchema } from "../../../../client"; +import { getPluralForm } from "../../../../shared/lib/utils.ts"; +import { sum } from "lodash"; +import { Draggable, Droppable } from "@hello-pangea/dnd"; +import DragState from "../../../../pages/DealsPage/enums/DragState.ts"; +import { useContextMenu } from "mantine-contextmenu"; +import { IconEdit, IconTrash } from "@tabler/icons-react"; +import useStatus from "./hooks/useStatus.tsx"; + + +type Props = { + status: StatusSchema; + index: number; + summaries: DealSummary[]; + dragState: DragState; + refetch: () => void; +} + +const Status = ({ summaries, status, dragState, index, refetch }: Props) => { + const isDropDisabled = dragState === DragState.DRAG_DEAL; + + const { + onEditStatusClick, + onDeleteStatusClick, + } = useStatus({ refetch }); + + const getDealsText = () => { + const pluralForm = getPluralForm( + summaries.length, + "сделка", + "сделки", + "сделок", + ); + return `${summaries.length} ${pluralForm}: ${sum(summaries.map(summary => summary.totalPrice)).toLocaleString("ru-RU")}₽`; + }; + + const { showContextMenu } = useContextMenu(); + + const contextMenu = () => showContextMenu([ + { + key: "complete", + onClick: () => onEditStatusClick(status), + title: "Переименовать", + icon: , + }, + { + key: "delete", + onClick: () => onDeleteStatusClick(status), + title: "Удалить", + icon: , + }, + ]); + + return ( + + {provided => ( +
+ + {(provided) => ( +
+ + {status.name} + + + {getDealsText()} + + +
+ )} +
+ {provided.placeholder} +
+ )} +
+ ); +}; + +export default Status; diff --git a/src/components/Dnd/Statuses/Status/hooks/useStatus.tsx b/src/components/Dnd/Statuses/Status/hooks/useStatus.tsx new file mode 100644 index 0000000..1ff1309 --- /dev/null +++ b/src/components/Dnd/Statuses/Status/hooks/useStatus.tsx @@ -0,0 +1,57 @@ +import { BoardSchema, StatusSchema, StatusService } from "../../../../../client"; +import { modals } from "@mantine/modals"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; + + +type Props = { + refetch: () => void; +} + +const useStatus = ({ refetch }: Props) => { + const onEditStatusClick = (status: StatusSchema) => { + modals.openContextModal({ + modal: "statusModal", + title: "Редактирование статуса", + withCloseButton: false, + innerProps: { + status, + refetch, + }, + }); + }; + + const onCreateStatusClick = (board: BoardSchema) => { + modals.openContextModal({ + modal: "statusModal", + title: "Добавление статуса", + withCloseButton: false, + innerProps: { + boardId: board.id, + refetch, + }, + }); + }; + + const onDeleteStatusClick = (status: StatusSchema) => { + if (!status) return; + StatusService.deleteStatus({ + statusId: status.id, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetch(); + }) + .catch(err => console.log(err)); + }; + + return { + onEditStatusClick, + onCreateStatusClick, + onDeleteStatusClick, + }; +}; + +export default useStatus; diff --git a/src/components/Dnd/Statuses/Statuses/Statuses.tsx b/src/components/Dnd/Statuses/Statuses/Statuses.tsx new file mode 100644 index 0000000..33f8e23 --- /dev/null +++ b/src/components/Dnd/Statuses/Statuses/Statuses.tsx @@ -0,0 +1,86 @@ +import { BoardSchema, DealSummary, StatusSchema } from "../../../../client"; +import DealsDndColumn from "../../Deals/DealsDndColumn/DealsDndColumn.tsx"; +import styles from "../../../../pages/DealsPage/ui/DealsPage.module.css"; +import DealsDndFooter from "../../Deals/DealsDndFooter/DealsDndFooter.tsx"; +import { Flex, rem, Stack } from "@mantine/core"; +import { DragDropContext } from "@hello-pangea/dnd"; +import useDnd from "../../../../pages/DealsPage/hooks/useDnd.tsx"; +import Status from "../Status/Status.tsx"; + + +type Props = { + selectedBoard: BoardSchema | null; + summariesRaw: DealSummary[]; + refetchSummaries: () => void; + refetchBoards: () => void; +} + +const Statuses = ({ + selectedBoard, + summariesRaw, + refetchSummaries, + refetchBoards, + }: Props) => { + const { + summaries, + dragState, + onDragStart, + onDragEnd, + } = useDnd({ + selectedBoard, + summariesRaw, + refetchSummaries, + refetchBoards, + }); + + const statusDndColumn = (status: StatusSchema, index: number) => { + const filteredSummaries = summaries.filter( + summary => summary.status.id == status.id, + ); + + return ( + + + + + ); + }; + + const statuses = selectedBoard?.dealStatuses + .filter(status => !status.isDeleted) + .sort((a, b) => a.ordinalNumber - b.ordinalNumber) ?? []; + + return ( + + + + {selectedBoard && + statuses.map(((status: StatusSchema, index: number) => { + return statusDndColumn(status, index); + })) + } + + + + + ); +}; + +export default Statuses; diff --git a/src/components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx b/src/components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx new file mode 100644 index 0000000..141917a --- /dev/null +++ b/src/components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx @@ -0,0 +1,50 @@ +import { DropResult } from "@hello-pangea/dnd"; +import { BoardSchema, StatusSchema, StatusService } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; + +type Props = { + board: BoardSchema | null; + refetch: () => void; +} + +const useStatusesDnd = ({ refetch, board }: Props) => { + const updateStatusOrder = (status: StatusSchema, newOrdinalNumber: number) => { + if (!board) return; + + StatusService.updateStatusOrder({ + requestBody: { + boardId: board.id, + statusId: status.id, + newOrdinalNumber, + }, + }) + .then(({ ok, message }) => { + if (!ok) notifications.error({ message }); + refetch(); + }); + }; + + const onStatusDragEnd = async (result: DropResult) => { + if (!board) return; + + // If there is no changes + if (!result.destination || result.destination == result.source) return; + + // Checking for valid dealId + const statusIdStr = result.draggableId.replace("status-", ""); + const statusId = parseInt(statusIdStr); + if (isNaN(statusId)) return; + + // Checking for valid deal + const status = board.dealStatuses.find(board => board.id == statusId); + if (!status) return; + + updateStatusOrder(status, result.destination.index); + }; + + return { + onStatusDragEnd, + }; +}; + +export default useStatusesDnd; diff --git a/src/components/ManagerSelect/ManagerSelect.tsx b/src/components/ManagerSelect/ManagerSelect.tsx index 6cdb7d9..370f040 100644 --- a/src/components/ManagerSelect/ManagerSelect.tsx +++ b/src/components/ManagerSelect/ManagerSelect.tsx @@ -1,7 +1,7 @@ import { FC } from "react"; import ObjectSelect, { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx"; import { UserSchema } from "../../client"; -import useManagersList from "../../pages/LeadsPage/hooks/useManagersList.tsx"; +import useManagersList from "../../pages/DealsPage/hooks/useManagersList.tsx"; type Props = Omit< ObjectSelectProps, @@ -15,6 +15,7 @@ const UserSelect: FC = props => { getLabelFn={(manager: UserSchema) => `${manager.firstName} ${manager.secondName}`} getValueFn={(manager: UserSchema) => manager.id.toString()} clearable + searchable {...props} onClear={() => props.onChange(null)} /> diff --git a/src/components/ProjectSelect/ProjectSelect.tsx b/src/components/ProjectSelect/ProjectSelect.tsx new file mode 100644 index 0000000..29992f6 --- /dev/null +++ b/src/components/ProjectSelect/ProjectSelect.tsx @@ -0,0 +1,43 @@ +import ObjectSelect, { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx"; +import { FC, useEffect, useState } from "react"; +import { ProjectSchema, ProjectService } from "../../client"; + +type OtherProps = { + data?: ProjectSchema[]; +} + +type SelectProps = Omit, "data" | "getLabelFn" | "getValueFn">; + +type Props = OtherProps & SelectProps; + +const ProjectSelect: FC = ({ data, ...props }) => { + const [projects, setProjects] = useState(data ?? []); + + const onClear = () => props.onChange(null); + + const fetchProjects = () => { + ProjectService.getProjects() + .then(({ projects }) => { + setProjects(projects); + }) + .catch(err => console.log(err)); + }; + + useEffect(() => { + if (!data) { + fetchProjects(); + } + }, []); + + return ( + + ); +}; + +export default ProjectSelect; diff --git a/src/modals/EmployeeTableModal/EmployeeTableModal.tsx b/src/modals/EmployeeTableModal/EmployeeTableModal.tsx index b617af2..d025970 100644 --- a/src/modals/EmployeeTableModal/EmployeeTableModal.tsx +++ b/src/modals/EmployeeTableModal/EmployeeTableModal.tsx @@ -1,4 +1,4 @@ -import SimpleUsersTable from "../../pages/LeadsPage/components/SimpleUsersTable/SimpleUsersTable.tsx"; +import SimpleUsersTable from "../../pages/DealsPage/components/SimpleUsersTable/SimpleUsersTable.tsx"; import { ContextModalProps } from "@mantine/modals"; import { Flex, rem } from "@mantine/core"; import { UserSchema } from "../../client"; diff --git a/src/modals/modals.ts b/src/modals/modals.ts index cf2c7ff..a681e96 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -3,13 +3,13 @@ import CreateServiceCategoryModal from "../pages/ServicesPage/modals/CreateServi import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.tsx"; import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx"; import ProductFormModal from "../pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx"; -import AddDealServiceModal from "../pages/LeadsPage/modals/AddDealServiceModal.tsx"; -import AddDealProductModal from "../pages/LeadsPage/modals/AddDealProductModal.tsx"; +import AddDealServiceModal from "../pages/DealsPage/modals/AddDealServiceModal.tsx"; +import AddDealProductModal from "../pages/DealsPage/modals/AddDealProductModal.tsx"; import PrintBarcodeModal from "./PrintBarcodeModal/PrintBarcodeModal.tsx"; import AddBarcodeModal from "./AddBarcodeModal/AddBarcodeModal.tsx"; import BarcodeTemplateFormModal from "../pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx"; -import ProductServiceFormModal from "../pages/LeadsPage/modals/ProductServiceFormModal.tsx"; +import ProductServiceFormModal from "../pages/DealsPage/modals/ProductServiceFormModal.tsx"; import UserFormModal from "../pages/AdminPage/modals/UserFormModal/UserFormModal.tsx"; import EmployeeSelectModal from "./EmployeeSelectModal/EmployeeSelectModal.tsx"; import EmployeeTableModal from "./EmployeeTableModal/EmployeeTableModal.tsx"; @@ -18,22 +18,25 @@ import PayRateFormModal from "../pages/AdminPage/modals/PayRateFormModal/PayRate import CreatePaymentRecordModal from "../pages/AdminPage/modals/CreatePaymentRecordModal/CreatePaymentRecordModal.tsx"; import ServiceKitModalForm from "../pages/ServicesPage/modals/ServicesKitModalForm.tsx"; import ServicesKitSelectModal from "./ServicesKitSelectModal/ServicesKitSelectModal.tsx"; -import SelectDealProductsModal from "../pages/LeadsPage/modals/SelectDealProductsModal.tsx"; +import SelectDealProductsModal from "../pages/DealsPage/modals/SelectDealProductsModal.tsx"; import ShippingWarehouseForm from "../pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx"; import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx"; import ServicePriceCategoryForm from "../pages/ServicesPage/modals/ServicePriceCategoryForm.tsx"; import ScanningModal from "./ScanningModal/ScanningModal.tsx"; import TransactionFormModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionFormModal.tsx"; import TransactionTagsModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionTagsModal.tsx"; -import ShippingProductModal from "../pages/LeadsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx"; +import ShippingProductModal from "../pages/DealsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx"; import DepartmentModal from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/DepartmentModal.tsx"; import AddUserToDepartmentModal from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/AddUserToDepartmentModal.tsx"; -import AssignUserModal from "../pages/LeadsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx"; +import AssignUserModal from "../pages/DealsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx"; import ResidualProductModal from "../pages/ResiduesPage/modals/ResidualProductModal/ResidualProductModal.tsx"; import NewReceiptModal from "../pages/ReceiptPage/components/NewReceipt/modals/NewReceiptModal.tsx"; import ReceiptModal from "../pages/ReceiptPage/components/ReceiptEditing/modals/ReceiptModal.tsx"; import SelectScannedProductModal from "../pages/ReceiptPage/modals/SelectScannedProductModal.tsx"; +import ProjectsModal from "../pages/DealsPage/modals/ProjectsModal/ProjectsModal.tsx"; +import BoardModal from "../pages/DealsPage/modals/BoardModal/BoardModal.tsx"; +import StatusModal from "../pages/DealsPage/modals/StatusModal/StatusModal.tsx"; export const modals = { enterDeadline: EnterDeadlineModal, @@ -70,4 +73,7 @@ export const modals = { departmentModal: DepartmentModal, addUserToDepartmentModal: AddUserToDepartmentModal, assignUserModal: AssignUserModal, + projectsModal: ProjectsModal, + boardModal: BoardModal, + statusModal: StatusModal, }; diff --git a/src/pages/DealPage/ui/DealPage.tsx b/src/pages/DealPage/ui/DealPage.tsx index e6689c8..20ad65b 100644 --- a/src/pages/DealPage/ui/DealPage.tsx +++ b/src/pages/DealPage/ui/DealPage.tsx @@ -1,6 +1,6 @@ import { useParams } from "@tanstack/react-router"; -import { DealPageContextProvider, useDealPageContext } from "../../LeadsPage/contexts/DealPageContext.tsx"; -import ProductAndServiceTab from "../../LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx"; +import { DealPageContextProvider, useDealPageContext } from "../../DealsPage/contexts/DealPageContext.tsx"; +import ProductAndServiceTab from "../../DealsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx"; import { FC, useEffect } from "react"; import { DealService } from "../../../client"; diff --git a/src/pages/LeadsPage/components/DealProductsTable/DealProductServiceTable.tsx b/src/pages/DealsPage/components/DealProductsTable/DealProductServiceTable.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealProductsTable/DealProductServiceTable.tsx rename to src/pages/DealsPage/components/DealProductsTable/DealProductServiceTable.tsx diff --git a/src/pages/LeadsPage/components/DealProductsTable/DealProductsTable.tsx b/src/pages/DealsPage/components/DealProductsTable/DealProductsTable.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealProductsTable/DealProductsTable.tsx rename to src/pages/DealsPage/components/DealProductsTable/DealProductsTable.tsx diff --git a/src/pages/LeadsPage/components/DealProductsTable/columns.tsx b/src/pages/DealsPage/components/DealProductsTable/columns.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealProductsTable/columns.tsx rename to src/pages/DealsPage/components/DealProductsTable/columns.tsx diff --git a/src/pages/LeadsPage/components/DealServicesTable/DealServicesTable.tsx b/src/pages/DealsPage/components/DealServicesTable/DealServicesTable.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealServicesTable/DealServicesTable.tsx rename to src/pages/DealsPage/components/DealServicesTable/DealServicesTable.tsx diff --git a/src/pages/LeadsPage/components/DealServicesTable/columns.tsx b/src/pages/DealsPage/components/DealServicesTable/columns.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealServicesTable/columns.tsx rename to src/pages/DealsPage/components/DealServicesTable/columns.tsx diff --git a/src/pages/LeadsPage/components/DealStatusChangeTable/DealStatusChangeTable.tsx b/src/pages/DealsPage/components/DealStatusChangeTable/DealStatusChangeTable.tsx similarity index 100% rename from src/pages/LeadsPage/components/DealStatusChangeTable/DealStatusChangeTable.tsx rename to src/pages/DealsPage/components/DealStatusChangeTable/DealStatusChangeTable.tsx diff --git a/src/pages/LeadsPage/components/DealStatusChangeTable/columns.tsx b/src/pages/DealsPage/components/DealStatusChangeTable/columns.tsx similarity index 81% rename from src/pages/LeadsPage/components/DealStatusChangeTable/columns.tsx rename to src/pages/DealsPage/components/DealStatusChangeTable/columns.tsx index d4dae7b..11b09ad 100644 --- a/src/pages/LeadsPage/components/DealStatusChangeTable/columns.tsx +++ b/src/pages/DealsPage/components/DealStatusChangeTable/columns.tsx @@ -1,10 +1,6 @@ import { useMemo } from "react"; import { MRT_ColumnDef } from "mantine-react-table"; import { DealStatusHistorySchema } from "../../../../client"; -import { - DealStatus, - DealStatusDictionary, -} from "../../../../shared/enums/DealStatus.ts"; import { Spoiler, Text } from "@mantine/core"; export const useDealStatusChangeTableColumns = () => { @@ -22,16 +18,12 @@ export const useDealStatusChangeTableColumns = () => { `${row.user.firstName} ${row.user.secondName}`, }, { - accessorKey: "fromStatus", + accessorKey: "fromStatus.name", header: "Из статуса", - accessorFn: row => - DealStatusDictionary[row.fromStatus as DealStatus], }, { - accessorKey: "toStatus", + accessorKey: "toStatus.name", header: "В статус", - accessorFn: row => - DealStatusDictionary[row.toStatus as DealStatus], }, { accessorKey: "comment", diff --git a/src/pages/DealsPage/components/DealStatusSelect/DealStatusSelect.tsx b/src/pages/DealsPage/components/DealStatusSelect/DealStatusSelect.tsx deleted file mode 100644 index b35f795..0000000 --- a/src/pages/DealsPage/components/DealStatusSelect/DealStatusSelect.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import ObjectSelect, { - ObjectSelectProps, -} from "../../../../components/ObjectSelect/ObjectSelect.tsx"; -import { FC } from "react"; -import { DealStatuses } from "../../../../shared/enums/DealStatus.ts"; - -type DealStatus = { - name: string; - id: number; -}; -type Props = Omit, "data">; - -const DealStatusSelect: FC = props => { - const data: DealStatus[] = DealStatuses; - return ( - - ); -}; -export default DealStatusSelect; diff --git a/src/pages/DealsPage/components/DealsTable/DealsTable.tsx b/src/pages/DealsPage/components/DealsTable/DealsTable.tsx index df1d22a..b3d9d81 100644 --- a/src/pages/DealsPage/components/DealsTable/DealsTable.tsx +++ b/src/pages/DealsPage/components/DealsTable/DealsTable.tsx @@ -6,7 +6,7 @@ import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx"; import { ActionIcon, Flex, Tooltip } from "@mantine/core"; import { IconEdit } from "@tabler/icons-react"; import { MRT_TableOptions } from "mantine-react-table"; -import { useDealPageContext } from "../../../LeadsPage/contexts/DealPageContext.tsx"; +import { useDealPageContext } from "../../contexts/DealPageContext.tsx"; type RestProps = { viewOnly?: boolean; diff --git a/src/pages/DealsPage/components/DealsTable/columns.tsx b/src/pages/DealsPage/components/DealsTable/columns.tsx index 8c41a79..29e8917 100644 --- a/src/pages/DealsPage/components/DealsTable/columns.tsx +++ b/src/pages/DealsPage/components/DealsTable/columns.tsx @@ -42,15 +42,6 @@ const useDealsTableColumns = () => { header: "Клиент", enableSorting: false, }, - { - Cell: ({ row }) => - new Date(row.original.deadline || 0).toLocaleString("ru-RU"), - accessorKey: "deadline", - header: "Дедлайн", - sortingFn: (rowA, rowB) => - new Date(rowB.original.deadline || 0).getTime() - - new Date(rowA.original.deadline || 0).getTime(), - }, { header: "Общая стоимость", Cell: ({ row }) => diff --git a/src/pages/DealsPage/components/LeadsPageHeader/LeadsPageHeader.tsx b/src/pages/DealsPage/components/LeadsPageHeader/LeadsPageHeader.tsx new file mode 100644 index 0000000..7b6166c --- /dev/null +++ b/src/pages/DealsPage/components/LeadsPageHeader/LeadsPageHeader.tsx @@ -0,0 +1,127 @@ +import { ActionIcon, Flex, rem, Text } from "@mantine/core"; +import { IconEdit, IconMenu2, IconMenuDeep } from "@tabler/icons-react"; +import { motion } from "framer-motion"; +import styles from "../../ui/DealsPage.module.css"; +import PageBlock from "../../../../components/PageBlock/PageBlock.tsx"; +import DisplayMode from "../../enums/DisplayMode.ts"; +import { UseFormReturnType } from "@mantine/form"; +import { DealsPageState } from "../../hooks/useDealsPageState.tsx"; +import React from "react"; +import { ProjectSchema } from "../../../../client"; +import { modals } from "@mantine/modals"; +import ObjectSelect from "../../../../components/ObjectSelect/ObjectSelect.tsx"; +import DealsTableFiltersModal from "../../modals/DealsTableFiltersModal.tsx"; + +type Props = { + displayMode: DisplayMode; + setDisplayMode: React.Dispatch>; + form: UseFormReturnType; + projects: ProjectSchema[]; + refetchProjects: () => void; +} + +const LeadsPageHeader = ({ + displayMode, + setDisplayMode, + form, + projects, + refetchProjects, + }: Props) => { + const openModal = () => { + modals.openContextModal({ + modal: "projectsModal", + title: "Проекты", + innerProps: { + onUpdate: refetchProjects, + }, + }); + }; + + const getHeaderInputsBoard = () => { + return ( +
+ + + + +
+ ); + }; + + const getHeaderInputsTable = () => { + return ( +
+ +
+ ); + }; + + return ( + + + + Вид + + + setDisplayMode(DisplayMode.BOARD) + } + variant={ + displayMode === DisplayMode.BOARD + ? "filled" + : "default" + }> + + + + setDisplayMode(DisplayMode.TABLE) + } + variant={ + displayMode === DisplayMode.TABLE + ? "filled" + : "default" + }> + + + + + + {getHeaderInputsTable()} + {getHeaderInputsBoard()} + + + + ); +}; + +export default LeadsPageHeader; diff --git a/src/pages/LeadsPage/components/SimpleUsersTable/SimpleUsersTable.tsx b/src/pages/DealsPage/components/SimpleUsersTable/SimpleUsersTable.tsx similarity index 100% rename from src/pages/LeadsPage/components/SimpleUsersTable/SimpleUsersTable.tsx rename to src/pages/DealsPage/components/SimpleUsersTable/SimpleUsersTable.tsx diff --git a/src/pages/LeadsPage/components/SimpleUsersTable/columns.tsx b/src/pages/DealsPage/components/SimpleUsersTable/columns.tsx similarity index 100% rename from src/pages/LeadsPage/components/SimpleUsersTable/columns.tsx rename to src/pages/DealsPage/components/SimpleUsersTable/columns.tsx diff --git a/src/pages/LeadsPage/contexts/DealPageContext.tsx b/src/pages/DealsPage/contexts/DealPageContext.tsx similarity index 100% rename from src/pages/LeadsPage/contexts/DealPageContext.tsx rename to src/pages/DealsPage/contexts/DealPageContext.tsx diff --git a/src/pages/LeadsPage/contexts/PrefillDealContext.tsx b/src/pages/DealsPage/contexts/PrefillDealContext.tsx similarity index 100% rename from src/pages/LeadsPage/contexts/PrefillDealContext.tsx rename to src/pages/DealsPage/contexts/PrefillDealContext.tsx diff --git a/src/pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx b/src/pages/DealsPage/contexts/PrefillDealsWithExcelContext.tsx similarity index 95% rename from src/pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx rename to src/pages/DealsPage/contexts/PrefillDealsWithExcelContext.tsx index af9682b..0ec0e0c 100644 --- a/src/pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx +++ b/src/pages/DealsPage/contexts/PrefillDealsWithExcelContext.tsx @@ -3,7 +3,7 @@ import { useDisclosure } from "@mantine/hooks"; import { DealsWithExcelForm, ProductExcelData } from "../drawers/PrefillDealWithExcelDrawer/types.tsx"; import { FileWithPath } from "@mantine/dropzone"; import { notifications } from "../../../shared/lib/notifications.ts"; -import { DealService, type ProductFromExcelSchema, ProductSchema } from "../../../client"; +import { DealService, type ProductFromExcelSchema, ProductSchema, StatusSchema } from "../../../client"; import UseExcelDropzone from "../../../types/UseExcelDropzone.tsx"; import { useForm, UseFormReturnType } from "@mantine/form"; import { useDealPageContext } from "./DealPageContext.tsx"; @@ -16,7 +16,7 @@ type PrefillDealsWithExcelContextState = { onProductSelectChange: (barcode: string, selectedProduct: ProductSchema) => void, onDrop: (files: FileWithPath[]) => void; excelDropzone: UseExcelDropzone; - createDeals: (values: DealsWithExcelForm) => void; + createDeals: (values: DealsWithExcelForm, status: StatusSchema) => void; form: UseFormReturnType; errors: string[]; }; @@ -24,6 +24,7 @@ type PrefillDealsWithExcelContextState = { const PrefillDealsWithExcelContext = createContext( undefined, ); + const usePrefillDealsWithExcelContextState = () => { const [prefillWithExcelOpened, { open, close }] = useDisclosure(false); const { refetchDeals } = useDealPageContext(); @@ -90,7 +91,7 @@ const usePrefillDealsWithExcelContextState = () => { form.reset(); }; - const createDeals = (values: DealsWithExcelForm) => { + const createDeals = (values: DealsWithExcelForm, status: StatusSchema) => { const products: ProductFromExcelSchema[] = barcodeProductsMap.entries().map(([, productData]) => { return { productId: productData.selectedProduct!.id, @@ -102,6 +103,7 @@ const usePrefillDealsWithExcelContextState = () => { requestBody: { products, clientId: values.client?.id ?? -1, + statusId: status.id, }, }) .then(({ ok, message }) => { diff --git a/src/pages/LeadsPage/drawers/DealEditDrawer/DealEditDrawer.module.css b/src/pages/DealsPage/drawers/DealEditDrawer/DealEditDrawer.module.css similarity index 100% rename from src/pages/LeadsPage/drawers/DealEditDrawer/DealEditDrawer.module.css rename to src/pages/DealsPage/drawers/DealEditDrawer/DealEditDrawer.module.css diff --git a/src/pages/LeadsPage/drawers/DealEditDrawer/DealEditDrawer.tsx b/src/pages/DealsPage/drawers/DealEditDrawer/DealEditDrawer.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/DealEditDrawer/DealEditDrawer.tsx rename to src/pages/DealsPage/drawers/DealEditDrawer/DealEditDrawer.tsx diff --git a/src/pages/LeadsPage/drawers/DealEditDrawer/tabs/ClientTab.tsx b/src/pages/DealsPage/drawers/DealEditDrawer/tabs/ClientTab.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/DealEditDrawer/tabs/ClientTab.tsx rename to src/pages/DealsPage/drawers/DealEditDrawer/tabs/ClientTab.tsx diff --git a/src/pages/LeadsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx b/src/pages/DealsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx similarity index 92% rename from src/pages/LeadsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx rename to src/pages/DealsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx index 9f2f0ad..f9096d9 100644 --- a/src/pages/LeadsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx +++ b/src/pages/DealsPage/drawers/DealEditDrawer/tabs/DealEditDrawerGeneralTab.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, useState } from "react"; import { useDealPageContext } from "../../../contexts/DealPageContext.tsx"; import { ActionIcon, @@ -14,8 +14,14 @@ import { Tooltip, } from "@mantine/core"; import { useForm } from "@mantine/form"; -import { ClientService, DealSchema, DealService, ShippingWarehouseSchema } from "../../../../../client"; -import { DealStatus, DealStatusDictionary } from "../../../../../shared/enums/DealStatus.ts"; +import { + ClientService, + DealSchema, + DealService, + ProjectSchema, + ShippingWarehouseSchema, + StatusSchema, +} from "../../../../../client"; import { isEqual } from "lodash"; import { notifications } from "../../../../../shared/lib/notifications.ts"; import { useQueryClient } from "@tanstack/react-query"; @@ -27,10 +33,13 @@ import ButtonCopy from "../../../../../components/ButtonCopy/ButtonCopy.tsx"; import FileSaver from "file-saver"; import { dateWithoutTimezone, getCurrentDateTimeForFilename } from "../../../../../shared/lib/date.ts"; import { IconBarcode, IconPrinter } from "@tabler/icons-react"; -import styles from "../../../ui/LeadsPage.module.css"; +import styles from "../../../ui/DealsPage.module.css"; import { base64ToBlob } from "../../../../../shared/lib/utils.ts"; import { DatePickerInput } from "@mantine/dates"; import ManagerSelect from "../../../../../components/ManagerSelect/ManagerSelect.tsx"; +import ProjectSelect from "../../../../../components/ProjectSelect/ProjectSelect.tsx"; +import BoardSelect from "../../../../../components/BoardSelect/BoardSelect.tsx"; +import DealStatusSelect from "../../../../../components/DealStatusSelect/DealStatusSelect.tsx"; type Props = { deal: DealSchema; @@ -42,6 +51,7 @@ const Content: FC = ({ deal }) => { const { setSelectedDeal } = useDealPageContext(); const clipboard = useClipboard(); const queryClient = useQueryClient(); + const [project, setProject] = useState(deal.board.project); // ignore typescript @@ -61,6 +71,8 @@ const Content: FC = ({ deal }) => { value.length > 0 ? null : "Название сделки не может быть пустым", + status: (value: StatusSchema) => + !value && "Статус для сделки не выбран", }, }); const updateDealInfo = async (values: DealGeneralFormType) => { @@ -147,15 +159,20 @@ const Content: FC = ({ deal }) => { "ru-RU", )} /> - + + {deal.category && ( { +type Props = { + board: BoardSchema | null; +} + +const PrefillDealsWithExcelDrawer = ({ board }: Props) => { const { prefillWithExcelOpened, prefillWithExcelOnClose, @@ -14,10 +19,12 @@ const PrefillDealsWithExcelDrawer = () => { } = usePrefillDealsWithExcelContext(); const getBody = () => { + if (!board || board.dealStatuses.length === 0) return; + if (barcodeProductsMap?.size === 0) { return ; } - return ; + return ; }; return ( diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/BreakdownByCityTable.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/BreakdownByCityTable.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/BreakdownByCityTable.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/BreakdownByCityTable.tsx diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ParsingResultsTooltip.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ParsingResultsTooltip.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ParsingResultsTooltip.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ParsingResultsTooltip.tsx diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx similarity index 94% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx index 3b10d60..8cacf52 100644 --- a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx +++ b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsPreview.tsx @@ -6,8 +6,13 @@ import { ProductExcelData } from "../types.tsx"; import BreakdownByCityTable from "./BreakdownByCityTable.tsx"; import ClientSelect from "../../../../../components/Selects/ClientSelect/ClientSelect.tsx"; import ParsingResultsTooltip from "./ParsingResultsTooltip.tsx"; +import { StatusSchema } from "../../../../../client"; -const ProductsPreview = () => { +type Props = { + status: StatusSchema; +} + +const ProductsPreview = ({ status }: Props) => { const { barcodeProductsMap, createDeals, form } = usePrefillDealsWithExcelContext(); const getTitle = (barcode: string, productsData: ProductExcelData) => { @@ -41,7 +46,7 @@ const ProductsPreview = () => { return ( Предпросмотр -
createDeals(values))}> + createDeals(values, status))}> ( diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsTable.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsTable.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsTable.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/components/ProductsTable.tsx diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/hooks/useBreakdownByCityTableColumns.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/hooks/useBreakdownByCityTableColumns.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/hooks/useBreakdownByCityTableColumns.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/hooks/useBreakdownByCityTableColumns.tsx diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/hooks/useProductsTableColumns.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/hooks/useProductsTableColumns.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/hooks/useProductsTableColumns.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/hooks/useProductsTableColumns.tsx diff --git a/src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/types.tsx b/src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/types.tsx similarity index 100% rename from src/pages/LeadsPage/drawers/PrefillDealWithExcelDrawer/types.tsx rename to src/pages/DealsPage/drawers/PrefillDealWithExcelDrawer/types.tsx diff --git a/src/pages/DealsPage/enums/DisplayMode.ts b/src/pages/DealsPage/enums/DisplayMode.ts new file mode 100644 index 0000000..a33c92c --- /dev/null +++ b/src/pages/DealsPage/enums/DisplayMode.ts @@ -0,0 +1,6 @@ +enum DisplayMode { + BOARD, + TABLE, +} + +export default DisplayMode; diff --git a/src/pages/DealsPage/enums/DragState.ts b/src/pages/DealsPage/enums/DragState.ts new file mode 100644 index 0000000..749ea36 --- /dev/null +++ b/src/pages/DealsPage/enums/DragState.ts @@ -0,0 +1,7 @@ +enum DragState { + DRAG_ENDED, + DRAG_DEAL, + DRAG_STATUS, +} + +export default DragState; diff --git a/src/pages/DealsPage/hooks/useBoards.tsx b/src/pages/DealsPage/hooks/useBoards.tsx new file mode 100644 index 0000000..f1bb355 --- /dev/null +++ b/src/pages/DealsPage/hooks/useBoards.tsx @@ -0,0 +1,33 @@ +import { useEffect, useState } from "react"; +import { BoardSchema, BoardService } from "../../../client"; + +type Props = { + projectId?: number; +} + +const useBoards = ({ projectId }: Props) => { + const [boards, setBoards] = useState([]); + + const refetchBoards = () => { + if (!projectId) return; + + BoardService.getBoards({ + projectId, + }) + .then(data => { + setBoards(data.boards); + }) + .catch(e => console.log(e)); + }; + + useEffect(() => { + refetchBoards(); + }, [projectId]); + + return { + boards, + refetchBoards, + }; +}; + +export default useBoards; diff --git a/src/pages/LeadsPage/hooks/useDealSummaries.tsx b/src/pages/DealsPage/hooks/useDealSummaries.tsx similarity index 100% rename from src/pages/LeadsPage/hooks/useDealSummaries.tsx rename to src/pages/DealsPage/hooks/useDealSummaries.tsx diff --git a/src/pages/DealsPage/hooks/useDealsPageState.tsx b/src/pages/DealsPage/hooks/useDealsPageState.tsx index 0b80cc0..68495e6 100644 --- a/src/pages/DealsPage/hooks/useDealsPageState.tsx +++ b/src/pages/DealsPage/hooks/useDealsPageState.tsx @@ -1,53 +1,90 @@ -import { useDealSummariesFull } from "../../LeadsPage/hooks/useDealSummaries.tsx"; +import { useDealSummariesFull } from "./useDealSummaries.tsx"; import { useForm } from "@mantine/form"; import { useEffect, useState } from "react"; -import { BaseMarketplaceSchema, ClientSchema } from "../../../client"; +import { BaseMarketplaceSchema, BoardSchema, ClientSchema, ProjectSchema } from "../../../client"; import { DealStatusType } from "../../../shared/enums/DealStatus.ts"; -type State = { + +type Props = { + projects: ProjectSchema[]; +} + +export type DealsPageState = { id: number | null; marketplace: BaseMarketplaceSchema | null; - dealStatus: DealStatusType | null; client: ClientSchema | null; + project: ProjectSchema | null; + + projectForTable: ProjectSchema | null; + board: BoardSchema | null; + dealStatus: DealStatusType | null; }; -const useDealsPageState = () => { + +const useDealsPageState = ({ projects }: Props) => { const { objects } = useDealSummariesFull(); - const form = useForm({ + + const form = useForm({ initialValues: { + project: null, id: null, marketplace: null, - dealStatus: null, client: null, + + projectForTable: null, + board: null, + dealStatus: null, }, }); + const [data, setData] = useState(objects); + const applyFilters = () => { let result = objects; if (form.values.id) { result = result.filter( - obj => obj.id === form.values.id - ) + obj => obj.id === form.values.id, + ); } if (form.values.marketplace) { result = result.filter( - obj => obj.baseMarketplace?.key === form.values.marketplace?.key + obj => obj.baseMarketplace?.key === form.values.marketplace?.key, ); } - if (form.values.dealStatus) { + if (form.values.projectForTable) { result = result.filter( - obj => obj.status === form.values.dealStatus?.id + obj => obj.board.projectId === form.values.project?.id, ); + + if (form.values.board) { + result = result.filter( + obj => obj.board.id === form.values.board?.id, + ); + + if (form.values.dealStatus) { + result = result.filter( + obj => obj.status.id === form.values.dealStatus?.id, + ); + } + } } if (form.values.client) { result = result.filter( - obj => obj.clientName === form.values.client?.name + obj => obj.clientName === form.values.client?.name, ); } setData(result); }; + useEffect(() => { applyFilters(); }, [form.values, objects]); + + useEffect(() => { + if (projects.length > 0 && form.values.project === null) { + form.setFieldValue("project", projects[0]); + } + }, [projects]); + return { data, form }; }; diff --git a/src/pages/DealsPage/hooks/useDnd.tsx b/src/pages/DealsPage/hooks/useDnd.tsx new file mode 100644 index 0000000..0a9d64d --- /dev/null +++ b/src/pages/DealsPage/hooks/useDnd.tsx @@ -0,0 +1,63 @@ +import { BoardSchema, DealSummary } from "../../../client"; +import { DragStart, DropResult } from "@hello-pangea/dnd"; +import { useState } from "react"; +import DragState from "../enums/DragState.ts"; +import useDealsDnd from "../../../components/Dnd/Deals/DealsDndColumn/hooks/useDealsDnd.tsx"; +import useStatusesDnd from "../../../components/Dnd/Statuses/Statuses/hooks/useStatusesDnd.tsx"; + + +type Props = { + selectedBoard: BoardSchema | null; + summariesRaw: DealSummary[]; + refetchSummaries: () => void; + refetchBoards: () => void; +} + +const useDnd = ({ + selectedBoard, + summariesRaw, + refetchSummaries, + refetchBoards, + }: Props) => { + const [dragState, setDragState] = useState(DragState.DRAG_ENDED); + + const { + summaries, + onDealDragEnd, + } = useDealsDnd({ + summariesRaw, + refetchSummaries, + }) + + const { + onStatusDragEnd, + } = useStatusesDnd({ + board: selectedBoard, + refetch: refetchBoards, + }); + + const onDragEnd = async (result: DropResult) => { + setDragState(DragState.DRAG_ENDED); + if (result.draggableId.includes("status")) { + return onStatusDragEnd(result); + } + return onDealDragEnd(result); + } + + const onDragStart = (start: DragStart) => { + if (start.source.droppableId.includes("status")) { + setDragState(DragState.DRAG_STATUS); + } else { + setDragState(DragState.DRAG_DEAL); + } + } + + return { + summaries, + dragState, + onDragStart, + onDragEnd, + }; +}; + +export default useDnd; diff --git a/src/pages/LeadsPage/hooks/useManagersList.tsx b/src/pages/DealsPage/hooks/useManagersList.tsx similarity index 100% rename from src/pages/LeadsPage/hooks/useManagersList.tsx rename to src/pages/DealsPage/hooks/useManagersList.tsx diff --git a/src/pages/DealsPage/hooks/useProjects.tsx b/src/pages/DealsPage/hooks/useProjects.tsx new file mode 100644 index 0000000..6b1b14f --- /dev/null +++ b/src/pages/DealsPage/hooks/useProjects.tsx @@ -0,0 +1,26 @@ +import { useEffect, useState } from "react"; +import { ProjectSchema, ProjectService } from "../../../client"; + + +const useProjects = () => { + const [projects, setProjects] = useState([]); + + const refetchProjects = () => { + ProjectService.getProjects() + .then(data => { + setProjects(data.projects); + }) + .catch(e => console.log(e)); + }; + + useEffect(() => { + refetchProjects(); + }, []); + + return { + projects, + refetchProjects, + }; +}; + +export default useProjects; diff --git a/src/pages/LeadsPage/modals/AddDealProductModal.tsx b/src/pages/DealsPage/modals/AddDealProductModal.tsx similarity index 100% rename from src/pages/LeadsPage/modals/AddDealProductModal.tsx rename to src/pages/DealsPage/modals/AddDealProductModal.tsx diff --git a/src/pages/LeadsPage/modals/AddDealServiceModal.tsx b/src/pages/DealsPage/modals/AddDealServiceModal.tsx similarity index 100% rename from src/pages/LeadsPage/modals/AddDealServiceModal.tsx rename to src/pages/DealsPage/modals/AddDealServiceModal.tsx diff --git a/src/pages/DealsPage/modals/BoardModal/BoardModal.tsx b/src/pages/DealsPage/modals/BoardModal/BoardModal.tsx new file mode 100644 index 0000000..9f206ce --- /dev/null +++ b/src/pages/DealsPage/modals/BoardModal/BoardModal.tsx @@ -0,0 +1,46 @@ +import { ContextModalProps } from "@mantine/modals"; +import { Button, Stack, TextInput } from "@mantine/core"; +import { BoardSchema } from "../../../../client"; +import useBoardModal from "./hooks/useBoardModal.tsx"; + +type Props = { + projectId: number; + board?: BoardSchema; + refetchBoards: () => void; +}; + +const BoardModal = ({ + context, + id, + innerProps, + }: ContextModalProps) => { + const closeModal = () => context.closeContextModal(id); + + const { + form, + onSubmit, + } = useBoardModal({ + ...innerProps, + closeModal, + }); + + return ( + onSubmit(values))}> + + + + + + ); +}; + +export default BoardModal; diff --git a/src/pages/DealsPage/modals/BoardModal/hooks/useBoardModal.tsx b/src/pages/DealsPage/modals/BoardModal/hooks/useBoardModal.tsx new file mode 100644 index 0000000..ab637bf --- /dev/null +++ b/src/pages/DealsPage/modals/BoardModal/hooks/useBoardModal.tsx @@ -0,0 +1,87 @@ +import { useForm } from "@mantine/form"; +import { BoardSchema, BoardService } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; + +type BoardForm = { + name: string; +} + +type Props = { + projectId: number; + board?: BoardSchema; + refetchBoards: () => void; + closeModal: () => void; +}; + +const useBoardModal = ({ + projectId, + board, + refetchBoards, + closeModal, + }: Props) => { + const form = useForm({ + initialValues: { + name: board ? board.name : "", + }, + validate: { + name: name => !name && "Необходимо ввести название доски", + }, + }); + + const createBoard = (values: BoardForm) => { + BoardService.createBoard({ + requestBody: { + board: { + projectId: projectId, + name: values.name, + }, + }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetchBoards(); + closeModal(); + }) + .catch(err => console.log(err)); + }; + + const updateBoard = (values: BoardForm) => { + if (!board) return; + + BoardService.updateBoard({ + requestBody: { + board: { + ...board, + name: values.name, + }, + }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetchBoards(); + closeModal(); + }) + .catch(err => console.log(err)); + }; + + const onSubmit = (values: BoardForm) => { + if (board) { + updateBoard(values); + return; + } + createBoard(values); + }; + + return { + form, + onSubmit, + }; +}; + +export default useBoardModal; diff --git a/src/pages/DealsPage/modals/DealsTableFiltersModal.tsx b/src/pages/DealsPage/modals/DealsTableFiltersModal.tsx new file mode 100644 index 0000000..c596f92 --- /dev/null +++ b/src/pages/DealsPage/modals/DealsTableFiltersModal.tsx @@ -0,0 +1,78 @@ +import { ProjectSchema } from "../../../client"; +import { Flex, Modal, NumberInput, rem } from "@mantine/core"; +import { UseFormReturnType } from "@mantine/form"; +import { DealsPageState } from "../hooks/useDealsPageState.tsx"; +import ObjectSelect from "../../../components/ObjectSelect/ObjectSelect.tsx"; +import DealStatusSelect from "../../../components/DealStatusSelect/DealStatusSelect.tsx"; +import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; +import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; +import { useDisclosure } from "@mantine/hooks"; +import InlineButton from "../../../components/InlineButton/InlineButton.tsx"; +import { IconFilter } from "@tabler/icons-react"; +import BoardSelect from "../../../components/BoardSelect/BoardSelect.tsx"; + +type Props = { + form: UseFormReturnType; + projects: ProjectSchema[]; +}; + +const DealsTableFiltersModal = ({ form, projects }: Props) => { + const [opened, { open, close }] = useDisclosure(); + + return ( + <> + + + Фильтры + + + + + form.setFieldValue("projectForTable", null)} + /> + + + form.setFieldValue("marketplace", null)} + clearable + placeholder={"Выберите маркетплейс"} + {...form.getInputProps("marketplace")} + /> + + form.setFieldValue("client", null) + } + clearable + searchable + placeholder={"Выберите клиента"} + {...form.getInputProps("client")} + /> + + + + ); +}; + +export default DealsTableFiltersModal; diff --git a/src/pages/LeadsPage/modals/ProductServiceFormModal.tsx b/src/pages/DealsPage/modals/ProductServiceFormModal.tsx similarity index 100% rename from src/pages/LeadsPage/modals/ProductServiceFormModal.tsx rename to src/pages/DealsPage/modals/ProductServiceFormModal.tsx diff --git a/src/pages/DealsPage/modals/ProjectsModal/ProjectsModal.tsx b/src/pages/DealsPage/modals/ProjectsModal/ProjectsModal.tsx new file mode 100644 index 0000000..0281954 --- /dev/null +++ b/src/pages/DealsPage/modals/ProjectsModal/ProjectsModal.tsx @@ -0,0 +1,85 @@ +import { ProjectSchema } from "../../../../client"; +import { ContextModalProps } from "@mantine/modals"; +import { ActionIcon, Flex, rem, Stack, TextInput, Tooltip } from "@mantine/core"; +import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx"; +import useProjectsTableColumns from "./hooks/projectsTableColumns.tsx"; +import { IconCheck, IconEdit, IconPlus, IconTrash } from "@tabler/icons-react"; +import { MRT_TableOptions } from "mantine-react-table"; +import InlineButton from "../../../../components/InlineButton/InlineButton.tsx"; +import useProjectModal from "./hooks/useProjectModal.tsx"; + +type Props = { + onUpdate: () => void; +}; + +const ProjectsModal = ({ innerProps }: ContextModalProps) => { + const { + projects, + name, + setName, + editingProjects, + handleEditClick, + handleDeleteClick, + handleCreateClick, + } = useProjectModal(innerProps); + + const columns = useProjectsTableColumns({ editingProjects }); + + return ( + + setName(e.target.value)} + /> + + + Добавить + + + ( + + + handleEditClick(row.original)} + variant={"default"}> + { + editingProjects.has(row.original.id) ? ( + + ) : ( + + ) + } + + + + handleDeleteClick(row.original)} + disabled={row.original.boardsCount > 0} + variant={"default"}> + + + + + ), + } as MRT_TableOptions + } + /> + + ); +}; + +export default ProjectsModal; diff --git a/src/pages/DealsPage/modals/ProjectsModal/hooks/projectsTableColumns.tsx b/src/pages/DealsPage/modals/ProjectsModal/hooks/projectsTableColumns.tsx new file mode 100644 index 0000000..4b330fe --- /dev/null +++ b/src/pages/DealsPage/modals/ProjectsModal/hooks/projectsTableColumns.tsx @@ -0,0 +1,46 @@ +import { useMemo } from "react"; +import { MRT_ColumnDef } from "mantine-react-table"; +import { BaseProjectSchema, ProjectSchema } from "../../../../../client"; +import { TextInput } from "@mantine/core"; + + +type Props = { + editingProjects: Map; +} + +const useProjectsTableColumns = ({ editingProjects }: Props) => { + return useMemo[]>( + () => [ + { + header: "Название", + accessorKey: "name", + Cell: ({ row }) => { + if (editingProjects.has(row.original.id)) { + return ( + { + const project = editingProjects.get(row.original.id); + if (!project) return; + project.name = e.target.value; + editingProjects.set(row.original.id, project); + }} + /> + ); + } + return row.original.name; + }, + size: 25, + }, + { + header: "Кол-во досок", + accessorKey: "boardsCount", + size: 10, + }, + ], + [], + ); +}; + +export default useProjectsTableColumns; diff --git a/src/pages/DealsPage/modals/ProjectsModal/hooks/useProjectModal.tsx b/src/pages/DealsPage/modals/ProjectsModal/hooks/useProjectModal.tsx new file mode 100644 index 0000000..24829e1 --- /dev/null +++ b/src/pages/DealsPage/modals/ProjectsModal/hooks/useProjectModal.tsx @@ -0,0 +1,100 @@ +import { BaseProjectSchema, ProjectSchema, ProjectService } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; +import { useMap } from "@mantine/hooks"; +import { useState } from "react"; +import useProjects from "../../../hooks/useProjects.tsx"; + +type Props = { + onUpdate: () => void; +} + +const useProjectModal = ({ onUpdate }: Props) => { + const editingProjects = useMap(); + const { projects, refetchProjects } = useProjects(); + const [name, setName] = useState(""); + + const updateProject = (project: ProjectSchema) => { + ProjectService.updateProject({ + requestBody: { + project, + }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + editingProjects.delete(project.id); + refetchProjects(); + onUpdate(); + }) + .catch(err => console.log(err)); + }; + + const handleEditClick = (project: ProjectSchema) => { + const editedProject = editingProjects.get(project.id); + + if (!editedProject) { + editingProjects.set(project.id, project); + return; + } + + if (editedProject.name.length === 0) { + notifications.error({ message: "Имя проекта не может быть пустым" }); + return; + } + + updateProject(project); + }; + + const handleDeleteClick = (project: ProjectSchema) => { + ProjectService.deleteProject({ + projectId: project.id, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetchProjects(); + onUpdate(); + }) + .catch(err => console.log(err)); + }; + + const createProject = (project: BaseProjectSchema) => { + ProjectService.createProject({ + requestBody: { project }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + setName(""); + refetchProjects(); + onUpdate(); + }) + .catch(err => console.log(err)); + }; + + const handleCreateClick = () => { + if (name.length === 0) { + notifications.error({ message: "Имя проекта не может быть пустым" }); + return; + } + createProject({ name }); + }; + + return { + projects, + name, + setName, + editingProjects, + handleEditClick, + handleDeleteClick, + handleCreateClick, + }; +}; + +export default useProjectModal; diff --git a/src/pages/LeadsPage/modals/SelectDealProductsModal.tsx b/src/pages/DealsPage/modals/SelectDealProductsModal.tsx similarity index 100% rename from src/pages/LeadsPage/modals/SelectDealProductsModal.tsx rename to src/pages/DealsPage/modals/SelectDealProductsModal.tsx diff --git a/src/pages/DealsPage/modals/StatusModal/StatusModal.tsx b/src/pages/DealsPage/modals/StatusModal/StatusModal.tsx new file mode 100644 index 0000000..bb63aa6 --- /dev/null +++ b/src/pages/DealsPage/modals/StatusModal/StatusModal.tsx @@ -0,0 +1,46 @@ +import { ContextModalProps } from "@mantine/modals"; +import { Button, Stack, TextInput } from "@mantine/core"; +import { StatusSchema } from "../../../../client"; +import useStatusModal from "./hooks/useStatusModal.tsx"; + +type Props = { + boardId?: number; + status?: StatusSchema; + refetch: () => void; +}; + +const StatusModal = ({ + context, + id, + innerProps, + }: ContextModalProps) => { + const closeModal = () => context.closeContextModal(id); + + const { + form, + onSubmit, + } = useStatusModal({ + ...innerProps, + closeModal, + }); + + return ( +
onSubmit(values))}> + + + + +
+ ); +}; + +export default StatusModal; diff --git a/src/pages/DealsPage/modals/StatusModal/hooks/useStatusModal.tsx b/src/pages/DealsPage/modals/StatusModal/hooks/useStatusModal.tsx new file mode 100644 index 0000000..fa65910 --- /dev/null +++ b/src/pages/DealsPage/modals/StatusModal/hooks/useStatusModal.tsx @@ -0,0 +1,88 @@ +import { useForm } from "@mantine/form"; +import { StatusSchema, StatusService } from "../../../../../client"; +import { notifications } from "../../../../../shared/lib/notifications.ts"; + +type StatusForm = { + name: string; +} + +type Props = { + boardId?: number; + status?: StatusSchema; + refetch: () => void; + closeModal: () => void; +}; + +const useStatusModal = ({ + boardId, + status, + refetch, + closeModal, + }: Props) => { + const form = useForm({ + initialValues: { + name: status ? status.name : "", + }, + validate: { + name: name => !name && "Необходимо ввести название статуса", + }, + }); + + const createBoard = (values: StatusForm) => { + if (!boardId) return; + StatusService.createStatus({ + requestBody: { + status: { + boardId, + name: values.name, + }, + }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetch(); + closeModal(); + }) + .catch(err => console.log(err)); + }; + + const updateBoard = (values: StatusForm) => { + if (!status) return; + + StatusService.updateStatus({ + requestBody: { + status: { + ...status, + name: values.name, + }, + }, + }) + .then(({ ok, message }) => { + if (!ok) { + notifications.error({ message }); + return; + } + refetch(); + closeModal(); + }) + .catch(err => console.log(err)); + }; + + const onSubmit = (values: StatusForm) => { + if (status) { + updateBoard(values); + return; + } + createBoard(values); + }; + + return { + form, + onSubmit, + }; +}; + +export default useStatusModal; diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/EmployeesTab.tsx b/src/pages/DealsPage/tabs/EmployeesTab/EmployeesTab.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/EmployeesTab.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/EmployeesTab.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/components/AvailableEmployeesSelect.tsx b/src/pages/DealsPage/tabs/EmployeesTab/components/AvailableEmployeesSelect.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/components/AvailableEmployeesSelect.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/components/AvailableEmployeesSelect.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/components/EmployeeInput.tsx b/src/pages/DealsPage/tabs/EmployeesTab/components/EmployeeInput.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/components/EmployeeInput.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/components/EmployeeInput.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/components/EmployeesTable.tsx b/src/pages/DealsPage/tabs/EmployeesTab/components/EmployeesTable.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/components/EmployeesTable.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/components/EmployeesTable.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/hooks/useAvailableEmployeesList.tsx b/src/pages/DealsPage/tabs/EmployeesTab/hooks/useAvailableEmployeesList.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/hooks/useAvailableEmployeesList.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/hooks/useAvailableEmployeesList.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/hooks/useEmployeesTab.tsx b/src/pages/DealsPage/tabs/EmployeesTab/hooks/useEmployeesTab.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/hooks/useEmployeesTab.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/hooks/useEmployeesTab.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/hooks/useEmployeesTableColumns.tsx b/src/pages/DealsPage/tabs/EmployeesTab/hooks/useEmployeesTableColumns.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/hooks/useEmployeesTableColumns.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/hooks/useEmployeesTableColumns.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx b/src/pages/DealsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/modals/AssignUserModal.tsx diff --git a/src/pages/LeadsPage/tabs/EmployeesTab/types/AssignUserModalForm.tsx b/src/pages/DealsPage/tabs/EmployeesTab/types/AssignUserModalForm.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/EmployeesTab/types/AssignUserModalForm.tsx rename to src/pages/DealsPage/tabs/EmployeesTab/types/AssignUserModalForm.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.module.css b/src/pages/DealsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.module.css similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.module.css rename to src/pages/DealsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.module.css diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/components/DealServicesTable/DealServicesTable.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/ProductServicesTable.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/columns.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/columns.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/columns.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductServicesTable/columns.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.module.css b/src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.module.css similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.module.css rename to src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.module.css diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx diff --git a/src/pages/LeadsPage/tabs/ProductAndServiceTab/hooks/useProductAndServiceTabState.tsx b/src/pages/DealsPage/tabs/ProductAndServiceTab/hooks/useProductAndServiceTabState.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ProductAndServiceTab/hooks/useProductAndServiceTabState.tsx rename to src/pages/DealsPage/tabs/ProductAndServiceTab/hooks/useProductAndServiceTabState.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/ShippingTab.tsx b/src/pages/DealsPage/tabs/ShippingTab/ShippingTab.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/ShippingTab.tsx rename to src/pages/DealsPage/tabs/ShippingTab/ShippingTab.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/components/BoxesTable.tsx b/src/pages/DealsPage/tabs/ShippingTab/components/BoxesTable.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/components/BoxesTable.tsx rename to src/pages/DealsPage/tabs/ShippingTab/components/BoxesTable.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/components/ShippingProductSelect.tsx b/src/pages/DealsPage/tabs/ShippingTab/components/ShippingProductSelect.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/components/ShippingProductSelect.tsx rename to src/pages/DealsPage/tabs/ShippingTab/components/ShippingProductSelect.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx b/src/pages/DealsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx rename to src/pages/DealsPage/tabs/ShippingTab/components/ShippingProductsTable.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/components/ShippingTree.tsx b/src/pages/DealsPage/tabs/ShippingTab/components/ShippingTree.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/components/ShippingTree.tsx rename to src/pages/DealsPage/tabs/ShippingTab/components/ShippingTree.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx b/src/pages/DealsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx rename to src/pages/DealsPage/tabs/ShippingTab/hooks/shippingTableColumns.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/hooks/useShipping.tsx b/src/pages/DealsPage/tabs/ShippingTab/hooks/useShipping.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/hooks/useShipping.tsx rename to src/pages/DealsPage/tabs/ShippingTab/hooks/useShipping.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/hooks/useShippingQrs.tsx b/src/pages/DealsPage/tabs/ShippingTab/hooks/useShippingQrs.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/hooks/useShippingQrs.tsx rename to src/pages/DealsPage/tabs/ShippingTab/hooks/useShippingQrs.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/hooks/useUpdateDeal.tsx b/src/pages/DealsPage/tabs/ShippingTab/hooks/useUpdateDeal.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/hooks/useUpdateDeal.tsx rename to src/pages/DealsPage/tabs/ShippingTab/hooks/useUpdateDeal.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx b/src/pages/DealsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx rename to src/pages/DealsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/types/ShippingProductData.tsx b/src/pages/DealsPage/tabs/ShippingTab/types/ShippingProductData.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/types/ShippingProductData.tsx rename to src/pages/DealsPage/tabs/ShippingTab/types/ShippingProductData.tsx diff --git a/src/pages/LeadsPage/tabs/ShippingTab/utils/getRestProducts.tsx b/src/pages/DealsPage/tabs/ShippingTab/utils/getRestProducts.tsx similarity index 100% rename from src/pages/LeadsPage/tabs/ShippingTab/utils/getRestProducts.tsx rename to src/pages/DealsPage/tabs/ShippingTab/utils/getRestProducts.tsx diff --git a/src/pages/DealsPage/ui/DealsPage.module.css b/src/pages/DealsPage/ui/DealsPage.module.css index 2664bd3..f18f2c3 100644 --- a/src/pages/DealsPage/ui/DealsPage.module.css +++ b/src/pages/DealsPage/ui/DealsPage.module.css @@ -1,25 +1,52 @@ .container { display: flex; - flex-direction: column; flex: 1; - gap: rem(10); + flex-direction: column; + height: 100%; } -.body-container { +.statuses { + margin-top: 1rem; + flex: 1; + display: flex; + gap: 0.5rem; + justify-content: left; + /*background-color: rebeccapurple;*/ + padding-right: 3%; + padding-left: 3%; +} + +.header-statuses { + display: flex; + align-items: stretch; + text-align: center; + flex-direction: column; +} + +.delete { + @mixin light { + border-color: var(--mantine-color-gray-1); + } + @mixin dark { + border-color: var(--mantine-color-dark-5); + } + border: dashed var(--item-border-size) var(--mantine-color-default-border); + border-radius: var(--item-border-radius); + padding: rem(30); + text-align: center; +} + +.delete-hidden { + border: none; } .top-panel { padding: rem(5); gap: rem(10); display: flex; + align-items: center; } -.table-container { - display: flex; - gap: rem(10); - flex-direction: column; -} - -.table-pagination { - align-self: flex-end; +.print-deals-button { + align-self: center; } diff --git a/src/pages/DealsPage/ui/DealsPage.tsx b/src/pages/DealsPage/ui/DealsPage.tsx index 71d9f32..2baee3d 100644 --- a/src/pages/DealsPage/ui/DealsPage.tsx +++ b/src/pages/DealsPage/ui/DealsPage.tsx @@ -1,61 +1,108 @@ -import { FC } from "react"; +import { FC, useState } from "react"; +import { useDealSummaries } from "../hooks/useDealSummaries.tsx"; import PageBlock from "../../../components/PageBlock/PageBlock.tsx"; -import styles from "./DealsPage.module.css"; -import DealStatusSelect from "../components/DealStatusSelect/DealStatusSelect.tsx"; -import DealsTable from "../components/DealsTable/DealsTable.tsx"; -import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; -import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; -import { DealPageContextProvider } from "../../LeadsPage/contexts/DealPageContext.tsx"; -import DealEditDrawer from "../../LeadsPage/drawers/DealEditDrawer/DealEditDrawer.tsx"; +import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx"; +import { DealPageContextProvider } from "../contexts/DealPageContext.tsx"; +import { rem } from "@mantine/core"; import useDealsPageState from "../hooks/useDealsPageState.tsx"; +import DealsTable from "../components/DealsTable/DealsTable.tsx"; +import { motion } from "framer-motion"; +import DealPrefillDrawer from "../drawers/DealPrefillDrawer/DealPrefillDrawer.tsx"; +import { PrefillDealContextProvider } from "../contexts/PrefillDealContext.tsx"; +import { useParams } from "@tanstack/react-router"; +import { PrefillDealsWithExcelContextProvider } from "../contexts/PrefillDealsWithExcelContext.tsx"; +import DisplayMode from "../enums/DisplayMode.ts"; +import LeadsPageHeader from "../components/LeadsPageHeader/LeadsPageHeader.tsx"; +import useProjects from "../hooks/useProjects.tsx"; +import Boards from "../../../components/Dnd/Boards/Boards/Boards.tsx"; +import useBoards from "../hooks/useBoards.tsx"; export const DealsPage: FC = () => { - const { data, form } = useDealsPageState(); - return ( - <> - { + const { projects, refetchProjects } = useProjects(); + const { data, form } = useDealsPageState({ projects }); + const { boards, refetchBoards } = useBoards({ projectId: form.values.project?.id }); + const { dealId } = useParams({ strict: false }); + const { summariesRaw, refetch: refetchSummaries } = useDealSummaries(); - }}> -
- -
- - form.setFieldValue("dealStatus", null) - } - clearable - placeholder={"Выберите статус "} - {...form.getInputProps("dealStatus")} - /> - - form.setFieldValue("marketplace", null) - } - clearable - placeholder={"Выберите маркетплейс"} - {...form.getInputProps("marketplace")} - /> - - form.setFieldValue("client", null) - } - clearable - searchable - placeholder={"Выберите клиента"} - {...form.getInputProps("client")} - /> -
-
- -
-
- -
-
-
-
- + const [displayMode, setDisplayMode] = useState( + DisplayMode.BOARD, + ); + + const getTableBody = () => { + return ( + + ); + }; + + const getBoardsBody = () => { + return ( + + ); + }; + + const getBody = () => { + return ( + + {displayMode === DisplayMode.TABLE + ? getTableBody() + : getBoardsBody() + } + + ); + }; + + return ( + + { + await refetchSummaries(); + }} + > + + + + + {getBody()} + + + + + - + ); }; diff --git a/src/pages/LeadsPage/index.ts b/src/pages/LeadsPage/index.ts deleted file mode 100644 index 7f1099a..0000000 --- a/src/pages/LeadsPage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LeadsPage } from "./ui/LeadsPage.tsx"; diff --git a/src/pages/LeadsPage/ui/LeadsPage.module.css b/src/pages/LeadsPage/ui/LeadsPage.module.css deleted file mode 100644 index 42cedae..0000000 --- a/src/pages/LeadsPage/ui/LeadsPage.module.css +++ /dev/null @@ -1,44 +0,0 @@ -.container { - display: flex; - flex: 1; - flex-direction: column; - height: 100%; -} - -.boards { - margin-top: 1rem; - flex: 1; - display: flex; - gap: 0.5rem; - justify-content: center; - /*background-color: rebeccapurple;*/ - padding-right: 5%; - padding-left: 5%; -} - -.delete { - @mixin light { - border-color: var(--mantine-color-gray-1); - } - @mixin dark { - border-color: var(--mantine-color-dark-5); - } - border: dashed var(--item-border-size) var(--mantine-color-default-border); - border-radius: var(--item-border-radius); - padding: rem(30); - text-align: center; -} - -.delete-hidden { - border: none; -} - -.top-panel { - padding: rem(5); - gap: rem(10); - display: flex; -} - -.print-deals-button { - align-self: center; -} diff --git a/src/pages/LeadsPage/ui/LeadsPage.tsx b/src/pages/LeadsPage/ui/LeadsPage.tsx deleted file mode 100644 index 540a907..0000000 --- a/src/pages/LeadsPage/ui/LeadsPage.tsx +++ /dev/null @@ -1,508 +0,0 @@ -import { FC, useEffect, useState } from "react"; -import styles from "./LeadsPage.module.css"; -import Board from "../../../components/Dnd/Board/Board.tsx"; -import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd"; -import { useDealSummaries } from "../hooks/useDealSummaries.tsx"; -import { DealStatus, getDealStatusByName } from "../../../shared/enums/DealStatus.ts"; -import PageBlock from "../../../components/PageBlock/PageBlock.tsx"; -import DealEditDrawer from "../drawers/DealEditDrawer/DealEditDrawer.tsx"; -import { DealPageContextProvider } from "../contexts/DealPageContext.tsx"; -import { modals } from "@mantine/modals"; -import { DealService, DealSummaryReorderRequest } from "../../../client"; -import { ActionIcon, Flex, NumberInput, rem, Text } from "@mantine/core"; -import classNames from "classnames"; -import { notifications } from "../../../shared/lib/notifications.ts"; -import { IconMenu2, IconMenuDeep } from "@tabler/icons-react"; -import useDealsPageState from "../../DealsPage/hooks/useDealsPageState.tsx"; -import DealStatusSelect from "../../DealsPage/components/DealStatusSelect/DealStatusSelect.tsx"; -import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; -import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; -import DealsTable from "../../DealsPage/components/DealsTable/DealsTable.tsx"; -import { motion } from "framer-motion"; -import { dateWithoutTimezone } from "../../../shared/lib/date.ts"; -import DealPrefillDrawer from "../drawers/DealPrefillDrawer/DealPrefillDrawer.tsx"; -import { PrefillDealContextProvider } from "../contexts/PrefillDealContext.tsx"; -import { useParams } from "@tanstack/react-router"; -import { PrefillDealsWithExcelContextProvider } from "../contexts/PrefillDealsWithExcelContext.tsx"; -import PrefillDealsWithExcelDrawer from "../drawers/PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.tsx"; - -enum DisplayMode { - BOARD, - TABLE, -} - -export const LeadsPage: FC = () => { - const { data, form } = useDealsPageState(); - const { dealId } = useParams({ strict: false }); - const { summariesRaw, refetch } = useDealSummaries(); - const [summaries, setSummaries] = useState(summariesRaw); - const [displayMode, setDisplayMode] = useState( - DisplayMode.BOARD, - ); - const [isDragEnded, setIsDragEnded] = useState(true); - - // const [selectedDeals, setSelectedDeals] = useState([]); - - useEffect(() => { - setSummaries(summariesRaw); - }, [summariesRaw]); - - const recalculate = async (dealId: number) => { - return DealService.recalculateDealPrice({ - requestBody: { - dealId: dealId, - }, - }).then(({ ok, message }) => { - notifications.guess(ok, { message }); - }); - }; - - const onDelete = (dealId: number) => { - const summary = summaries.find(summary => summary.id == dealId); - if (!summary) return; - modals.openConfirmModal({ - title: "Удаление сделки", - children: ( - - Вы действительно хотите удалить сделку {summary.name}? - - ), - onConfirm: () => { - DealService.deleteDeal({ - requestBody: { dealId: dealId }, - }).then(async ({ ok, message }) => { - notifications.guess(ok, { message }); - if (!ok) return; - await refetch(); - }); - }, - labels: { - confirm: "Удалить", - cancel: "Отмена", - }, - }); - }; - const onSuccess = (dealId: number) => { - const summary = summaries.find(summary => summary.id == dealId); - if (!summary) return; - modals.openConfirmModal({ - title: "Завершение сделки", - children: ( - - Вы действительно хотите завершить сделку {summary.name}? - - ), - onConfirm: () => { - DealService.completeDeal({ - requestBody: { dealId: dealId }, - }).then(async ({ ok, message }) => { - notifications.guess(ok, { message }); - if (!ok) return; - await refetch(); - }); - }, - labels: { - confirm: "Завершить", - cancel: "Отмена", - }, - }); - }; - const onCombine = async (result: DropResult) => { - if (!result.combine) return; - const destination = result.combine.draggableId; - const source = result.draggableId; - if (!destination || !source) return; - const sourceId = parseInt(source); - if (destination.includes("group")) { - const groupId = parseInt(destination.split("-")[1]); - DealService.addDealToGroup({ - requestBody: { - dealId: sourceId, - groupId: groupId, - }, - }).then(async response => { - if (!response.ok) { - notifications.error({ message: response.message }); - return; - } - await refetch(); - await recalculate(sourceId); - await refetch(); - }); - } else { - const destinationId = parseInt(destination); - // creating new group - DealService.createDealGroup({ - requestBody: { - draggingDealId: sourceId, - hoveredDealId: destinationId, - }, - }).then(async response => { - if (!response.ok) { - notifications.error({ message: response.message }); - return; - } - await refetch(); - await recalculate(sourceId); - await refetch(); - }); - return; - } - }; - const moveGroup = async (result: DropResult) => { - const groupId = parseInt(result.draggableId.split("-")[1]); - const destination = result.destination?.droppableId; - if (!destination) return; - const status = getDealStatusByName(destination); - DealService.changeDealGroupStatus({ - requestBody: { - groupId: groupId, - newStatus: status, - }, - }).then(async response => { - if (!response.ok) { - notifications.error({ message: response.message }); - return; - } - await refetch(); - }); - }; - const onDragEnd = async (result: DropResult) => { - - if (result.combine) { - return onCombine(result); - } - setIsDragEnded(true); - // If there is no changes - if (!result.destination || result.destination == result.source) return; - - // Checking for valid dealId - if (result.draggableId.includes("group")) { - return moveGroup(result); - } - const dealId = parseInt(result.draggableId); - if (isNaN(dealId)) return; - - // Checking for valid deal - const summary = summaries.find(summary => summary.id == dealId); - if (!summary) return; - - // Checking if it is custom actions - const droppableId = result.destination.droppableId; - if (droppableId === "DELETE") { - onDelete(dealId); - return; - } - if (droppableId === "SUCCESS") { - onSuccess(dealId); - return; - } - const status = getDealStatusByName(droppableId); - const request: Partial = { - dealId: dealId, - index: result.destination.index, - status: status, - }; - if (status == summary.status) { - DealService.reorderDealSummaries({ - requestBody: request as DealSummaryReorderRequest, - }).then(async response => { - setSummaries(response.summaries); - await refetch(); - }); - return; - } - - DealService.reorderDealSummaries({ - requestBody: { - dealId: dealId, - status: status, - index: result.destination.index, - comment: "", - deadline: dateWithoutTimezone(new Date()), - }, - }).then(async response => { - setSummaries(response.summaries); - await refetch(); - }); - }; - const getTableBody = () => { - return ( - - - - ); - }; - const getBoardBody = () => { - return ( - - { - setIsDragEnded(false); - }} - onDragEnd={onDragEnd}> - -
- - summary.status == - DealStatus.AWAITING_ACCEPTANCE, - )} - title={"Ожидает приемки"} - droppableId={"AWAITING_ACCEPTANCE"} - color={"#4A90E2"} - /> - - summary.status == DealStatus.READY_FOR_WORK, - )} - title={"Готов к работе"} - droppableId={"READY_FOR_WORK"} - color={"#D3D3D3"} - /> - - summary.status == DealStatus.PACKAGING, - )} - title={"Упаковка"} - droppableId={"PACKAGING"} - color={"#F5A623"} - /> - - summary.status == - DealStatus.AWAITING_SHIPMENT, - )} - title={"Ожидает отгрузки"} - droppableId={"AWAITING_SHIPMENT"} - color={"#7ED321"} - /> - - summary.status == DealStatus.IN_DELIVERY, - )} - title={"В доставке"} - droppableId={"IN_DELIVERY"} - color={"#6A0DAD"} - /> - - summary.status == - DealStatus.AWAITING_PAYMENT, - )} - title={"Ожидает оплаты"} - droppableId={"AWAITING_PAYMENT"} - color={"#D0021B"} - /> - - summary.status == DealStatus.COMPLETED, - )} - title={"Завершена"} - droppableId={"COMPLETED"} - color={"#417505"} - /> -
- -
- - {(provided, snapshot) => ( - <> -
- {!isDragEnded && - !snapshot.isDraggingOver && ( - Удалить - )} -
- {provided.placeholder} - - )} -
-
-
- - {(provided, snapshot) => ( - <> -
- {!isDragEnded && - !snapshot.isDraggingOver && ( - - Успешно завершена - - )} -
- {provided.placeholder} - - )} -
-
-
-
-
-
- ); - }; - const getBody = () => { - return displayMode === DisplayMode.TABLE - ? getTableBody() - : getBoardBody(); - }; - return ( - - { - await refetch(); - }}> - - - - - - Вид - - - setDisplayMode(DisplayMode.BOARD) - } - variant={ - displayMode === DisplayMode.BOARD - ? "filled" - : "default" - }> - - - - setDisplayMode(DisplayMode.TABLE) - } - variant={ - displayMode === DisplayMode.TABLE - ? "filled" - : "default" - }> - - - - - -
- - - form.setFieldValue("dealStatus", null) - } - clearable - placeholder={"Выберите статус "} - {...form.getInputProps("dealStatus")} - /> - - form.setFieldValue("marketplace", null) - } - clearable - placeholder={"Выберите маркетплейс"} - {...form.getInputProps("marketplace")} - /> - - form.setFieldValue("client", null) - } - clearable - searchable - placeholder={"Выберите клиента"} - {...form.getInputProps("client")} - /> -
-
-
-
- - {getBody()} - - - - -
-
-
-
- ); -}; diff --git a/src/pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx b/src/pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx index 9553c3f..ab39755 100644 --- a/src/pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx +++ b/src/pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx @@ -4,8 +4,8 @@ import { ContextModalProps } from "@mantine/modals"; import { useForm } from "@mantine/form"; import { Input, TextInput } from "@mantine/core"; import DealsTable from "../../DealsPage/components/DealsTable/DealsTable.tsx"; -import { DealPageContextProvider } from "../../LeadsPage/contexts/DealPageContext.tsx"; -import DealEditDrawer from "../../LeadsPage/drawers/DealEditDrawer/DealEditDrawer.tsx"; +import { DealPageContextProvider } from "../../DealsPage/contexts/DealPageContext.tsx"; +import DealEditDrawer from "../../DealsPage/drawers/DealEditDrawer/DealEditDrawer.tsx"; type RestProps = { summaries: DealSummary[]; diff --git a/src/pages/ShippingWarehousesPage/ui/ShippingWarehousesPage.tsx b/src/pages/ShippingWarehousesPage/ui/ShippingWarehousesPage.tsx index 3231fc3..df0bb33 100644 --- a/src/pages/ShippingWarehousesPage/ui/ShippingWarehousesPage.tsx +++ b/src/pages/ShippingWarehousesPage/ui/ShippingWarehousesPage.tsx @@ -10,7 +10,7 @@ import { ShippingWarehouseService, } from "../../../client"; import { notifications } from "../../../shared/lib/notifications.ts"; -import { useDealSummariesFull } from "../../LeadsPage/hooks/useDealSummaries.tsx"; +import { useDealSummariesFull } from "../../DealsPage/hooks/useDealSummaries.tsx"; export const ShippingWarehousesPage = () => { const { shippingWarehouses, refetch } = useShippingWarehousesList(); diff --git a/src/pages/StatisticsPage/tabs/ProfitTab/components/Filters/Filters.tsx b/src/pages/StatisticsPage/tabs/ProfitTab/components/Filters/Filters.tsx index 494ab23..c4d60db 100644 --- a/src/pages/StatisticsPage/tabs/ProfitTab/components/Filters/Filters.tsx +++ b/src/pages/StatisticsPage/tabs/ProfitTab/components/Filters/Filters.tsx @@ -1,15 +1,24 @@ import { DatePickerInput, DatePickerInputProps } from "@mantine/dates"; -import { Divider, Stack, Text } from "@mantine/core"; +import { Checkbox, CheckboxProps, Divider, Stack, Text } from "@mantine/core"; import ClientSelectNew from "../../../../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; -import { BaseMarketplaceSchema, ClientSchema, TransactionTagSchema, UserSchema } from "../../../../../../client"; +import { + BaseMarketplaceSchema, + BoardSchema, + ClientSchema, + ProjectSchema, + StatusSchema, + TransactionTagSchema, + UserSchema, +} from "../../../../../../client"; import { ObjectSelectProps } from "../../../../../../components/ObjectSelect/ObjectSelect.tsx"; import BaseMarketplaceSelect from "../../../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; -import DealStatusSelect from "../../../../../DealsPage/components/DealStatusSelect/DealStatusSelect.tsx"; -import { DealStatusType } from "../../../../../../shared/enums/DealStatus.ts"; +import DealStatusSelect from "../../../../../../components/DealStatusSelect/DealStatusSelect.tsx"; import { ProfitTableSegmentedControl } from "../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx"; import ManagerSelect from "../../../../../../components/ManagerSelect/ManagerSelect.tsx"; import TransactionTagSelect from "../../../../components/ExpenseTagSelect/TransactionTagSelect.tsx"; +import BoardSelect from "../../../../../../components/BoardSelect/BoardSelect.tsx"; +import ProjectSelect from "../../../../../../components/ProjectSelect/ProjectSelect.tsx"; type SelectProps = Omit< @@ -26,12 +35,17 @@ type FiltersProps = { baseMarketplaceSelectProps?: SelectProps; onBaseMarketplaceClear?: () => void; - dealStatusSelectProps?: Omit, "data">; - onDealStatusClear?: () => void; + projectSelectProps?: Omit, "data">; + + boardSelectProps?: Omit, "data">; + + dealStatusSelectProps?: Omit, "data">; managerSelectProps?: SelectProps; onManagerClear?: () => void; + isCompletedOnlyCheckboxProps?: CheckboxProps; + expenseTagSelectProps?: SelectProps; onExpenseTagClear?: () => void; @@ -61,8 +75,8 @@ export const Filters = (props: FiltersProps) => { isIncome={isIncome} /> - ) - } + ); + }; return ( @@ -79,12 +93,24 @@ export const Filters = (props: FiltersProps) => { valueFormat={"DD.MM.YYYY"} /> } + {props.projectSelectProps && + + } + {props.boardSelectProps && + + } {props.dealStatusSelectProps && } {props.clientSelectProps && @@ -111,6 +137,10 @@ export const Filters = (props: FiltersProps) => { placeholder={"Выберите менеджера"} /> } + {getTransactionTagsSelect(false)} {getTransactionTagsSelect(true)} {props.groupTableByProps && @@ -118,6 +148,8 @@ export const Filters = (props: FiltersProps) => { Группировка таблицы: { +export const useProfitTableColumns = ({ groupTableBy, statuses }: Props) => { const groupedValueHeader = { [GroupStatisticsTable.BY_DATES]: "Дата", [GroupStatisticsTable.BY_CLIENTS]: "Клиент", + [GroupStatisticsTable.BY_PROJECTS]: "Проект", + [GroupStatisticsTable.BY_BOARDS]: "Доска", [GroupStatisticsTable.BY_STATUSES]: "Статус", [GroupStatisticsTable.BY_MARKETPLACES]: "Маркетплейс", [GroupStatisticsTable.BY_WAREHOUSES]: "Склад отгрузки", @@ -49,8 +51,8 @@ export const useProfitTableColumns = ({ groupTableBy }: Props) => { enableSorting: groupTableBy === GroupStatisticsTable.BY_DATES, Cell: ({ row }) => { if (groupTableBy === GroupStatisticsTable.BY_STATUSES) { - const statusIndex = row.original.groupedValue as DealStatus; - return DealStatusDictionary[statusIndex]; + const status = statuses?.find(s => s.id === row.original.groupedValue) + return status?.name; } if (groupTableBy == GroupStatisticsTable.BY_DATES) { return formatDate(row.original.groupedValue as string); diff --git a/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTable/hooks/useProfitTable.tsx b/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTable/hooks/useProfitTable.tsx index 70696b4..e90b3ab 100644 --- a/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTable/hooks/useProfitTable.tsx +++ b/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTable/hooks/useProfitTable.tsx @@ -13,6 +13,7 @@ export const useProfitTable = () => { const columns = useProfitTableColumns({ groupTableBy: form.values.groupTableBy, + statuses: form.values.board?.dealStatuses, }); const defaultSorting = [{ id: "groupedValue", desc: true }]; diff --git a/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx b/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx index bac01f4..1f4a49a 100644 --- a/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx +++ b/src/pages/StatisticsPage/tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx @@ -1,44 +1,82 @@ -import { SegmentedControl, SegmentedControlProps } from "@mantine/core"; -import { FC } from "react"; +import { SegmentedControl, SegmentedControlItem, SegmentedControlProps } from "@mantine/core"; +import { FC, useEffect } from "react"; +import { BoardSchema, ProjectSchema } from "../../../../../../client"; export enum GroupStatisticsTable { BY_DATES, BY_CLIENTS, + BY_PROJECTS, + BY_BOARDS, BY_STATUSES, BY_WAREHOUSES, BY_MARKETPLACES, BY_MANAGERS, } -type Props = Omit; -const data = [ - { - label: "По датам", - value: GroupStatisticsTable.BY_DATES.toString(), - }, - { - label: "По клиентам", - value: GroupStatisticsTable.BY_CLIENTS.toString(), - }, - { - label: "По статусам", - value: GroupStatisticsTable.BY_STATUSES.toString(), - }, - { - label: "По складам отгрузки", - value: GroupStatisticsTable.BY_WAREHOUSES.toString(), - }, - { - label: "По маркетплейсам", - value: GroupStatisticsTable.BY_MARKETPLACES.toString(), - }, - { - label: "По менеджерам", - value: GroupStatisticsTable.BY_MANAGERS.toString(), - }, -]; +type ControlProps = Omit; + +type OtherProps = { + selectedBoard: BoardSchema | null; + selectedProject: ProjectSchema | null; +} + +type Props = ControlProps & OtherProps; export const ProfitTableSegmentedControl: FC = props => { + const data: (string | SegmentedControlItem)[] = [ + { + label: "По датам", + value: GroupStatisticsTable.BY_DATES.toString(), + }, + { + label: "По клиентам", + value: GroupStatisticsTable.BY_CLIENTS.toString(), + }, + { + label: "По проектам", + value: GroupStatisticsTable.BY_PROJECTS.toString(), + }, + { + label: "По доскам", + value: GroupStatisticsTable.BY_BOARDS.toString(), + disabled: !props.selectedProject, + }, + { + label: "По статусам", + value: GroupStatisticsTable.BY_STATUSES.toString(), + disabled: !props.selectedBoard, + }, + { + label: "По складам отгрузки", + value: GroupStatisticsTable.BY_WAREHOUSES.toString(), + }, + { + label: "По маркетплейсам", + value: GroupStatisticsTable.BY_MARKETPLACES.toString(), + }, + { + label: "По менеджерам", + value: GroupStatisticsTable.BY_MANAGERS.toString(), + }, + ]; + + const setGrouping = (status: GroupStatisticsTable) => { + if (!props.onChange) return; + props.onChange(status.toString()); + }; + + useEffect(() => { + if (props.value === GroupStatisticsTable.BY_STATUSES.toString()) { + if (!props.selectedProject) { + setGrouping(GroupStatisticsTable.BY_PROJECTS); + } else if (!props.selectedBoard) { + setGrouping(GroupStatisticsTable.BY_BOARDS); + } + } else if (props.value === GroupStatisticsTable.BY_BOARDS.toString() && !props.selectedProject) { + setGrouping(GroupStatisticsTable.BY_PROJECTS); + } + }, [props.selectedBoard, props.selectedProject]); + return ( { groupTableBy: GroupStatisticsTable.BY_DATES, client: null, marketplace: null, - dealStatus: defaultDealStatus, + project: null, + board: null, + dealStatus: null, manager: null, expenseTag: null, incomeTag: null, + isCompletedOnly: true, }, }); const [isChartLoading, setIsChartLoading] = useState(false); @@ -48,10 +50,13 @@ const useProfitTabContextState = () => { ], clientId: form.values.client?.id ?? -1, baseMarketplaceKey: form.values.marketplace?.key ?? "all", + projectId: form.values.project?.id ?? -1, + boardId: form.values.board?.id ?? -1, dealStatusId: form.values.dealStatus?.id ?? -1, managerId: form.values.manager?.id ?? -1, expenseTagId: form.values.expenseTag?.id ?? -1, incomeTagId: form.values.incomeTag?.id ?? -1, + isCompletedOnly: form.values.isCompletedOnly, }; }; diff --git a/src/pages/StatisticsPage/tabs/ProfitTab/modals/ProfitFiltersModal.tsx b/src/pages/StatisticsPage/tabs/ProfitTab/modals/ProfitFiltersModal.tsx index 7d011bb..e9fe33f 100644 --- a/src/pages/StatisticsPage/tabs/ProfitTab/modals/ProfitFiltersModal.tsx +++ b/src/pages/StatisticsPage/tabs/ProfitTab/modals/ProfitFiltersModal.tsx @@ -40,10 +40,12 @@ export const ProfitFiltersModal = ({ form }: Props) => { onClientClear={() => form.setFieldValue("client", null)} baseMarketplaceSelectProps={form.getInputProps("marketplace")} onBaseMarketplaceClear={() => form.setFieldValue("marketplace", null)} + projectSelectProps={form.getInputProps("project")} + boardSelectProps={form.getInputProps("board")} dealStatusSelectProps={form.getInputProps("dealStatus")} - onDealStatusClear={() => form.setFieldValue("dealStatus", null)} managerSelectProps={form.getInputProps("manager")} onManagerClear={() => form.setFieldValue("manager", null)} + isCompletedOnlyCheckboxProps={form.getInputProps("isCompletedOnly", { type: "checkbox" })} expenseTagSelectProps={form.getInputProps("expenseTag")} onExpenseTagClear={() => form.setFieldValue("expenseTag", null)} incomeTagSelectProps={form.getInputProps("incomeTag")} diff --git a/src/pages/StatisticsPage/types/FormFilters.ts b/src/pages/StatisticsPage/types/FormFilters.ts index 82c1d38..38213ef 100644 --- a/src/pages/StatisticsPage/types/FormFilters.ts +++ b/src/pages/StatisticsPage/types/FormFilters.ts @@ -1,16 +1,25 @@ import { GroupStatisticsTable, } from "../tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx"; -import { BaseMarketplaceSchema, ClientSchema, TransactionTagSchema, UserSchema } from "../../../client"; -import { DealStatusType } from "../../../shared/enums/DealStatus.ts"; +import { + BaseMarketplaceSchema, BoardSchema, + ClientSchema, + ProjectSchema, + StatusSchema, + TransactionTagSchema, + UserSchema, +} from "../../../client"; export interface FormFilters { dateRange: [Date | null, Date | null]; groupTableBy: GroupStatisticsTable; client: ClientSchema | null; marketplace: BaseMarketplaceSchema | null; - dealStatus: DealStatusType | null; + project: ProjectSchema | null; + board: BoardSchema | null; + dealStatus: StatusSchema | null; manager: UserSchema | null; + isCompletedOnly: boolean; expenseTag: TransactionTagSchema | null; incomeTag: TransactionTagSchema | null; } \ No newline at end of file diff --git a/src/pages/StatisticsPage/utils/defaultFilterValues.ts b/src/pages/StatisticsPage/utils/defaultFilterValues.ts deleted file mode 100644 index 5d22b4d..0000000 --- a/src/pages/StatisticsPage/utils/defaultFilterValues.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { DealStatus, DealStatusDictionary } from "../../../shared/enums/DealStatus.ts"; - -export const defaultDealStatus = { - id: DealStatus.COMPLETED, - name: DealStatusDictionary[DealStatus.COMPLETED], -}; \ No newline at end of file diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 37fbd67..994a434 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -1,12 +1,12 @@ +/* prettier-ignore-start */ + /* eslint-disable */ // @ts-nocheck // noinspection JSUnusedGlobalSymbols -// This file was automatically generated by TanStack Router. -// You should NOT make any changes in this file as it will be overwritten. -// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. +// This file is auto-generated by TanStack Router import { createFileRoute } from '@tanstack/react-router' @@ -36,19 +36,16 @@ const IndexLazyImport = createFileRoute('/')() // Create/Update Routes const TestLazyRoute = TestLazyImport.update({ - id: '/test', path: '/test', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/test.lazy').then((d) => d.Route)) const StatisticsLazyRoute = StatisticsLazyImport.update({ - id: '/statistics', path: '/statistics', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/statistics.lazy').then((d) => d.Route)) const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({ - id: '/shipping_warehouses', path: '/shipping_warehouses', getParentRoute: () => rootRoute, } as any).lazy(() => @@ -56,79 +53,66 @@ const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({ ) const ServicesLazyRoute = ServicesLazyImport.update({ - id: '/services', path: '/services', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/services.lazy').then((d) => d.Route)) const ResiduesLazyRoute = ResiduesLazyImport.update({ - id: '/residues', path: '/residues', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/residues.lazy').then((d) => d.Route)) const ReceiptLazyRoute = ReceiptLazyImport.update({ - id: '/receipt', path: '/receipt', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/receipt.lazy').then((d) => d.Route)) const ProductsLazyRoute = ProductsLazyImport.update({ - id: '/products', path: '/products', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route)) const MarketplacesLazyRoute = MarketplacesLazyImport.update({ - id: '/marketplaces', path: '/marketplaces', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route)) const LoginLazyRoute = LoginLazyImport.update({ - id: '/login', path: '/login', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route)) const LeadsLazyRoute = LeadsLazyImport.update({ - id: '/leads', path: '/leads', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/leads.lazy').then((d) => d.Route)) const ClientsLazyRoute = ClientsLazyImport.update({ - id: '/clients', path: '/clients', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/clients.lazy').then((d) => d.Route)) const BarcodeLazyRoute = BarcodeLazyImport.update({ - id: '/barcode', path: '/barcode', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/barcode.lazy').then((d) => d.Route)) const AdminLazyRoute = AdminLazyImport.update({ - id: '/admin', path: '/admin', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route)) const IndexLazyRoute = IndexLazyImport.update({ - id: '/', path: '/', getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) const LeadsDealIdRoute = LeadsDealIdImport.update({ - id: '/$dealId', path: '/$dealId', getParentRoute: () => LeadsLazyRoute, } as any) const DealsDealIdRoute = DealsDealIdImport.update({ - id: '/deals/$dealId', path: '/deals/$dealId', getParentRoute: () => rootRoute, } as any) @@ -422,6 +406,8 @@ export const routeTree = rootRoute ._addFileChildren(rootRouteChildren) ._addFileTypes() +/* prettier-ignore-end */ + /* ROUTE_MANIFEST_START { "routes": { diff --git a/src/routes/leads.$dealId.tsx b/src/routes/leads.$dealId.tsx index ba7215d..988eaf3 100644 --- a/src/routes/leads.$dealId.tsx +++ b/src/routes/leads.$dealId.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from "@tanstack/react-router"; -import { LeadsPage } from "../pages/LeadsPage"; +import { DealsPage } from "../pages/DealsPage"; export const Route = createFileRoute("/leads/$dealId")({ - component: LeadsPage, + component: DealsPage, }); \ No newline at end of file diff --git a/src/routes/leads.lazy.tsx b/src/routes/leads.lazy.tsx index a5dafcd..6f95b6c 100644 --- a/src/routes/leads.lazy.tsx +++ b/src/routes/leads.lazy.tsx @@ -1,6 +1,6 @@ import { createLazyFileRoute } from "@tanstack/react-router"; -import { LeadsPage } from "../pages/LeadsPage"; +import { DealsPage } from "../pages/DealsPage"; export const Route = createLazyFileRoute("/leads")({ - component: LeadsPage, + component: DealsPage, }); diff --git a/src/types/utils.ts b/src/types/utils.ts index d30f9c8..3bd6505 100644 --- a/src/types/utils.ts +++ b/src/types/utils.ts @@ -1,6 +1,6 @@ import { ProductSchema } from "../client"; import { isNil } from "lodash"; -import { ProductFieldNames } from "../pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx"; +import { ProductFieldNames } from "../pages/DealsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx"; import UseObjectState from "./UseObjectState.ts"; import { CRUDTableProps } from "./CRUDTable.tsx"; import { MRT_RowData } from "mantine-react-table";