feat: deal group and stuff
This commit is contained in:
		@@ -40,6 +40,7 @@
 | 
				
			|||||||
        "globals": "^15.8.0",
 | 
					        "globals": "^15.8.0",
 | 
				
			||||||
        "jwt-decode": "^4.0.0",
 | 
					        "jwt-decode": "^4.0.0",
 | 
				
			||||||
        "lodash": "^4.17.21",
 | 
					        "lodash": "^4.17.21",
 | 
				
			||||||
 | 
					        "mantine-contextmenu": "^7.12.2",
 | 
				
			||||||
        "mantine-form-zod-resolver": "^1.1.0",
 | 
					        "mantine-form-zod-resolver": "^1.1.0",
 | 
				
			||||||
        "mantine-react-table": "^2.0.0-beta.5",
 | 
					        "mantine-react-table": "^2.0.0-beta.5",
 | 
				
			||||||
        "phone": "^3.1.49",
 | 
					        "phone": "^3.1.49",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,11 +71,15 @@ export type { DealAddServiceRequest } from './models/DealAddServiceRequest';
 | 
				
			|||||||
export type { DealAddServiceResponse } from './models/DealAddServiceResponse';
 | 
					export type { DealAddServiceResponse } from './models/DealAddServiceResponse';
 | 
				
			||||||
export type { DealAddServicesRequest } from './models/DealAddServicesRequest';
 | 
					export type { DealAddServicesRequest } from './models/DealAddServicesRequest';
 | 
				
			||||||
export type { DealAddServicesResponse } from './models/DealAddServicesResponse';
 | 
					export type { DealAddServicesResponse } from './models/DealAddServicesResponse';
 | 
				
			||||||
 | 
					export type { DealAddToGroupRequest } from './models/DealAddToGroupRequest';
 | 
				
			||||||
 | 
					export type { DealAddToGroupResponse } from './models/DealAddToGroupResponse';
 | 
				
			||||||
export type { DealBillRequestSchema } from './models/DealBillRequestSchema';
 | 
					export type { DealBillRequestSchema } from './models/DealBillRequestSchema';
 | 
				
			||||||
export type { DealChangeStatusRequest } from './models/DealChangeStatusRequest';
 | 
					export type { DealChangeStatusRequest } from './models/DealChangeStatusRequest';
 | 
				
			||||||
export type { DealChangeStatusResponse } from './models/DealChangeStatusResponse';
 | 
					export type { DealChangeStatusResponse } from './models/DealChangeStatusResponse';
 | 
				
			||||||
export type { DealCompleteRequest } from './models/DealCompleteRequest';
 | 
					export type { DealCompleteRequest } from './models/DealCompleteRequest';
 | 
				
			||||||
export type { DealCompleteResponse } from './models/DealCompleteResponse';
 | 
					export type { DealCompleteResponse } from './models/DealCompleteResponse';
 | 
				
			||||||
 | 
					export type { DealCreateGroupRequest } from './models/DealCreateGroupRequest';
 | 
				
			||||||
 | 
					export type { DealCreateGroupResponse } from './models/DealCreateGroupResponse';
 | 
				
			||||||
export type { DealCreateGuestUrlRequest } from './models/DealCreateGuestUrlRequest';
 | 
					export type { DealCreateGuestUrlRequest } from './models/DealCreateGuestUrlRequest';
 | 
				
			||||||
export type { DealCreateGuestUrlResponse } from './models/DealCreateGuestUrlResponse';
 | 
					export type { DealCreateGuestUrlResponse } from './models/DealCreateGuestUrlResponse';
 | 
				
			||||||
export type { DealCreateRequest } from './models/DealCreateRequest';
 | 
					export type { DealCreateRequest } from './models/DealCreateRequest';
 | 
				
			||||||
@@ -91,6 +95,11 @@ export type { DealDeleteServicesRequest } from './models/DealDeleteServicesReque
 | 
				
			|||||||
export type { DealDeleteServicesResponse } from './models/DealDeleteServicesResponse';
 | 
					export type { DealDeleteServicesResponse } from './models/DealDeleteServicesResponse';
 | 
				
			||||||
export type { DealGeneralInfoSchema } from './models/DealGeneralInfoSchema';
 | 
					export type { DealGeneralInfoSchema } from './models/DealGeneralInfoSchema';
 | 
				
			||||||
export type { DealGetAllResponse } from './models/DealGetAllResponse';
 | 
					export type { DealGetAllResponse } from './models/DealGetAllResponse';
 | 
				
			||||||
 | 
					export type { DealGroupChangeStatusRequest } from './models/DealGroupChangeStatusRequest';
 | 
				
			||||||
 | 
					export type { DealGroupChangeStatusResponse } from './models/DealGroupChangeStatusResponse';
 | 
				
			||||||
 | 
					export type { DealGroupSchema } from './models/DealGroupSchema';
 | 
				
			||||||
 | 
					export type { DealGroupUpdateRequest } from './models/DealGroupUpdateRequest';
 | 
				
			||||||
 | 
					export type { DealGroupUpdateResponse } from './models/DealGroupUpdateResponse';
 | 
				
			||||||
export type { DealPrefillRequest } from './models/DealPrefillRequest';
 | 
					export type { DealPrefillRequest } from './models/DealPrefillRequest';
 | 
				
			||||||
export type { DealPrefillResponse } from './models/DealPrefillResponse';
 | 
					export type { DealPrefillResponse } from './models/DealPrefillResponse';
 | 
				
			||||||
export type { DealProductAddKitRequest } from './models/DealProductAddKitRequest';
 | 
					export type { DealProductAddKitRequest } from './models/DealProductAddKitRequest';
 | 
				
			||||||
@@ -101,6 +110,8 @@ export type { DealQuickCreateRequest } from './models/DealQuickCreateRequest';
 | 
				
			|||||||
export type { DealQuickCreateResponse } from './models/DealQuickCreateResponse';
 | 
					export type { DealQuickCreateResponse } from './models/DealQuickCreateResponse';
 | 
				
			||||||
export type { DealRecalculatePriceRequest } from './models/DealRecalculatePriceRequest';
 | 
					export type { DealRecalculatePriceRequest } from './models/DealRecalculatePriceRequest';
 | 
				
			||||||
export type { DealRecalculatePriceResponse } from './models/DealRecalculatePriceResponse';
 | 
					export type { DealRecalculatePriceResponse } from './models/DealRecalculatePriceResponse';
 | 
				
			||||||
 | 
					export type { DealRemoveFromGroupRequest } from './models/DealRemoveFromGroupRequest';
 | 
				
			||||||
 | 
					export type { DealRemoveFromGroupResponse } from './models/DealRemoveFromGroupResponse';
 | 
				
			||||||
export type { DealSchema } from './models/DealSchema';
 | 
					export type { DealSchema } from './models/DealSchema';
 | 
				
			||||||
export type { DealServiceSchema } from './models/DealServiceSchema';
 | 
					export type { DealServiceSchema } from './models/DealServiceSchema';
 | 
				
			||||||
export type { DealServicesCopyRequest } from './models/DealServicesCopyRequest';
 | 
					export type { DealServicesCopyRequest } from './models/DealServicesCopyRequest';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/DealAddToGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealAddToGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealAddToGroupRequest = {
 | 
				
			||||||
 | 
					    dealId: number;
 | 
				
			||||||
 | 
					    groupId: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealAddToGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealAddToGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealAddToGroupResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealCreateGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealCreateGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealCreateGroupRequest = {
 | 
				
			||||||
 | 
					    draggingDealId: number;
 | 
				
			||||||
 | 
					    hoveredDealId: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealCreateGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealCreateGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealCreateGroupResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealGroupChangeStatusRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealGroupChangeStatusRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealGroupChangeStatusRequest = {
 | 
				
			||||||
 | 
					    groupId: number;
 | 
				
			||||||
 | 
					    newStatus: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealGroupChangeStatusResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealGroupChangeStatusResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealGroupChangeStatusResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/client/models/DealGroupSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/DealGroupSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealGroupSchema = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    name?: (string | null);
 | 
				
			||||||
 | 
					    lexorank: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealGroupUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealGroupUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { DealGroupSchema } from './DealGroupSchema';
 | 
				
			||||||
 | 
					export type DealGroupUpdateRequest = {
 | 
				
			||||||
 | 
					    data: DealGroupSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealGroupUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealGroupUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealGroupUpdateResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								src/client/models/DealRemoveFromGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/DealRemoveFromGroupRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealRemoveFromGroupRequest = {
 | 
				
			||||||
 | 
					    dealId: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DealRemoveFromGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealRemoveFromGroupResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DealRemoveFromGroupResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -4,13 +4,14 @@
 | 
				
			|||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema';
 | 
					import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema';
 | 
				
			||||||
import type { DealBillRequestSchema } from './DealBillRequestSchema';
 | 
					import type { DealBillRequestSchema } from './DealBillRequestSchema';
 | 
				
			||||||
 | 
					import type { DealGroupSchema } from './DealGroupSchema';
 | 
				
			||||||
export type DealSummary = {
 | 
					export type DealSummary = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    clientName: string;
 | 
					    clientName: string;
 | 
				
			||||||
    changedAt: string;
 | 
					    changedAt: string;
 | 
				
			||||||
    createdAt: string;
 | 
					    createdAt: string;
 | 
				
			||||||
    deadline: string;
 | 
					    deadline?: (string | null);
 | 
				
			||||||
    status: number;
 | 
					    status: number;
 | 
				
			||||||
    totalPrice: number;
 | 
					    totalPrice: number;
 | 
				
			||||||
    rank: number;
 | 
					    rank: number;
 | 
				
			||||||
@@ -21,5 +22,6 @@ export type DealSummary = {
 | 
				
			|||||||
    deliveryDate?: (string | null);
 | 
					    deliveryDate?: (string | null);
 | 
				
			||||||
    receivingSlotDate?: (string | null);
 | 
					    receivingSlotDate?: (string | null);
 | 
				
			||||||
    billRequest?: (DealBillRequestSchema | null);
 | 
					    billRequest?: (DealBillRequestSchema | null);
 | 
				
			||||||
 | 
					    group?: (DealGroupSchema | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,10 +10,14 @@ import type { DealAddServiceRequest } from '../models/DealAddServiceRequest';
 | 
				
			|||||||
import type { DealAddServiceResponse } from '../models/DealAddServiceResponse';
 | 
					import type { DealAddServiceResponse } from '../models/DealAddServiceResponse';
 | 
				
			||||||
import type { DealAddServicesRequest } from '../models/DealAddServicesRequest';
 | 
					import type { DealAddServicesRequest } from '../models/DealAddServicesRequest';
 | 
				
			||||||
import type { DealAddServicesResponse } from '../models/DealAddServicesResponse';
 | 
					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 { DealChangeStatusRequest } from '../models/DealChangeStatusRequest';
 | 
				
			||||||
import type { DealChangeStatusResponse } from '../models/DealChangeStatusResponse';
 | 
					import type { DealChangeStatusResponse } from '../models/DealChangeStatusResponse';
 | 
				
			||||||
import type { DealCompleteRequest } from '../models/DealCompleteRequest';
 | 
					import type { DealCompleteRequest } from '../models/DealCompleteRequest';
 | 
				
			||||||
import type { DealCompleteResponse } from '../models/DealCompleteResponse';
 | 
					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 { DealCreateGuestUrlRequest } from '../models/DealCreateGuestUrlRequest';
 | 
				
			||||||
import type { DealCreateGuestUrlResponse } from '../models/DealCreateGuestUrlResponse';
 | 
					import type { DealCreateGuestUrlResponse } from '../models/DealCreateGuestUrlResponse';
 | 
				
			||||||
import type { DealCreateRequest } from '../models/DealCreateRequest';
 | 
					import type { DealCreateRequest } from '../models/DealCreateRequest';
 | 
				
			||||||
@@ -28,6 +32,10 @@ import type { DealDeleteServiceResponse } from '../models/DealDeleteServiceRespo
 | 
				
			|||||||
import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest';
 | 
					import type { DealDeleteServicesRequest } from '../models/DealDeleteServicesRequest';
 | 
				
			||||||
import type { DealDeleteServicesResponse } from '../models/DealDeleteServicesResponse';
 | 
					import type { DealDeleteServicesResponse } from '../models/DealDeleteServicesResponse';
 | 
				
			||||||
import type { DealGetAllResponse } from '../models/DealGetAllResponse';
 | 
					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 { DealPrefillRequest } from '../models/DealPrefillRequest';
 | 
				
			||||||
import type { DealPrefillResponse } from '../models/DealPrefillResponse';
 | 
					import type { DealPrefillResponse } from '../models/DealPrefillResponse';
 | 
				
			||||||
import type { DealProductAddKitRequest } from '../models/DealProductAddKitRequest';
 | 
					import type { DealProductAddKitRequest } from '../models/DealProductAddKitRequest';
 | 
				
			||||||
@@ -36,6 +44,8 @@ import type { DealQuickCreateRequest } from '../models/DealQuickCreateRequest';
 | 
				
			|||||||
import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse';
 | 
					import type { DealQuickCreateResponse } from '../models/DealQuickCreateResponse';
 | 
				
			||||||
import type { DealRecalculatePriceRequest } from '../models/DealRecalculatePriceRequest';
 | 
					import type { DealRecalculatePriceRequest } from '../models/DealRecalculatePriceRequest';
 | 
				
			||||||
import type { DealRecalculatePriceResponse } from '../models/DealRecalculatePriceResponse';
 | 
					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 { DealSchema } from '../models/DealSchema';
 | 
				
			||||||
import type { DealServicesCopyRequest } from '../models/DealServicesCopyRequest';
 | 
					import type { DealServicesCopyRequest } from '../models/DealServicesCopyRequest';
 | 
				
			||||||
import type { DealServicesCopyResponse } from '../models/DealServicesCopyResponse';
 | 
					import type { DealServicesCopyResponse } from '../models/DealServicesCopyResponse';
 | 
				
			||||||
@@ -652,4 +662,104 @@ export class DealService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add To Group
 | 
				
			||||||
 | 
					     * @returns DealAddToGroupResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static addDealToGroup({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: DealAddToGroupRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<DealAddToGroupResponse> {
 | 
				
			||||||
 | 
					        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<DealCreateGroupResponse> {
 | 
				
			||||||
 | 
					        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<DealRemoveFromGroupResponse> {
 | 
				
			||||||
 | 
					        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<DealGroupUpdateResponse> {
 | 
				
			||||||
 | 
					        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<DealGroupChangeStatusResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/deal/group/change-status',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,12 @@ import styles from "./Board.module.css";
 | 
				
			|||||||
import { Divider, Text, Title } from "@mantine/core";
 | 
					import { Divider, Text, Title } from "@mantine/core";
 | 
				
			||||||
import { Draggable, Droppable } from "@hello-pangea/dnd";
 | 
					import { Draggable, Droppable } from "@hello-pangea/dnd";
 | 
				
			||||||
import CreateDealButton from "../CreateDealButton/CreateDealButton.tsx";
 | 
					import CreateDealButton from "../CreateDealButton/CreateDealButton.tsx";
 | 
				
			||||||
import { DealSummary } from "../../../client";
 | 
					import { DealGroupSchema, DealSummary } from "../../../client";
 | 
				
			||||||
import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx";
 | 
					import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx";
 | 
				
			||||||
import classNames from "classnames";
 | 
					import classNames from "classnames";
 | 
				
			||||||
import { getPluralForm } from "../../../shared/lib/utils.ts";
 | 
					import { getPluralForm } from "../../../shared/lib/utils.ts";
 | 
				
			||||||
import { sum } from "lodash";
 | 
					import { groupBy, has, sum, uniq } from "lodash";
 | 
				
			||||||
 | 
					import { DealGroupView } from "../DealGroupView/DealGroupView.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    droppableId: string;
 | 
					    droppableId: string;
 | 
				
			||||||
@@ -16,24 +17,127 @@ type Props = {
 | 
				
			|||||||
    summaries: DealSummary[];
 | 
					    summaries: DealSummary[];
 | 
				
			||||||
    color: string;
 | 
					    color: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					type GroupWithDeals = { group: DealGroupSchema, deals: DealSummary[] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Board: FC<Props> = ({
 | 
					export const Board: FC<Props> = ({
 | 
				
			||||||
    droppableId,
 | 
					                                     droppableId,
 | 
				
			||||||
    title,
 | 
					                                     title,
 | 
				
			||||||
    summaries,
 | 
					                                     summaries,
 | 
				
			||||||
    color,
 | 
					                                     color,
 | 
				
			||||||
    withCreateButton = false,
 | 
					                                     withCreateButton = false,
 | 
				
			||||||
}) => {
 | 
					                                 }) => {
 | 
				
			||||||
    const getDealsText = () => {
 | 
					    const getDealsText = () => {
 | 
				
			||||||
        const pluralForm = getPluralForm(
 | 
					        const pluralForm = getPluralForm(
 | 
				
			||||||
            summaries.length,
 | 
					            summaries.length,
 | 
				
			||||||
            "сделка",
 | 
					            "сделка",
 | 
				
			||||||
            "сделки",
 | 
					            "сделки",
 | 
				
			||||||
            "сделок"
 | 
					            "сделок",
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        return `${summaries.length} ${pluralForm}: ${sum(summaries.map(summary => summary.totalPrice)).toLocaleString("ru-RU")}₽`;
 | 
					        return `${summaries.length} ${pluralForm}: ${sum(summaries.map(summary => summary.totalPrice)).toLocaleString("ru-RU")}₽`;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    const isGroup = (obj: GroupWithDeals | DealSummary): obj is GroupWithDeals => {
 | 
				
			||||||
 | 
					        return has(obj, "deals");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getDateFromDealOrGroup = (obj: GroupWithDeals | DealSummary) => {
 | 
				
			||||||
 | 
					        // if is group get group with the delivery earliest date
 | 
				
			||||||
 | 
					        if (isGroup(obj)) {
 | 
				
			||||||
 | 
					            const dates = obj.deals.map(d => d.deliveryDate || d.createdAt).filter(Boolean);
 | 
				
			||||||
 | 
					            if (dates.length === 0) return null;
 | 
				
			||||||
 | 
					            return new Date(Math.min(...dates.map(d => {
 | 
				
			||||||
 | 
					                return new Date(d).getTime();
 | 
				
			||||||
 | 
					            })));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // if is deal get deal delivery date
 | 
				
			||||||
 | 
					        return new Date(obj.deliveryDate || obj.createdAt);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const getDealGroups = (): GroupWithDeals[] => {
 | 
				
			||||||
 | 
					        const groups = uniq<DealGroupSchema>(summaries.filter(s => s.group).map(summary => summary.group) as DealGroupSchema[]);
 | 
				
			||||||
 | 
					        if (groups.length === 0) return [];
 | 
				
			||||||
 | 
					        const groupedSummaries = groupBy(summaries, "group.id");
 | 
				
			||||||
 | 
					        const groupDict = groups.reduce((acc, group) => {
 | 
				
			||||||
 | 
					                acc[group.id] = group;
 | 
				
			||||||
 | 
					                return acc;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            , {} as { [key: number]: DealGroupSchema });
 | 
				
			||||||
 | 
					        return Object.entries(groupedSummaries).reduce((acc, [groupId, deals]) => {
 | 
				
			||||||
 | 
					            if (!groupId) return acc;
 | 
				
			||||||
 | 
					            const group = groupDict[parseInt(groupId)];
 | 
				
			||||||
 | 
					            if (!group) return acc;
 | 
				
			||||||
 | 
					            acc.push({
 | 
				
			||||||
 | 
					                group,
 | 
				
			||||||
 | 
					                deals,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return acc;
 | 
				
			||||||
 | 
					        }, [] as { group: DealGroupSchema; deals: DealSummary[] }[]);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const getDealsAndGroups = (): (GroupWithDeals | DealSummary)[] => {
 | 
				
			||||||
 | 
					        const groups = getDealGroups();
 | 
				
			||||||
 | 
					        const deals = summaries.filter(s => !s.group);
 | 
				
			||||||
 | 
					        const data = [...groups, ...deals];
 | 
				
			||||||
 | 
					        return data.sort((a, b) => {
 | 
				
			||||||
 | 
					            const aDate = getDateFromDealOrGroup(a);
 | 
				
			||||||
 | 
					            const bDate = getDateFromDealOrGroup(b);
 | 
				
			||||||
 | 
					            if (!aDate || !bDate) return 0;
 | 
				
			||||||
 | 
					            return aDate.getTime() - bDate.getTime();
 | 
				
			||||||
 | 
					        }).map((obj, index) => {
 | 
				
			||||||
 | 
					            if (isGroup(obj)) {
 | 
				
			||||||
 | 
					                obj.deals[0].rank = index;
 | 
				
			||||||
 | 
					                return obj;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            obj.rank = index;
 | 
				
			||||||
 | 
					            return obj;
 | 
				
			||||||
 | 
					        }) as (GroupWithDeals | DealSummary)[];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const renderDeal = (deal: DealSummary) => {
 | 
				
			||||||
 | 
					        return (<Draggable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            draggableId={deal.id.toString()}
 | 
				
			||||||
 | 
					            index={deal.rank}
 | 
				
			||||||
 | 
					            key={deal.id}>
 | 
				
			||||||
 | 
					            {(provided, snapshot) => (
 | 
				
			||||||
 | 
					                <div
 | 
				
			||||||
 | 
					                    {...provided.draggableProps}
 | 
				
			||||||
 | 
					                    {...provided.dragHandleProps}
 | 
				
			||||||
 | 
					                    ref={provided.innerRef}>
 | 
				
			||||||
 | 
					                    <div
 | 
				
			||||||
 | 
					                        style={{
 | 
				
			||||||
 | 
					                            transition: "transform 0.1s ease-in-out",
 | 
				
			||||||
 | 
					                            transform: snapshot.combineWith ? "scale(0.85)" : "none",
 | 
				
			||||||
 | 
					                            color: snapshot.combineWith ? "red" : "black",
 | 
				
			||||||
 | 
					                        }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <DealSummaryCard
 | 
				
			||||||
 | 
					                            dealSummary={deal}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					        </Draggable>);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const renderGroup = (obj: GroupWithDeals) => {
 | 
				
			||||||
 | 
					        const { deals, group } = obj;
 | 
				
			||||||
 | 
					        return (<Draggable
 | 
				
			||||||
 | 
					            draggableId={"group-" + group.id}
 | 
				
			||||||
 | 
					            index={deals[0].rank}
 | 
				
			||||||
 | 
					            key={"group-" + group.id}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            {(provided) => (
 | 
				
			||||||
 | 
					                <div
 | 
				
			||||||
 | 
					                    {...provided.draggableProps}
 | 
				
			||||||
 | 
					                    {...provided.dragHandleProps}
 | 
				
			||||||
 | 
					                    ref={provided.innerRef}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                    <DealGroupView
 | 
				
			||||||
 | 
					                        deals={deals}
 | 
				
			||||||
 | 
					                        group={group}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					        </Draggable>);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={styles["container"]}>
 | 
					        <div className={styles["container"]}>
 | 
				
			||||||
            <div className={styles["header"]}>
 | 
					            <div className={styles["header"]}>
 | 
				
			||||||
@@ -45,38 +149,29 @@ export const Board: FC<Props> = ({
 | 
				
			|||||||
                    color={color}
 | 
					                    color={color}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <Droppable droppableId={droppableId}>
 | 
					            <Droppable
 | 
				
			||||||
 | 
					                isCombineEnabled
 | 
				
			||||||
 | 
					                droppableId={droppableId}>
 | 
				
			||||||
                {(provided, snapshot) => (
 | 
					                {(provided, snapshot) => (
 | 
				
			||||||
                    <div
 | 
					                    <div
 | 
				
			||||||
                        ref={provided.innerRef}
 | 
					                        ref={provided.innerRef}
 | 
				
			||||||
                        className={classNames(
 | 
					                        className={classNames(
 | 
				
			||||||
                            styles["items-list"],
 | 
					                            styles["items-list"],
 | 
				
			||||||
                            snapshot.isDraggingOver &&
 | 
					                            snapshot.isDraggingOver &&
 | 
				
			||||||
                                !snapshot.draggingFromThisWith &&
 | 
					                            !snapshot.draggingFromThisWith &&
 | 
				
			||||||
                                styles["items-list-drag-over"]
 | 
					                            styles["items-list-drag-over"],
 | 
				
			||||||
                        )}
 | 
					                        )}
 | 
				
			||||||
                        {...provided.droppableProps}>
 | 
					                        {...provided.droppableProps}>
 | 
				
			||||||
                        {withCreateButton && (
 | 
					                        {withCreateButton && (
 | 
				
			||||||
                            <CreateDealButton onClick={() => {}} />
 | 
					                            <CreateDealButton onClick={() => {
 | 
				
			||||||
 | 
					                            }} />
 | 
				
			||||||
                        )}
 | 
					                        )}
 | 
				
			||||||
                        {summaries.map(summary => (
 | 
					                        {getDealsAndGroups().map(obj => {
 | 
				
			||||||
                            <Draggable
 | 
					                            if (isGroup(obj)) {
 | 
				
			||||||
                                draggableId={summary.id.toString()}
 | 
					                                return renderGroup(obj);
 | 
				
			||||||
                                index={summary.rank}
 | 
					                            }
 | 
				
			||||||
                                key={summary.id}>
 | 
					                            return renderDeal(obj);
 | 
				
			||||||
                                {provided => (
 | 
					                        })}
 | 
				
			||||||
                                    <div
 | 
					 | 
				
			||||||
                                        {...provided.draggableProps}
 | 
					 | 
				
			||||||
                                        {...provided.dragHandleProps}
 | 
					 | 
				
			||||||
                                        ref={provided.innerRef}>
 | 
					 | 
				
			||||||
                                        <DealSummaryCard
 | 
					 | 
				
			||||||
                                            dealSummary={summary}
 | 
					 | 
				
			||||||
                                        />
 | 
					 | 
				
			||||||
                                    </div>
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                            </Draggable>
 | 
					 | 
				
			||||||
                        ))}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        {provided.placeholder}
 | 
					                        {provided.placeholder}
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
@@ -86,3 +181,4 @@ export const Board: FC<Props> = ({
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Board;
 | 
					export default Board;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								src/components/Dnd/DealGroupView/DealGroupView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/components/Dnd/DealGroupView/DealGroupView.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					import { DealGroupSchema, DealService, 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";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					    deals: DealSummary[];
 | 
				
			||||||
 | 
					    group: DealGroupSchema;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const DealGroupView: FC<Props> = ({ deals, group }) => {
 | 
				
			||||||
 | 
					    const theme = useMantineColorScheme();
 | 
				
			||||||
 | 
					    const [name, setName] = useState<string>(group.name || "");
 | 
				
			||||||
 | 
					    const [debouncedName] = useDebouncedValue(name, 200);
 | 
				
			||||||
 | 
					    const totalPrice = useMemo(() => deals.reduce((acc, deal) => acc + deal.totalPrice, 0), [deals]);
 | 
				
			||||||
 | 
					    const totalProducts = useMemo(() => deals.reduce((acc, deal) => acc + deal.totalProducts, 0), [deals]);
 | 
				
			||||||
 | 
					    const updateName = () => {
 | 
				
			||||||
 | 
					        if (debouncedName === group.name) return;
 | 
				
			||||||
 | 
					        DealService.updateDealGroup({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                data: {
 | 
				
			||||||
 | 
					                    ...group,
 | 
				
			||||||
 | 
					                    name: debouncedName,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }).then(response => {
 | 
				
			||||||
 | 
					            if (response.ok) return;
 | 
				
			||||||
 | 
					            setName(group.name || "");
 | 
				
			||||||
 | 
					            notifications.guess(response.ok, { message: response.message });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        updateName();
 | 
				
			||||||
 | 
					    }, [debouncedName]);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Flex
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					                border: "dashed var(--item-border-size) var(--mantine-color-default-border)",
 | 
				
			||||||
 | 
					                borderRadius: "0.5rem",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p={rem(5)}
 | 
				
			||||||
 | 
					            py={rem(10)}
 | 
				
			||||||
 | 
					            bg={theme.colorScheme === "dark" ? "var(--mantine-color-dark-5)" : "var(--mantine-color-gray-1)"}
 | 
				
			||||||
 | 
					            gap={rem(10)}
 | 
				
			||||||
 | 
					            direction={"column"}>
 | 
				
			||||||
 | 
					            <Flex
 | 
				
			||||||
 | 
					                justify={"space-between"}
 | 
				
			||||||
 | 
					                align={"center"}
 | 
				
			||||||
 | 
					                gap={rem(10)}
 | 
				
			||||||
 | 
					                px={rem(10)}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <TextInput
 | 
				
			||||||
 | 
					                    value={name}
 | 
				
			||||||
 | 
					                    onChange={event => setName(event.currentTarget.value)}
 | 
				
			||||||
 | 
					                    variant={"unstyled"}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <IconGripHorizontal />
 | 
				
			||||||
 | 
					            </Flex>
 | 
				
			||||||
 | 
					            <Flex direction={"column"} gap={rem(10)}>
 | 
				
			||||||
 | 
					                {deals.map(deal => (
 | 
				
			||||||
 | 
					                    <DealSummaryCard
 | 
				
			||||||
 | 
					                        color={theme.colorScheme === "dark" ? "var(--mantine-color-dark-6)" : "var(--mantine-color-gray-2)"}
 | 
				
			||||||
 | 
					                        key={deal.id}
 | 
				
			||||||
 | 
					                        dealSummary={deal}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                ))}
 | 
				
			||||||
 | 
					            </Flex>
 | 
				
			||||||
 | 
					            <Flex
 | 
				
			||||||
 | 
					                p={rem(10)}
 | 
				
			||||||
 | 
					                direction={"column"}
 | 
				
			||||||
 | 
					                bg={theme.colorScheme === "dark" ? "var(--mantine-color-dark-6)" : "var(--mantine-color-gray-2)"}
 | 
				
			||||||
 | 
					                style={{ borderRadius: "0.5rem" }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <Text
 | 
				
			||||||
 | 
					                    c={"gray.6"}
 | 
				
			||||||
 | 
					                    size={"xs"}>Сумма: {totalPrice.toLocaleString("ru-RU")} руб.</Text>
 | 
				
			||||||
 | 
					                <Text
 | 
				
			||||||
 | 
					                    c={"gray.6"}
 | 
				
			||||||
 | 
					                    size={"xs"}>Всего товаров: {totalProducts.toLocaleString("ru-RU")} шт.</Text>
 | 
				
			||||||
 | 
					            </Flex>
 | 
				
			||||||
 | 
					        </Flex>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -13,20 +13,27 @@ import {
 | 
				
			|||||||
    Popover,
 | 
					    Popover,
 | 
				
			||||||
    rem,
 | 
					    rem,
 | 
				
			||||||
    Text,
 | 
					    Text,
 | 
				
			||||||
 | 
					    ThemeIcon,
 | 
				
			||||||
    Tooltip,
 | 
					    Tooltip,
 | 
				
			||||||
} from "@mantine/core";
 | 
					} from "@mantine/core";
 | 
				
			||||||
import { useDealPageContext } from "../../../pages/LeadsPage/contexts/DealPageContext.tsx";
 | 
					import { useDealPageContext } from "../../../pages/LeadsPage/contexts/DealPageContext.tsx";
 | 
				
			||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 | 
					import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 | 
				
			||||||
import { faCheck } from "@fortawesome/free-solid-svg-icons";
 | 
					import { faCheck } from "@fortawesome/free-solid-svg-icons";
 | 
				
			||||||
import { DealStatus } from "../../../shared/enums/DealStatus.ts";
 | 
					import { DealStatus } from "../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
import { IconCheck } from "@tabler/icons-react";
 | 
					import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					import { useContextMenu } from "mantine-contextmenu";
 | 
				
			||||||
 | 
					import useDealSummaryState from "./useDealSummaryState.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    dealSummary: DealSummary;
 | 
					    dealSummary: DealSummary;
 | 
				
			||||||
 | 
					    color?: string
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DealSummaryCard: FC<Props> = ({ dealSummary }) => {
 | 
					const DealSummaryCard: FC<Props> = ({ dealSummary, color }) => {
 | 
				
			||||||
 | 
					    const { showContextMenu } = useContextMenu();
 | 
				
			||||||
    const { setSelectedDeal } = useDealPageContext();
 | 
					    const { setSelectedDeal } = useDealPageContext();
 | 
				
			||||||
 | 
					    const { onDelete, onComplete, onDeleteFromGroup } = useDealSummaryState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onDealSummaryClick = () => {
 | 
					    const onDealSummaryClick = () => {
 | 
				
			||||||
        DealService.getDealById({ dealId: dealSummary.id }).then(deal => {
 | 
					        DealService.getDealById({ dealId: dealSummary.id }).then(deal => {
 | 
				
			||||||
            setSelectedDeal(deal);
 | 
					            setSelectedDeal(deal);
 | 
				
			||||||
@@ -63,12 +70,36 @@ const DealSummaryCard: FC<Props> = ({ dealSummary }) => {
 | 
				
			|||||||
        <Indicator
 | 
					        <Indicator
 | 
				
			||||||
            position={"top-end"}
 | 
					            position={"top-end"}
 | 
				
			||||||
            withBorder
 | 
					            withBorder
 | 
				
			||||||
 | 
					            size={15}
 | 
				
			||||||
 | 
					            processing
 | 
				
			||||||
            {...getIndicatorProps()}
 | 
					            {...getIndicatorProps()}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
 | 
					                onContextMenu={showContextMenu([
 | 
				
			||||||
 | 
					                    ...dealSummary.group ? [{
 | 
				
			||||||
 | 
					                        key: "removeFromGroup",
 | 
				
			||||||
 | 
					                        onClick: () => onDeleteFromGroup(dealSummary),
 | 
				
			||||||
 | 
					                        title: "Убрать из группы",
 | 
				
			||||||
 | 
					                        icon: <IconLayoutGridRemove />,
 | 
				
			||||||
 | 
					                    }] : [],
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        key: "complete",
 | 
				
			||||||
 | 
					                        onClick: () => onComplete(dealSummary),
 | 
				
			||||||
 | 
					                        title: "Завершить",
 | 
				
			||||||
 | 
					                        icon: <IconCheck />,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        key: "delete",
 | 
				
			||||||
 | 
					                        onClick: () => onDelete(dealSummary),
 | 
				
			||||||
 | 
					                        title: "Удалить",
 | 
				
			||||||
 | 
					                        icon: <IconTrash />,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                ])}
 | 
				
			||||||
                onClick={() => onDealSummaryClick()}
 | 
					                onClick={() => onDealSummaryClick()}
 | 
				
			||||||
                className={styles["container"]}>
 | 
					                className={styles["container"]}
 | 
				
			||||||
 | 
					                style={{ backgroundColor: color }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
                <Flex direction={"column"} flex={1} gap={rem(3)}>
 | 
					                <Flex direction={"column"} flex={1} gap={rem(3)}>
 | 
				
			||||||
                    <Flex justify={"space-between"}>
 | 
					                    <Flex justify={"space-between"}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,7 +112,9 @@ const DealSummaryCard: FC<Props> = ({ dealSummary }) => {
 | 
				
			|||||||
                        </Text>
 | 
					                        </Text>
 | 
				
			||||||
                    </Flex>
 | 
					                    </Flex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <Text c={"blue.5"} size={"sm"}>
 | 
					                    <Text
 | 
				
			||||||
 | 
					                        c={"blue.5"}
 | 
				
			||||||
 | 
					                        size={"sm"}>
 | 
				
			||||||
                        {dealSummary.name}
 | 
					                        {dealSummary.name}
 | 
				
			||||||
                    </Text>
 | 
					                    </Text>
 | 
				
			||||||
                    <Flex
 | 
					                    <Flex
 | 
				
			||||||
@@ -109,14 +142,14 @@ const DealSummaryCard: FC<Props> = ({ dealSummary }) => {
 | 
				
			|||||||
                    <Flex direction={"column"}>
 | 
					                    <Flex direction={"column"}>
 | 
				
			||||||
                        {dealSummary.deliveryDate && (
 | 
					                        {dealSummary.deliveryDate && (
 | 
				
			||||||
                            <Text
 | 
					                            <Text
 | 
				
			||||||
                                c={"gray.6"}
 | 
					                                c={"blue.5"}
 | 
				
			||||||
                                size={"sm"}>
 | 
					                                size={"sm"}>
 | 
				
			||||||
                                Доставка: {(new Date(dealSummary.deliveryDate)).toLocaleDateString("ru-RU")}
 | 
					                                Доставка: {(new Date(dealSummary.deliveryDate)).toLocaleDateString("ru-RU")}
 | 
				
			||||||
                            </Text>
 | 
					                            </Text>
 | 
				
			||||||
                        )}
 | 
					                        )}
 | 
				
			||||||
                        {dealSummary.receivingSlotDate && (
 | 
					                        {dealSummary.receivingSlotDate && (
 | 
				
			||||||
                            <Text
 | 
					                            <Text
 | 
				
			||||||
                                c={"gray.6"}
 | 
					                                c={"blue.5"}
 | 
				
			||||||
                                size={"sm"}>
 | 
					                                size={"sm"}>
 | 
				
			||||||
                                Слот: {(new Date(dealSummary.receivingSlotDate)).toLocaleDateString("ru-RU")}
 | 
					                                Слот: {(new Date(dealSummary.receivingSlotDate)).toLocaleDateString("ru-RU")}
 | 
				
			||||||
                            </Text>
 | 
					                            </Text>
 | 
				
			||||||
@@ -163,8 +196,11 @@ const DealSummaryCard: FC<Props> = ({ dealSummary }) => {
 | 
				
			|||||||
                            </CopyButton>
 | 
					                            </CopyButton>
 | 
				
			||||||
                            {dealSummary.billRequest?.paid && (
 | 
					                            {dealSummary.billRequest?.paid && (
 | 
				
			||||||
                                <Tooltip label={"Оплачен"}>
 | 
					                                <Tooltip label={"Оплачен"}>
 | 
				
			||||||
 | 
					                                    <ThemeIcon variant={"transparent"}>
 | 
				
			||||||
 | 
					                                        <IconCheck />
 | 
				
			||||||
 | 
					                                    </ThemeIcon>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                    <IconCheck />
 | 
					 | 
				
			||||||
                                </Tooltip>
 | 
					                                </Tooltip>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            )}
 | 
					                            )}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										101
									
								
								src/components/Dnd/DealSummaryCard/useDealSummaryState.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/components/Dnd/DealSummaryCard/useDealSummaryState.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					import { DealService, DealSummary } from "../../../client";
 | 
				
			||||||
 | 
					import { useDealPageContext } from "../../../pages/LeadsPage/contexts/DealPageContext.tsx";
 | 
				
			||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { Text } from "@mantine/core";
 | 
				
			||||||
 | 
					import { notifications } from "../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDealSummaryState = () => {
 | 
				
			||||||
 | 
					    const { refetchDeals } = useDealPageContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const recalculate = async (dealId: number) => {
 | 
				
			||||||
 | 
					        return DealService.recalculateDealPrice({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                dealId: dealId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }).then(({ ok, message }) => {
 | 
				
			||||||
 | 
					            notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onDelete = (summary: DealSummary) => {
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление сделки",
 | 
				
			||||||
 | 
					            children: (
 | 
				
			||||||
 | 
					                <Text>
 | 
				
			||||||
 | 
					                    Вы уверены что хотите удалить сделку "{summary.name}"?
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            labels: { confirm: "Да", cancel: "Нет" },
 | 
				
			||||||
 | 
					            confirmProps: { color: "red" },
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                DealService.deleteDeal({
 | 
				
			||||||
 | 
					                    requestBody: {
 | 
				
			||||||
 | 
					                        dealId: summary.id,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }).then(async (response) => {
 | 
				
			||||||
 | 
					                    notifications.guess(response.ok, { message: response.message });
 | 
				
			||||||
 | 
					                    if (response.ok) await refetchDeals();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onComplete = (summary: DealSummary) => {
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление сделки",
 | 
				
			||||||
 | 
					            children: (
 | 
				
			||||||
 | 
					                <Text>
 | 
				
			||||||
 | 
					                    Вы уверены что хотите завершить сделку "{summary.name}"?
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            labels: { confirm: "Да", cancel: "Нет" },
 | 
				
			||||||
 | 
					            confirmProps: { color: "green" },
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                DealService.completeDeal({
 | 
				
			||||||
 | 
					                    requestBody: {
 | 
				
			||||||
 | 
					                        dealId: summary.id,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }).then(async (response) => {
 | 
				
			||||||
 | 
					                    notifications.guess(response.ok, { message: response.message });
 | 
				
			||||||
 | 
					                    if (response.ok) await refetchDeals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onDeleteFromGroup = (summary: DealSummary) => {
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление сделки",
 | 
				
			||||||
 | 
					            children: (
 | 
				
			||||||
 | 
					                <Text>
 | 
				
			||||||
 | 
					                    Вы уверены что хотите удалить сделку "{summary.name}" из группы?
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            labels: { confirm: "Да", cancel: "Нет" },
 | 
				
			||||||
 | 
					            confirmProps: { color: "red" },
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                DealService.removeDealFromGroup({
 | 
				
			||||||
 | 
					                    requestBody: {
 | 
				
			||||||
 | 
					                        dealId: summary.id,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }).then(async (response) => {
 | 
				
			||||||
 | 
					                    notifications.guess(response.ok, { message: response.message });
 | 
				
			||||||
 | 
					                    if (response.ok) await refetchDeals();
 | 
				
			||||||
 | 
					                    await recalculate(summary.id);
 | 
				
			||||||
 | 
					                    if (response.ok) await refetchDeals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        onDelete,
 | 
				
			||||||
 | 
					        onComplete,
 | 
				
			||||||
 | 
					        onDeleteFromGroup,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useDealSummaryState;
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/main.tsx
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/main.tsx
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
import ReactDOM from "react-dom/client";
 | 
					import ReactDOM from "react-dom/client";
 | 
				
			||||||
import { RouterProvider, createRouter } from "@tanstack/react-router";
 | 
					import { createRouter, RouterProvider } from "@tanstack/react-router";
 | 
				
			||||||
import { routeTree } from "./routeTree.gen";
 | 
					import { routeTree } from "./routeTree.gen";
 | 
				
			||||||
import { MantineProvider } from "@mantine/core";
 | 
					import { MantineProvider } from "@mantine/core";
 | 
				
			||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 | 
					import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 | 
				
			||||||
@@ -10,6 +10,8 @@ import "@mantine/core/styles.css";
 | 
				
			|||||||
import "@mantine/notifications/styles.css";
 | 
					import "@mantine/notifications/styles.css";
 | 
				
			||||||
import "@mantine/dates/styles.css";
 | 
					import "@mantine/dates/styles.css";
 | 
				
			||||||
import "mantine-react-table/styles.css";
 | 
					import "mantine-react-table/styles.css";
 | 
				
			||||||
 | 
					import "mantine-contextmenu/styles.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "dayjs/locale/ru";
 | 
					import "dayjs/locale/ru";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,6 +22,7 @@ import { OpenAPI } from "./client";
 | 
				
			|||||||
import { DatesProvider } from "@mantine/dates";
 | 
					import { DatesProvider } from "@mantine/dates";
 | 
				
			||||||
import { modals } from "./modals/modals.ts";
 | 
					import { modals } from "./modals/modals.ts";
 | 
				
			||||||
import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
					import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
				
			||||||
 | 
					import { ContextMenuProvider } from "mantine-contextmenu";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuring router
 | 
					// Configuring router
 | 
				
			||||||
const router = createRouter({ routeTree });
 | 
					const router = createRouter({ routeTree });
 | 
				
			||||||
@@ -42,22 +45,25 @@ const queryClient = new QueryClient();
 | 
				
			|||||||
OpenAPI.BASE = import.meta.env.VITE_API_URL;
 | 
					OpenAPI.BASE = import.meta.env.VITE_API_URL;
 | 
				
			||||||
OpenAPI.TOKEN = JSON.parse(localStorage.getItem("authState") || "{}")[
 | 
					OpenAPI.TOKEN = JSON.parse(localStorage.getItem("authState") || "{}")[
 | 
				
			||||||
    "accessToken"
 | 
					    "accessToken"
 | 
				
			||||||
];
 | 
					    ];
 | 
				
			||||||
ReactDOM.createRoot(document.getElementById("root")!).render(
 | 
					ReactDOM.createRoot(document.getElementById("root")!).render(
 | 
				
			||||||
    <Provider store={store}>
 | 
					    <Provider store={store}>
 | 
				
			||||||
        <QueryClientProvider client={queryClient}>
 | 
					        <QueryClientProvider client={queryClient}>
 | 
				
			||||||
            <MantineProvider defaultColorScheme={"dark"}>
 | 
					            <MantineProvider defaultColorScheme={"dark"}>
 | 
				
			||||||
                <ModalsProvider
 | 
					                <ContextMenuProvider>
 | 
				
			||||||
                    labels={{ confirm: "Да", cancel: "Нет" }}
 | 
					
 | 
				
			||||||
                    modals={modals}>
 | 
					                    <ModalsProvider
 | 
				
			||||||
                    <DatesProvider settings={{ locale: "ru" }}>
 | 
					                        labels={{ confirm: "Да", cancel: "Нет" }}
 | 
				
			||||||
                        <TasksProvider>
 | 
					                        modals={modals}>
 | 
				
			||||||
                            <RouterProvider router={router} />
 | 
					                        <DatesProvider settings={{ locale: "ru" }}>
 | 
				
			||||||
                            <Notifications />
 | 
					                            <TasksProvider>
 | 
				
			||||||
                        </TasksProvider>
 | 
					                                <RouterProvider router={router} />
 | 
				
			||||||
                    </DatesProvider>
 | 
					                                <Notifications />
 | 
				
			||||||
                </ModalsProvider>
 | 
					                            </TasksProvider>
 | 
				
			||||||
 | 
					                        </DatesProvider>
 | 
				
			||||||
 | 
					                    </ModalsProvider>
 | 
				
			||||||
 | 
					                </ContextMenuProvider>
 | 
				
			||||||
            </MantineProvider>
 | 
					            </MantineProvider>
 | 
				
			||||||
        </QueryClientProvider>
 | 
					        </QueryClientProvider>
 | 
				
			||||||
    </Provider>
 | 
					    </Provider>,
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ import { useMemo } from "react";
 | 
				
			|||||||
import { DealServiceSchema } from "../../../../client";
 | 
					import { DealServiceSchema } from "../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    // onChange: (service: DealServiceSchema, quantity: number) => void;
 | 
					 | 
				
			||||||
    data: DealServiceSchema[];
 | 
					    data: DealServiceSchema[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,11 +30,6 @@ export const useDealServicesTableColumns = (props: Props) => {
 | 
				
			|||||||
                accessorKey: "price",
 | 
					                accessorKey: "price",
 | 
				
			||||||
                header: "Цена",
 | 
					                header: "Цена",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                enableGrouping: false,
 | 
					 | 
				
			||||||
                accessorKey: "service.cost",
 | 
					 | 
				
			||||||
                header: "Себестоимость",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                enableGrouping: false,
 | 
					                enableGrouping: false,
 | 
				
			||||||
                accessorKey: "quantity",
 | 
					                accessorKey: "quantity",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,30 +4,40 @@ import { DealSchema } from "../../../client";
 | 
				
			|||||||
type DealPageContextState = {
 | 
					type DealPageContextState = {
 | 
				
			||||||
    selectedDeal?: DealSchema;
 | 
					    selectedDeal?: DealSchema;
 | 
				
			||||||
    setSelectedDeal: (deal: DealSchema | undefined) => void;
 | 
					    setSelectedDeal: (deal: DealSchema | undefined) => void;
 | 
				
			||||||
 | 
					    refetchDeals: () => Promise<void>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DealPageContext = createContext<DealPageContextState | undefined>(
 | 
					const DealPageContext = createContext<DealPageContextState | undefined>(
 | 
				
			||||||
    undefined
 | 
					    undefined,
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
const useDealPageContextState = () => {
 | 
					
 | 
				
			||||||
 | 
					type DealPageContextStateProps = {
 | 
				
			||||||
 | 
					    refetchDeals: () => Promise<void>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDealPageContextState = (props: DealPageContextStateProps) => {
 | 
				
			||||||
 | 
					    const { refetchDeals } = props;
 | 
				
			||||||
    const [selectedDeal, setSelectedDeal] = useState<DealSchema | undefined>(
 | 
					    const [selectedDeal, setSelectedDeal] = useState<DealSchema | undefined>(
 | 
				
			||||||
        undefined
 | 
					        undefined,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        selectedDeal,
 | 
					        selectedDeal,
 | 
				
			||||||
        setSelectedDeal,
 | 
					        setSelectedDeal,
 | 
				
			||||||
 | 
					        refetchDeals,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DealPageContextProviderProps = {
 | 
					type DealPageContextProviderProps = {
 | 
				
			||||||
    children: React.ReactNode;
 | 
					    children: React.ReactNode;
 | 
				
			||||||
 | 
					    refetchDeals: () => Promise<void>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DealPageContextProvider: FC<DealPageContextProviderProps> = ({
 | 
					export const DealPageContextProvider: FC<DealPageContextProviderProps> = ({
 | 
				
			||||||
    children,
 | 
					                                                                              children,
 | 
				
			||||||
}) => {
 | 
					                                                                              refetchDeals,
 | 
				
			||||||
    const state = useDealPageContextState();
 | 
					                                                                          }) => {
 | 
				
			||||||
 | 
					    const state = useDealPageContextState({ refetchDeals });
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <DealPageContext.Provider value={state}>
 | 
					        <DealPageContext.Provider value={state}>
 | 
				
			||||||
            {children}
 | 
					            {children}
 | 
				
			||||||
@@ -39,7 +49,7 @@ export const useDealPageContext = () => {
 | 
				
			|||||||
    const context = useContext(DealPageContext);
 | 
					    const context = useContext(DealPageContext);
 | 
				
			||||||
    if (!context) {
 | 
					    if (!context) {
 | 
				
			||||||
        throw new Error(
 | 
					        throw new Error(
 | 
				
			||||||
            "useDealPageContext must be used within a DealPageContextProvider"
 | 
					            "useDealPageContext must be used within a DealPageContextProvider",
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return context;
 | 
					    return context;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ import { useSelector } from "react-redux";
 | 
				
			|||||||
import { RootState } from "../../../../../../redux/store.ts";
 | 
					import { RootState } from "../../../../../../redux/store.ts";
 | 
				
			||||||
import useDealProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
					import useDealProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
				
			||||||
import LockCheckbox from "../../../../../../components/LockCheckbox/LockCheckbox.tsx";
 | 
					import LockCheckbox from "../../../../../../components/LockCheckbox/LockCheckbox.tsx";
 | 
				
			||||||
 | 
					import { useDebouncedCallback } from "@mantine/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    onKitAdd?: (kit: GetServiceKitSchema) => void;
 | 
					    onKitAdd?: (kit: GetServiceKitSchema) => void;
 | 
				
			||||||
@@ -23,6 +24,10 @@ const DealServicesTable: FC<Props> = ({
 | 
				
			|||||||
                                          onChange,
 | 
					                                          onChange,
 | 
				
			||||||
                                          onKitAdd,
 | 
					                                          onKitAdd,
 | 
				
			||||||
                                      }) => {
 | 
					                                      }) => {
 | 
				
			||||||
 | 
					    const debouncedOnChange = useDebouncedCallback(async (item: DealServiceSchema) => {
 | 
				
			||||||
 | 
					        if (!onChange) return;
 | 
				
			||||||
 | 
					        onChange(item);
 | 
				
			||||||
 | 
					    }, 200);
 | 
				
			||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { dealState } = useDealProductAndServiceTabState();
 | 
					    const { dealState } = useDealProductAndServiceTabState();
 | 
				
			||||||
@@ -39,7 +44,6 @@ const DealServicesTable: FC<Props> = ({
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    const onCreateClick = () => {
 | 
					    const onCreateClick = () => {
 | 
				
			||||||
        if (!onCreate) return;
 | 
					        if (!onCreate) return;
 | 
				
			||||||
        console.log("228");
 | 
					 | 
				
			||||||
        const serviceIds = items.map(service => service.service.id);
 | 
					        const serviceIds = items.map(service => service.service.id);
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: "addDealService",
 | 
					            modal: "addDealService",
 | 
				
			||||||
@@ -53,21 +57,21 @@ const DealServicesTable: FC<Props> = ({
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    const onQuantityChange = (item: DealServiceSchema, quantity: number) => {
 | 
					    const onQuantityChange = (item: DealServiceSchema, quantity: number) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        debouncedOnChange({
 | 
				
			||||||
            ...item,
 | 
					            ...item,
 | 
				
			||||||
            quantity,
 | 
					            quantity,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onPriceChange = (item: DealServiceSchema, price: number) => {
 | 
					    const onPriceChange = (item: DealServiceSchema, price: number) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        debouncedOnChange({
 | 
				
			||||||
            ...item,
 | 
					            ...item,
 | 
				
			||||||
            price,
 | 
					            price,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onLockChange = (item: DealServiceSchema, isLocked: boolean) => {
 | 
					    const onLockChange = (item: DealServiceSchema, isLocked: boolean) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        debouncedOnChange({
 | 
				
			||||||
            ...item,
 | 
					            ...item,
 | 
				
			||||||
            isFixedPrice: isLocked,
 | 
					            isFixedPrice: isLocked,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@@ -91,7 +95,7 @@ const DealServicesTable: FC<Props> = ({
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    const onEmployeesChange = (items: UserSchema[]) => {
 | 
					    const onEmployeesChange = (items: UserSchema[]) => {
 | 
				
			||||||
        if (!currentService || !onChange) return;
 | 
					        if (!currentService || !onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        debouncedOnChange({
 | 
				
			||||||
            ...currentService,
 | 
					            ...currentService,
 | 
				
			||||||
            employees: items,
 | 
					            employees: items,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,14 +15,7 @@ const useProductServicesTableColumns = (props: Props) => {
 | 
				
			|||||||
        () => data.reduce((acc, row) => acc + row.price * quantity, 0),
 | 
					        () => data.reduce((acc, row) => acc + row.price * quantity, 0),
 | 
				
			||||||
        [data, quantity]
 | 
					        [data, quantity]
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    const totalCost = useMemo(
 | 
					
 | 
				
			||||||
        () =>
 | 
					 | 
				
			||||||
            data.reduce(
 | 
					 | 
				
			||||||
                (acc, row) => acc + (row.service.cost || 0) * quantity,
 | 
					 | 
				
			||||||
                0
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        [data, quantity]
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const hideGuestColumns = ["service.cost"];
 | 
					    const hideGuestColumns = ["service.cost"];
 | 
				
			||||||
    return useMemo<MRT_ColumnDef<DealProductServiceSchema>[]>(
 | 
					    return useMemo<MRT_ColumnDef<DealProductServiceSchema>[]>(
 | 
				
			||||||
        () => [
 | 
					        () => [
 | 
				
			||||||
@@ -30,17 +23,6 @@ const useProductServicesTableColumns = (props: Props) => {
 | 
				
			|||||||
                accessorKey: "service.name",
 | 
					                accessorKey: "service.name",
 | 
				
			||||||
                header: "Услуга",
 | 
					                header: "Услуга",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                enableHiding: true,
 | 
					 | 
				
			||||||
                accessorKey: "service.cost",
 | 
					 | 
				
			||||||
                header: "Себестоимость",
 | 
					 | 
				
			||||||
                Footer: () => (
 | 
					 | 
				
			||||||
                    <>
 | 
					 | 
				
			||||||
                        Итоговая себестоимость: {totalCost.toLocaleString("ru")}
 | 
					 | 
				
			||||||
                        ₽
 | 
					 | 
				
			||||||
                    </>
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                accessorKey: "price",
 | 
					                accessorKey: "price",
 | 
				
			||||||
                header: "Цена",
 | 
					                header: "Цена",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,23 +6,14 @@ import {
 | 
				
			|||||||
    ProductSchema,
 | 
					    ProductSchema,
 | 
				
			||||||
} from "../../../../../../client";
 | 
					} from "../../../../../../client";
 | 
				
			||||||
import styles from "./ProductView.module.css";
 | 
					import styles from "./ProductView.module.css";
 | 
				
			||||||
import {
 | 
					import { ActionIcon, Box, Flex, Image, NumberInput, rem, Text, Title, Tooltip } from "@mantine/core";
 | 
				
			||||||
    ActionIcon,
 | 
					 | 
				
			||||||
    Box,
 | 
					 | 
				
			||||||
    Flex,
 | 
					 | 
				
			||||||
    Image,
 | 
					 | 
				
			||||||
    NumberInput,
 | 
					 | 
				
			||||||
    rem,
 | 
					 | 
				
			||||||
    Text,
 | 
					 | 
				
			||||||
    Title,
 | 
					 | 
				
			||||||
    Tooltip,
 | 
					 | 
				
			||||||
} from "@mantine/core";
 | 
					 | 
				
			||||||
import ProductServicesTable from "../ProductServicesTable/ProductServicesTable.tsx";
 | 
					import ProductServicesTable from "../ProductServicesTable/ProductServicesTable.tsx";
 | 
				
			||||||
import { isNil, isNumber } from "lodash";
 | 
					import { isNil, isNumber } from "lodash";
 | 
				
			||||||
import { IconBarcode, IconEdit, IconTrash } from "@tabler/icons-react";
 | 
					import { IconBarcode, IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import { ServiceType } from "../../../../../../shared/enums/ServiceType.ts";
 | 
					import { ServiceType } from "../../../../../../shared/enums/ServiceType.ts";
 | 
				
			||||||
import useDealProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
					import useDealProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
				
			||||||
 | 
					import { useDebouncedCallback } from "@mantine/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    product: DealProductSchema;
 | 
					    product: DealProductSchema;
 | 
				
			||||||
@@ -52,6 +43,10 @@ const ProductView: FC<Props> = ({
 | 
				
			|||||||
    onProductEdit,
 | 
					    onProductEdit,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const { dealState } = useDealProductAndServiceTabState();
 | 
					    const { dealState } = useDealProductAndServiceTabState();
 | 
				
			||||||
 | 
					    const debouncedOnChange = useDebouncedCallback(async (item: DealProductSchema) => {
 | 
				
			||||||
 | 
					        if (!onChange) return;
 | 
				
			||||||
 | 
					        onChange(item);
 | 
				
			||||||
 | 
					    }, 200);
 | 
				
			||||||
    const isLocked = Boolean(dealState.deal?.billRequest);
 | 
					    const isLocked = Boolean(dealState.deal?.billRequest);
 | 
				
			||||||
    const onDeleteClick = () => {
 | 
					    const onDeleteClick = () => {
 | 
				
			||||||
        if (!onDelete) return;
 | 
					        if (!onDelete) return;
 | 
				
			||||||
@@ -87,7 +82,7 @@ const ProductView: FC<Props> = ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const onQuantityChange = (quantity: number) => {
 | 
					    const onQuantityChange = (quantity: number) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        debouncedOnChange({
 | 
				
			||||||
            ...product,
 | 
					            ...product,
 | 
				
			||||||
            quantity,
 | 
					            quantity,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,5 @@
 | 
				
			|||||||
import { CRUDTableProps } from "../../../../../types/CRUDTable.tsx";
 | 
					import { CRUDTableProps } from "../../../../../types/CRUDTable.tsx";
 | 
				
			||||||
import {
 | 
					import { DealProductSchema, DealService, DealServiceSchema } from "../../../../../client";
 | 
				
			||||||
    DealProductSchema,
 | 
					 | 
				
			||||||
    DealService,
 | 
					 | 
				
			||||||
    DealServiceSchema,
 | 
					 | 
				
			||||||
} from "../../../../../client";
 | 
					 | 
				
			||||||
import { useDealPageContext } from "../../../contexts/DealPageContext.tsx";
 | 
					import { useDealPageContext } from "../../../contexts/DealPageContext.tsx";
 | 
				
			||||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -11,23 +7,29 @@ const useDealState = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
					    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
				
			||||||
    const recalculate = async () => {
 | 
					    const recalculate = async () => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return DealService.recalculateDealPrice({
 | 
					        return DealService.recalculateDealPrice({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                dealId: selectedDeal?.id || -1,
 | 
					                dealId: selectedDeal?.id || -1,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const refetch = async () => {
 | 
					    const refetchDeal = async () => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        const { ok, message } = await recalculate();
 | 
					
 | 
				
			||||||
        if (!ok) notifications.guess(ok, { message });
 | 
					 | 
				
			||||||
        return DealService.getDealById({ dealId: selectedDeal.id }).then(
 | 
					        return DealService.getDealById({ dealId: selectedDeal.id }).then(
 | 
				
			||||||
            deal => {
 | 
					            async deal => {
 | 
				
			||||||
                setSelectedDeal(deal);
 | 
					                setSelectedDeal(deal);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    const refetch = async () => {
 | 
				
			||||||
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
 | 
					        await refetchDeal();
 | 
				
			||||||
 | 
					        const { ok, message } = await recalculate();
 | 
				
			||||||
 | 
					        if (!ok) notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await refetchDeal();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        deal: selectedDeal,
 | 
					        deal: selectedDeal,
 | 
				
			||||||
        refetch,
 | 
					        refetch,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,16 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
        setSummaries(summariesRaw);
 | 
					        setSummaries(summariesRaw);
 | 
				
			||||||
    }, [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 onDelete = (dealId: number) => {
 | 
				
			||||||
        const summary = summaries.find(summary => summary.id == dealId);
 | 
					        const summary = summaries.find(summary => summary.id == dealId);
 | 
				
			||||||
        if (!summary) return;
 | 
					        if (!summary) return;
 | 
				
			||||||
@@ -94,12 +104,79 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    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) => {
 | 
					    const onDragEnd = async (result: DropResult) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (result.combine) {
 | 
				
			||||||
 | 
					            return onCombine(result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        setIsDragEnded(true);
 | 
					        setIsDragEnded(true);
 | 
				
			||||||
        // If there is no changes
 | 
					        // If there is no changes
 | 
				
			||||||
        if (!result.destination || result.destination == result.source) return;
 | 
					        if (!result.destination || result.destination == result.source) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Checking for valid dealId
 | 
					        // Checking for valid dealId
 | 
				
			||||||
 | 
					        if (result.draggableId.includes("group")) {
 | 
				
			||||||
 | 
					            return moveGroup(result);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const dealId = parseInt(result.draggableId);
 | 
					        const dealId = parseInt(result.draggableId);
 | 
				
			||||||
        if (isNaN(dealId)) return;
 | 
					        if (isNaN(dealId)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -317,7 +394,9 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                backgroundColor: "transparent",
 | 
					                backgroundColor: "transparent",
 | 
				
			||||||
                boxShadow: "none",
 | 
					                boxShadow: "none",
 | 
				
			||||||
            }}>
 | 
					            }}>
 | 
				
			||||||
            <DealPageContextProvider>
 | 
					            <DealPageContextProvider refetchDeals={async () => {
 | 
				
			||||||
 | 
					                await refetch();
 | 
				
			||||||
 | 
					            }}>
 | 
				
			||||||
                <PrefillDealContextProvider>
 | 
					                <PrefillDealContextProvider>
 | 
				
			||||||
                    <PageBlock style={{ flex: 0 }}>
 | 
					                    <PageBlock style={{ flex: 0 }}>
 | 
				
			||||||
                        <Flex
 | 
					                        <Flex
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user