feat: price by category
This commit is contained in:
		@@ -52,6 +52,8 @@ export type { CreatePayRateRequest } from './models/CreatePayRateRequest';
 | 
				
			|||||||
export type { CreatePayRateResponse } from './models/CreatePayRateResponse';
 | 
					export type { CreatePayRateResponse } from './models/CreatePayRateResponse';
 | 
				
			||||||
export type { CreatePositionRequest } from './models/CreatePositionRequest';
 | 
					export type { CreatePositionRequest } from './models/CreatePositionRequest';
 | 
				
			||||||
export type { CreatePositionResponse } from './models/CreatePositionResponse';
 | 
					export type { CreatePositionResponse } from './models/CreatePositionResponse';
 | 
				
			||||||
 | 
					export type { CreatePriceCategoryRequest } from './models/CreatePriceCategoryRequest';
 | 
				
			||||||
 | 
					export type { CreatePriceCategoryResponse } from './models/CreatePriceCategoryResponse';
 | 
				
			||||||
export type { CreateServiceKitSchema } from './models/CreateServiceKitSchema';
 | 
					export type { CreateServiceKitSchema } from './models/CreateServiceKitSchema';
 | 
				
			||||||
export type { CreateServicesKitRequest } from './models/CreateServicesKitRequest';
 | 
					export type { CreateServicesKitRequest } from './models/CreateServicesKitRequest';
 | 
				
			||||||
export type { CreateServicesKitResponse } from './models/CreateServicesKitResponse';
 | 
					export type { CreateServicesKitResponse } from './models/CreateServicesKitResponse';
 | 
				
			||||||
@@ -120,6 +122,8 @@ export type { DeletePayRateRequest } from './models/DeletePayRateRequest';
 | 
				
			|||||||
export type { DeletePayRateResponse } from './models/DeletePayRateResponse';
 | 
					export type { DeletePayRateResponse } from './models/DeletePayRateResponse';
 | 
				
			||||||
export type { DeletePositionRequest } from './models/DeletePositionRequest';
 | 
					export type { DeletePositionRequest } from './models/DeletePositionRequest';
 | 
				
			||||||
export type { DeletePositionResponse } from './models/DeletePositionResponse';
 | 
					export type { DeletePositionResponse } from './models/DeletePositionResponse';
 | 
				
			||||||
 | 
					export type { DeletePriceCategoryRequest } from './models/DeletePriceCategoryRequest';
 | 
				
			||||||
 | 
					export type { DeletePriceCategoryResponse } from './models/DeletePriceCategoryResponse';
 | 
				
			||||||
export type { DeleteShippingWarehouseRequest } from './models/DeleteShippingWarehouseRequest';
 | 
					export type { DeleteShippingWarehouseRequest } from './models/DeleteShippingWarehouseRequest';
 | 
				
			||||||
export type { DeleteShippingWarehouseResponse } from './models/DeleteShippingWarehouseResponse';
 | 
					export type { DeleteShippingWarehouseResponse } from './models/DeleteShippingWarehouseResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
					export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
				
			||||||
@@ -129,6 +133,7 @@ export type { GetAllBaseMarketplacesResponse } from './models/GetAllBaseMarketpl
 | 
				
			|||||||
export type { GetAllPayRatesResponse } from './models/GetAllPayRatesResponse';
 | 
					export type { GetAllPayRatesResponse } from './models/GetAllPayRatesResponse';
 | 
				
			||||||
export type { GetAllPayrollSchemeResponse } from './models/GetAllPayrollSchemeResponse';
 | 
					export type { GetAllPayrollSchemeResponse } from './models/GetAllPayrollSchemeResponse';
 | 
				
			||||||
export type { GetAllPositionsResponse } from './models/GetAllPositionsResponse';
 | 
					export type { GetAllPositionsResponse } from './models/GetAllPositionsResponse';
 | 
				
			||||||
 | 
					export type { GetAllPriceCategoriesResponse } from './models/GetAllPriceCategoriesResponse';
 | 
				
			||||||
export type { GetAllRolesResponse } from './models/GetAllRolesResponse';
 | 
					export type { GetAllRolesResponse } from './models/GetAllRolesResponse';
 | 
				
			||||||
export type { GetAllServicesKitsResponse } from './models/GetAllServicesKitsResponse';
 | 
					export type { GetAllServicesKitsResponse } from './models/GetAllServicesKitsResponse';
 | 
				
			||||||
export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWarehousesResponse';
 | 
					export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWarehousesResponse';
 | 
				
			||||||
@@ -174,6 +179,7 @@ export type { ProductUpdateRequest } from './models/ProductUpdateRequest';
 | 
				
			|||||||
export type { ProductUpdateResponse } from './models/ProductUpdateResponse';
 | 
					export type { ProductUpdateResponse } from './models/ProductUpdateResponse';
 | 
				
			||||||
export type { ProductUploadImageResponse } from './models/ProductUploadImageResponse';
 | 
					export type { ProductUploadImageResponse } from './models/ProductUploadImageResponse';
 | 
				
			||||||
export type { RoleSchema } from './models/RoleSchema';
 | 
					export type { RoleSchema } from './models/RoleSchema';
 | 
				
			||||||
 | 
					export type { ServiceCategoryPriceSchema } from './models/ServiceCategoryPriceSchema';
 | 
				
			||||||
export type { ServiceCategorySchema } from './models/ServiceCategorySchema';
 | 
					export type { ServiceCategorySchema } from './models/ServiceCategorySchema';
 | 
				
			||||||
export type { ServiceCreateCategoryRequest } from './models/ServiceCreateCategoryRequest';
 | 
					export type { ServiceCreateCategoryRequest } from './models/ServiceCreateCategoryRequest';
 | 
				
			||||||
export type { ServiceCreateCategoryResponse } from './models/ServiceCreateCategoryResponse';
 | 
					export type { ServiceCreateCategoryResponse } from './models/ServiceCreateCategoryResponse';
 | 
				
			||||||
@@ -183,6 +189,7 @@ export type { ServiceDeleteRequest } from './models/ServiceDeleteRequest';
 | 
				
			|||||||
export type { ServiceDeleteResponse } from './models/ServiceDeleteResponse';
 | 
					export type { ServiceDeleteResponse } from './models/ServiceDeleteResponse';
 | 
				
			||||||
export type { ServiceGetAllCategoriesResponse } from './models/ServiceGetAllCategoriesResponse';
 | 
					export type { ServiceGetAllCategoriesResponse } from './models/ServiceGetAllCategoriesResponse';
 | 
				
			||||||
export type { ServiceGetAllResponse } from './models/ServiceGetAllResponse';
 | 
					export type { ServiceGetAllResponse } from './models/ServiceGetAllResponse';
 | 
				
			||||||
 | 
					export type { ServicePriceCategorySchema } from './models/ServicePriceCategorySchema';
 | 
				
			||||||
export type { ServicePriceRangeSchema } from './models/ServicePriceRangeSchema';
 | 
					export type { ServicePriceRangeSchema } from './models/ServicePriceRangeSchema';
 | 
				
			||||||
export type { ServiceSchema } from './models/ServiceSchema';
 | 
					export type { ServiceSchema } from './models/ServiceSchema';
 | 
				
			||||||
export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
 | 
					export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
 | 
				
			||||||
@@ -196,6 +203,8 @@ export type { UpdateMarketplaceRequest } from './models/UpdateMarketplaceRequest
 | 
				
			|||||||
export type { UpdateMarketplaceResponse } from './models/UpdateMarketplaceResponse';
 | 
					export type { UpdateMarketplaceResponse } from './models/UpdateMarketplaceResponse';
 | 
				
			||||||
export type { UpdatePayRateRequest } from './models/UpdatePayRateRequest';
 | 
					export type { UpdatePayRateRequest } from './models/UpdatePayRateRequest';
 | 
				
			||||||
export type { UpdatePayRateResponse } from './models/UpdatePayRateResponse';
 | 
					export type { UpdatePayRateResponse } from './models/UpdatePayRateResponse';
 | 
				
			||||||
 | 
					export type { UpdatePriceCategoryRequest } from './models/UpdatePriceCategoryRequest';
 | 
				
			||||||
 | 
					export type { UpdatePriceCategoryResponse } from './models/UpdatePriceCategoryResponse';
 | 
				
			||||||
export type { UpdateServiceKitSchema } from './models/UpdateServiceKitSchema';
 | 
					export type { UpdateServiceKitSchema } from './models/UpdateServiceKitSchema';
 | 
				
			||||||
export type { UpdateServicesKitRequest } from './models/UpdateServicesKitRequest';
 | 
					export type { UpdateServicesKitRequest } from './models/UpdateServicesKitRequest';
 | 
				
			||||||
export type { UpdateServicesKitResponse } from './models/UpdateServicesKitResponse';
 | 
					export type { UpdateServicesKitResponse } from './models/UpdateServicesKitResponse';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								src/client/models/CreatePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/CreatePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type CreatePriceCategoryRequest = {
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/CreatePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/CreatePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type CreatePriceCategoryResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema';
 | 
					import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema';
 | 
				
			||||||
 | 
					import type { ServicePriceCategorySchema } from './ServicePriceCategorySchema';
 | 
				
			||||||
export type DealQuickCreateRequest = {
 | 
					export type DealQuickCreateRequest = {
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    clientName: string;
 | 
					    clientName: string;
 | 
				
			||||||
@@ -10,5 +11,6 @@ export type DealQuickCreateRequest = {
 | 
				
			|||||||
    acceptanceDate: string;
 | 
					    acceptanceDate: string;
 | 
				
			||||||
    shippingWarehouse: string;
 | 
					    shippingWarehouse: string;
 | 
				
			||||||
    baseMarketplace: BaseMarketplaceSchema;
 | 
					    baseMarketplace: BaseMarketplaceSchema;
 | 
				
			||||||
 | 
					    category?: (ServicePriceCategorySchema | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ import type { DealBillRequestSchema } from './DealBillRequestSchema';
 | 
				
			|||||||
import type { DealProductSchema } from './DealProductSchema';
 | 
					import type { DealProductSchema } from './DealProductSchema';
 | 
				
			||||||
import type { DealServiceSchema } from './DealServiceSchema';
 | 
					import type { DealServiceSchema } from './DealServiceSchema';
 | 
				
			||||||
import type { DealStatusHistorySchema } from './DealStatusHistorySchema';
 | 
					import type { DealStatusHistorySchema } from './DealStatusHistorySchema';
 | 
				
			||||||
 | 
					import type { ServicePriceCategorySchema } from './ServicePriceCategorySchema';
 | 
				
			||||||
import type { ShippingWarehouseSchema } from './ShippingWarehouseSchema';
 | 
					import type { ShippingWarehouseSchema } from './ShippingWarehouseSchema';
 | 
				
			||||||
export type DealSchema = {
 | 
					export type DealSchema = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
@@ -24,5 +25,6 @@ export type DealSchema = {
 | 
				
			|||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
    shippingWarehouse?: (ShippingWarehouseSchema | string | null);
 | 
					    shippingWarehouse?: (ShippingWarehouseSchema | string | null);
 | 
				
			||||||
    billRequest?: (DealBillRequestSchema | null);
 | 
					    billRequest?: (DealBillRequestSchema | null);
 | 
				
			||||||
 | 
					    category?: (ServicePriceCategorySchema | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								src/client/models/DeletePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/DeletePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DeletePriceCategoryRequest = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DeletePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DeletePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DeletePriceCategoryResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/GetAllPriceCategoriesResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/GetAllPriceCategoriesResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ServicePriceCategorySchema } from './ServicePriceCategorySchema';
 | 
				
			||||||
 | 
					export type GetAllPriceCategoriesResponse = {
 | 
				
			||||||
 | 
					    priceCategories: Array<ServicePriceCategorySchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/client/models/ServiceCategoryPriceSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/ServiceCategoryPriceSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ServicePriceCategorySchema } from './ServicePriceCategorySchema';
 | 
				
			||||||
 | 
					export type ServiceCategoryPriceSchema = {
 | 
				
			||||||
 | 
					    category: ServicePriceCategorySchema;
 | 
				
			||||||
 | 
					    price: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/ServicePriceCategorySchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ServicePriceCategorySchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type ServicePriceCategorySchema = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ServiceCategoryPriceSchema } from './ServiceCategoryPriceSchema';
 | 
				
			||||||
import type { ServiceCategorySchema } from './ServiceCategorySchema';
 | 
					import type { ServiceCategorySchema } from './ServiceCategorySchema';
 | 
				
			||||||
import type { ServicePriceRangeSchema } from './ServicePriceRangeSchema';
 | 
					import type { ServicePriceRangeSchema } from './ServicePriceRangeSchema';
 | 
				
			||||||
export type ServiceSchema = {
 | 
					export type ServiceSchema = {
 | 
				
			||||||
@@ -11,6 +12,7 @@ export type ServiceSchema = {
 | 
				
			|||||||
    price: number;
 | 
					    price: number;
 | 
				
			||||||
    serviceType: number;
 | 
					    serviceType: number;
 | 
				
			||||||
    priceRanges: Array<ServicePriceRangeSchema>;
 | 
					    priceRanges: Array<ServicePriceRangeSchema>;
 | 
				
			||||||
 | 
					    categoryPrices: Array<ServiceCategoryPriceSchema>;
 | 
				
			||||||
    cost: (number | null);
 | 
					    cost: (number | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/UpdatePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdatePriceCategoryRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdatePriceCategoryRequest = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdatePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdatePriceCategoryResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdatePriceCategoryResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,6 +305,27 @@ export class DealService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get Detailed Deal Document
 | 
				
			||||||
 | 
					     * @returns any Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getDealDocumentDetailed({
 | 
				
			||||||
 | 
					        dealId,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        dealId: number,
 | 
				
			||||||
 | 
					    }): CancelablePromise<any> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/deal/detailedDocument/{deal_id}',
 | 
				
			||||||
 | 
					            path: {
 | 
				
			||||||
 | 
					                'deal_id': dealId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Services Add
 | 
					     * Services Add
 | 
				
			||||||
     * @returns DealAddServicesResponse Successful Response
 | 
					     * @returns DealAddServicesResponse Successful Response
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,13 @@
 | 
				
			|||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
import type { BaseEnumListSchema } from '../models/BaseEnumListSchema';
 | 
					import type { BaseEnumListSchema } from '../models/BaseEnumListSchema';
 | 
				
			||||||
 | 
					import type { CreatePriceCategoryRequest } from '../models/CreatePriceCategoryRequest';
 | 
				
			||||||
 | 
					import type { CreatePriceCategoryResponse } from '../models/CreatePriceCategoryResponse';
 | 
				
			||||||
import type { CreateServicesKitRequest } from '../models/CreateServicesKitRequest';
 | 
					import type { CreateServicesKitRequest } from '../models/CreateServicesKitRequest';
 | 
				
			||||||
import type { CreateServicesKitResponse } from '../models/CreateServicesKitResponse';
 | 
					import type { CreateServicesKitResponse } from '../models/CreateServicesKitResponse';
 | 
				
			||||||
 | 
					import type { DeletePriceCategoryRequest } from '../models/DeletePriceCategoryRequest';
 | 
				
			||||||
 | 
					import type { DeletePriceCategoryResponse } from '../models/DeletePriceCategoryResponse';
 | 
				
			||||||
 | 
					import type { GetAllPriceCategoriesResponse } from '../models/GetAllPriceCategoriesResponse';
 | 
				
			||||||
import type { GetAllServicesKitsResponse } from '../models/GetAllServicesKitsResponse';
 | 
					import type { GetAllServicesKitsResponse } from '../models/GetAllServicesKitsResponse';
 | 
				
			||||||
import type { ServiceCreateCategoryRequest } from '../models/ServiceCreateCategoryRequest';
 | 
					import type { ServiceCreateCategoryRequest } from '../models/ServiceCreateCategoryRequest';
 | 
				
			||||||
import type { ServiceCreateCategoryResponse } from '../models/ServiceCreateCategoryResponse';
 | 
					import type { ServiceCreateCategoryResponse } from '../models/ServiceCreateCategoryResponse';
 | 
				
			||||||
@@ -16,6 +21,8 @@ import type { ServiceGetAllCategoriesResponse } from '../models/ServiceGetAllCat
 | 
				
			|||||||
import type { ServiceGetAllResponse } from '../models/ServiceGetAllResponse';
 | 
					import type { ServiceGetAllResponse } from '../models/ServiceGetAllResponse';
 | 
				
			||||||
import type { ServiceUpdateRequest } from '../models/ServiceUpdateRequest';
 | 
					import type { ServiceUpdateRequest } from '../models/ServiceUpdateRequest';
 | 
				
			||||||
import type { ServiceUpdateResponse } from '../models/ServiceUpdateResponse';
 | 
					import type { ServiceUpdateResponse } from '../models/ServiceUpdateResponse';
 | 
				
			||||||
 | 
					import type { UpdatePriceCategoryRequest } from '../models/UpdatePriceCategoryRequest';
 | 
				
			||||||
 | 
					import type { UpdatePriceCategoryResponse } from '../models/UpdatePriceCategoryResponse';
 | 
				
			||||||
import type { UpdateServicesKitRequest } from '../models/UpdateServicesKitRequest';
 | 
					import type { UpdateServicesKitRequest } from '../models/UpdateServicesKitRequest';
 | 
				
			||||||
import type { UpdateServicesKitResponse } from '../models/UpdateServicesKitResponse';
 | 
					import type { UpdateServicesKitResponse } from '../models/UpdateServicesKitResponse';
 | 
				
			||||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
@@ -186,4 +193,75 @@ export class ServiceService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All Price Categories
 | 
				
			||||||
 | 
					     * @returns GetAllPriceCategoriesResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllPriceCategories(): CancelablePromise<GetAllPriceCategoriesResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/service/price-categories/get-all',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create Price Category
 | 
				
			||||||
 | 
					     * @returns CreatePriceCategoryResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static createPriceCategory({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: CreatePriceCategoryRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<CreatePriceCategoryResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/service/price-categories/create',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Price Category
 | 
				
			||||||
 | 
					     * @returns UpdatePriceCategoryResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updatePriceCategory({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdatePriceCategoryRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdatePriceCategoryResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/service/price-categories/update',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete Price Category
 | 
				
			||||||
 | 
					     * @returns DeletePriceCategoryResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static deletePriceCategory({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: DeletePriceCategoryRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<DeletePriceCategoryResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/service/price-categories/delete',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,13 @@ import {Button, rem, Textarea, TextInput} from "@mantine/core";
 | 
				
			|||||||
import { QuickDeal } from "../../../types/QuickDeal.ts";
 | 
					import { QuickDeal } from "../../../types/QuickDeal.ts";
 | 
				
			||||||
import { FC } from "react";
 | 
					import { FC } from "react";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import styles from './CreateDealForm.module.css';
 | 
					import styles from "./CreateDealForm.module.css";
 | 
				
			||||||
import ClientAutocomplete from "../../Selects/ClientAutocomplete/ClientAutocomplete.tsx";
 | 
					import ClientAutocomplete from "../../Selects/ClientAutocomplete/ClientAutocomplete.tsx";
 | 
				
			||||||
import { DateTimePicker } from "@mantine/dates";
 | 
					import { DateTimePicker } from "@mantine/dates";
 | 
				
			||||||
import ShippingWarehouseAutocomplete
 | 
					import ShippingWarehouseAutocomplete
 | 
				
			||||||
    from "../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
					    from "../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
				
			||||||
import BaseMarketplaceSelect from "../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
					import BaseMarketplaceSelect from "../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
				
			||||||
 | 
					import ServicePriceCategorySelect from "../../Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    onSubmit: (quickDeal: QuickDeal) => void
 | 
					    onSubmit: (quickDeal: QuickDeal) => void
 | 
				
			||||||
@@ -16,84 +17,92 @@ type Props = {
 | 
				
			|||||||
const CreateDealFrom: FC<Props> = ({ onSubmit, onCancel }) => {
 | 
					const CreateDealFrom: FC<Props> = ({ onSubmit, onCancel }) => {
 | 
				
			||||||
    const form = useForm<QuickDeal>({
 | 
					    const form = useForm<QuickDeal>({
 | 
				
			||||||
        initialValues: {
 | 
					        initialValues: {
 | 
				
			||||||
            name: '',
 | 
					            name: "",
 | 
				
			||||||
            clientName: '',
 | 
					            clientName: "",
 | 
				
			||||||
            clientAddress: '',
 | 
					            clientAddress: "",
 | 
				
			||||||
            comment: '',
 | 
					            comment: "",
 | 
				
			||||||
            acceptanceDate: new Date(),
 | 
					            acceptanceDate: new Date(),
 | 
				
			||||||
            shippingWarehouse: '',
 | 
					            shippingWarehouse: "",
 | 
				
			||||||
            baseMarketplace: {
 | 
					            baseMarketplace: {
 | 
				
			||||||
                key: "",
 | 
					                key: "",
 | 
				
			||||||
                iconUrl: "",
 | 
					                iconUrl: "",
 | 
				
			||||||
                name: ""
 | 
					                name: "",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <form
 | 
					        <form
 | 
				
			||||||
            style={{width: '100%'}}
 | 
					            style={{ width: "100%" }}
 | 
				
			||||||
            onSubmit={form.onSubmit((values) => onSubmit(values))}
 | 
					            onSubmit={form.onSubmit((values) => onSubmit(values))}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <div style={{
 | 
					            <div style={{
 | 
				
			||||||
                display: 'flex',
 | 
					                display: "flex",
 | 
				
			||||||
                flexDirection: 'column',
 | 
					                flexDirection: "column",
 | 
				
			||||||
                width: '100%',
 | 
					                width: "100%",
 | 
				
			||||||
                gap: rem(10),
 | 
					                gap: rem(10),
 | 
				
			||||||
                padding: rem(10)
 | 
					                padding: rem(10),
 | 
				
			||||||
            }}>
 | 
					            }}>
 | 
				
			||||||
                <div className={styles['inputs']}>
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
                    <TextInput
 | 
					                    <TextInput
 | 
				
			||||||
                        placeholder={'Название сделки'}
 | 
					                        placeholder={"Название сделки"}
 | 
				
			||||||
                        {...form.getInputProps('name')}
 | 
					                        {...form.getInputProps("name")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className={styles['inputs']}>
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
                    <ClientAutocomplete
 | 
					                    <ClientAutocomplete
 | 
				
			||||||
                        nameRestProps={form.getInputProps('clientName')}
 | 
					                        nameRestProps={form.getInputProps("clientName")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className={styles['inputs']}>
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
                    <BaseMarketplaceSelect
 | 
					                    <BaseMarketplaceSelect
 | 
				
			||||||
                        rightSection={<></>}
 | 
					                        rightSection={<></>}
 | 
				
			||||||
                        placeholder={"Базовый маркетплейс"}
 | 
					                        placeholder={"Базовый маркетплейс"}
 | 
				
			||||||
                        {...form.getInputProps("baseMarketplace")}
 | 
					                        {...form.getInputProps("baseMarketplace")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <ShippingWarehouseAutocomplete
 | 
					                    <ShippingWarehouseAutocomplete
 | 
				
			||||||
                        {...form.getInputProps('shippingWarehouse')}
 | 
					                        {...form.getInputProps("shippingWarehouse")}
 | 
				
			||||||
                        placeholder={'Склад отгрузки'}
 | 
					                        placeholder={"Склад отгрузки"}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
 | 
					                    <ServicePriceCategorySelect
 | 
				
			||||||
 | 
					                        rightSection={<></>}
 | 
				
			||||||
 | 
					                        placeholder={"Выберите категорию"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("category")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <div className={styles['inputs']}>
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
                    <Textarea
 | 
					                    <Textarea
 | 
				
			||||||
                        autosize
 | 
					                        autosize
 | 
				
			||||||
                        placeholder={'Комментарий'}
 | 
					                        placeholder={"Комментарий"}
 | 
				
			||||||
                        minRows={2}
 | 
					                        minRows={2}
 | 
				
			||||||
                        maxRows={4}
 | 
					                        maxRows={4}
 | 
				
			||||||
                        {...form.getInputProps('comment')}
 | 
					                        {...form.getInputProps("comment")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className={styles['inputs']}>
 | 
					                <div className={styles["inputs"]}>
 | 
				
			||||||
                    <DateTimePicker
 | 
					                    <DateTimePicker
 | 
				
			||||||
                        placeholder={'Дата приемки'}
 | 
					                        placeholder={"Дата приемки"}
 | 
				
			||||||
                        {...form.getInputProps('acceptanceDate')}
 | 
					                        {...form.getInputProps("acceptanceDate")}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <div className={styles['buttons']}>
 | 
					                <div className={styles["buttons"]}>
 | 
				
			||||||
                    <Button
 | 
					                    <Button
 | 
				
			||||||
                        type={'submit'}
 | 
					                        type={"submit"}
 | 
				
			||||||
                    >Добавить</Button>
 | 
					                    >Добавить</Button>
 | 
				
			||||||
                    <Button
 | 
					                    <Button
 | 
				
			||||||
                        variant={'outline'}
 | 
					                        variant={"outline"}
 | 
				
			||||||
                        onClick={() => onCancel()}
 | 
					                        onClick={() => onCancel()}
 | 
				
			||||||
                    >Отменить</Button>
 | 
					                    >Отменить</Button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default CreateDealFrom;
 | 
					export default CreateDealFrom;
 | 
				
			||||||
@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import ObjectSelect, { ObjectSelectProps } from "../../ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
 | 
					import { ServicePriceCategorySchema } from "../../../client";
 | 
				
			||||||
 | 
					import useServicePriceCategoriesList from "../../../pages/ServicesPage/hooks/useServicePriceCategoriesList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<ObjectSelectProps<ServicePriceCategorySchema>, "data">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ServicePriceCategorySelect = (props: Props) => {
 | 
				
			||||||
 | 
					    const { objects } = useServicePriceCategoriesList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ObjectSelect
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					            data={objects}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServicePriceCategorySelect;
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
import { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx";
 | 
					import { ObjectSelectProps } from "../ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
import {ServiceSchema} from "../../client";
 | 
					import { ServicePriceCategorySchema, ServiceSchema } from "../../client";
 | 
				
			||||||
import { Flex, FlexProps, NumberInput, NumberInputProps, rem } from "@mantine/core";
 | 
					import { Flex, FlexProps, NumberInput, NumberInputProps, rem } from "@mantine/core";
 | 
				
			||||||
import { FC, useEffect, useRef, useState } from "react";
 | 
					import { FC, useEffect, useRef, useState } from "react";
 | 
				
			||||||
import ServiceSelectNew from "../Selects/ServiceSelectNew/ServiceSelectNew.tsx";
 | 
					import ServiceSelectNew from "../Selects/ServiceSelectNew/ServiceSelectNew.tsx";
 | 
				
			||||||
import { ServiceType } from "../../shared/enums/ServiceType.ts";
 | 
					import { ServiceType } from "../../shared/enums/ServiceType.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ServiceProps = Omit<ObjectSelectProps<ServiceSchema>, 'data'>;
 | 
					type ServiceProps = Omit<ObjectSelectProps<ServiceSchema>, "data">;
 | 
				
			||||||
type PriceProps = NumberInputProps;
 | 
					type PriceProps = NumberInputProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -15,6 +15,7 @@ type Props = {
 | 
				
			|||||||
    containerProps: FlexProps,
 | 
					    containerProps: FlexProps,
 | 
				
			||||||
    filterType?: ServiceType,
 | 
					    filterType?: ServiceType,
 | 
				
			||||||
    lockOnEdit?: boolean
 | 
					    lockOnEdit?: boolean
 | 
				
			||||||
 | 
					    category?: ServicePriceCategorySchema
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
const ServiceWithPriceInput: FC<Props> = ({
 | 
					const ServiceWithPriceInput: FC<Props> = ({
 | 
				
			||||||
                                              serviceProps,
 | 
					                                              serviceProps,
 | 
				
			||||||
@@ -22,10 +23,11 @@ const ServiceWithPriceInput: FC<Props> = ({
 | 
				
			|||||||
                                              quantity,
 | 
					                                              quantity,
 | 
				
			||||||
                                              containerProps,
 | 
					                                              containerProps,
 | 
				
			||||||
                                              filterType = ServiceType.PRODUCT_SERVICE,
 | 
					                                              filterType = ServiceType.PRODUCT_SERVICE,
 | 
				
			||||||
                                              lockOnEdit = true
 | 
					                                              lockOnEdit = true,
 | 
				
			||||||
 | 
					                                              category,
 | 
				
			||||||
                                          }) => {
 | 
					                                          }) => {
 | 
				
			||||||
    const [price, setPrice] = useState<number | undefined>(
 | 
					    const [price, setPrice] = useState<number | undefined>(
 | 
				
			||||||
        typeof priceProps.value === 'number' ? priceProps.value : undefined);
 | 
					        typeof priceProps.value === "number" ? priceProps.value : undefined);
 | 
				
			||||||
    const [service, setService] = useState<ServiceSchema | undefined>(serviceProps.value);
 | 
					    const [service, setService] = useState<ServiceSchema | undefined>(serviceProps.value);
 | 
				
			||||||
    const isFirstRender = useRef(true);
 | 
					    const isFirstRender = useRef(true);
 | 
				
			||||||
    const setPriceBasedOnQuantity = (): boolean => {
 | 
					    const setPriceBasedOnQuantity = (): boolean => {
 | 
				
			||||||
@@ -35,29 +37,40 @@ const ServiceWithPriceInput: FC<Props> = ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        setPrice(range.price);
 | 
					        setPrice(range.price);
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					    const setPriceBasedOnCategory = () => {
 | 
				
			||||||
 | 
					        if (!category || !service) return false;
 | 
				
			||||||
 | 
					        const categoryPrice = service.categoryPrices.find(categoryPrice => categoryPrice.category.id === category.id);
 | 
				
			||||||
 | 
					        if (!categoryPrice) return false;
 | 
				
			||||||
 | 
					        setPrice(categoryPrice.price);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    const setPriceBasedOnService = () => {
 | 
					    const setPriceBasedOnService = () => {
 | 
				
			||||||
        if (!service) return;
 | 
					        if (!service) return;
 | 
				
			||||||
 | 
					        // if category is set, we should not set price based on service
 | 
				
			||||||
 | 
					        if (setPriceBasedOnCategory()) return;
 | 
				
			||||||
        if (setPriceBasedOnQuantity()) return;
 | 
					        if (setPriceBasedOnQuantity()) return;
 | 
				
			||||||
        setPrice(service.price);
 | 
					        setPrice(service.price);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onServiceManualChange = (service: ServiceSchema) => {
 | 
					    const onServiceManualChange = (service: ServiceSchema) => {
 | 
				
			||||||
        setService(service);
 | 
					        setService(service);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onPriceManualChange = (value: number | string) => {
 | 
					    const onPriceManualChange = (value: number | string) => {
 | 
				
			||||||
        if (typeof value !== 'number') return;
 | 
					        if (typeof value !== "number") return;
 | 
				
			||||||
        setPrice(value);
 | 
					        setPrice(value);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (isFirstRender.current && lockOnEdit) return;
 | 
					        if (isFirstRender.current && lockOnEdit) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // we need to set price based on quantity only if category is not set, because category has higher priority
 | 
				
			||||||
 | 
					        if (category) return;
 | 
				
			||||||
        setPriceBasedOnQuantity();
 | 
					        setPriceBasedOnQuantity();
 | 
				
			||||||
    }, [quantity]);
 | 
					    }, [quantity]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (isFirstRender.current && lockOnEdit) return;
 | 
					        if (isFirstRender.current && lockOnEdit) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!priceProps.onChange || typeof price === 'undefined') return;
 | 
					        if (!priceProps.onChange || typeof price === "undefined") return;
 | 
				
			||||||
        priceProps.onChange(price);
 | 
					        priceProps.onChange(price);
 | 
				
			||||||
    }, [price]);
 | 
					    }, [price]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -97,7 +110,7 @@ const ServiceWithPriceInput: FC<Props> = ({
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </Flex>
 | 
					        </Flex>
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ServiceWithPriceInput;
 | 
					export default ServiceWithPriceInput;
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/main.tsx
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								src/main.tsx
									
									
									
									
									
								
							@@ -1,19 +1,19 @@
 | 
				
			|||||||
import ReactDOM from 'react-dom/client'
 | 
					import ReactDOM from "react-dom/client";
 | 
				
			||||||
import {RouterProvider, createRouter} from '@tanstack/react-router'
 | 
					import { RouterProvider, createRouter } 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";
 | 
				
			||||||
import { Provider } from "react-redux";
 | 
					import { Provider } from "react-redux";
 | 
				
			||||||
import { store } from "./redux/store.ts";
 | 
					import { store } from "./redux/store.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '@mantine/core/styles.css';
 | 
					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 'dayjs/locale/ru';
 | 
					import "dayjs/locale/ru";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import './main.css';
 | 
					import "./main.css";
 | 
				
			||||||
import { Notifications } from "@mantine/notifications";
 | 
					import { Notifications } from "@mantine/notifications";
 | 
				
			||||||
import { ModalsProvider } from "@mantine/modals";
 | 
					import { ModalsProvider } from "@mantine/modals";
 | 
				
			||||||
import { OpenAPI } from "./client";
 | 
					import { OpenAPI } from "./client";
 | 
				
			||||||
@@ -22,14 +22,14 @@ import {modals} from "./modals/modals.ts";
 | 
				
			|||||||
import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
					import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuring router
 | 
					// Configuring router
 | 
				
			||||||
const router = createRouter({routeTree})
 | 
					const router = createRouter({ routeTree });
 | 
				
			||||||
declare module '@tanstack/react-router' {
 | 
					declare module "@tanstack/react-router" {
 | 
				
			||||||
    interface Register {
 | 
					    interface Register {
 | 
				
			||||||
        router: typeof router
 | 
					        router: typeof router;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
declare module '@mantine/modals' {
 | 
					declare module "@mantine/modals" {
 | 
				
			||||||
    export interface MantineModalsOverride {
 | 
					    export interface MantineModalsOverride {
 | 
				
			||||||
        modals: typeof modals;
 | 
					        modals: typeof modals;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -39,14 +39,14 @@ declare module '@mantine/modals' {
 | 
				
			|||||||
const queryClient = new QueryClient();
 | 
					const queryClient = new QueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuring OpenAPI
 | 
					// Configuring OpenAPI
 | 
				
			||||||
OpenAPI.BASE = import.meta.env.VITE_API_URL
 | 
					OpenAPI.BASE = import.meta.env.VITE_API_URL;
 | 
				
			||||||
OpenAPI.TOKEN = JSON.parse(localStorage.getItem('authState') || "{}")['accessToken'];
 | 
					OpenAPI.TOKEN = JSON.parse(localStorage.getItem("authState") || "{}")["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 modals={modals}>
 | 
					                <ModalsProvider labels={{ confirm: "Да", cancel: "Нет" }} modals={modals}>
 | 
				
			||||||
                    <DatesProvider settings={{locale: 'ru'}}>
 | 
					                    <DatesProvider settings={{ locale: "ru" }}>
 | 
				
			||||||
                        <TasksProvider>
 | 
					                        <TasksProvider>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <RouterProvider router={router} />
 | 
					                            <RouterProvider router={router} />
 | 
				
			||||||
@@ -57,5 +57,5 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
 | 
				
			|||||||
                </ModalsProvider>
 | 
					                </ModalsProvider>
 | 
				
			||||||
            </MantineProvider>
 | 
					            </MantineProvider>
 | 
				
			||||||
        </QueryClientProvider>
 | 
					        </QueryClientProvider>
 | 
				
			||||||
    </Provider>
 | 
					    </Provider>,
 | 
				
			||||||
)
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ import ServicesKitSelectModal from "./ServicesKitSelectModal/ServicesKitSelectMo
 | 
				
			|||||||
import SelectDealProductsModal from "../pages/LeadsPage/modals/SelectDealProductsModal.tsx";
 | 
					import SelectDealProductsModal from "../pages/LeadsPage/modals/SelectDealProductsModal.tsx";
 | 
				
			||||||
import ShippingWarehouseForm from "../pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx";
 | 
					import ShippingWarehouseForm from "../pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx";
 | 
				
			||||||
import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx";
 | 
					import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx";
 | 
				
			||||||
 | 
					import ServicePriceCategoryForm from "../pages/ServicesPage/modals/ServicePriceCategoryForm.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const modals = {
 | 
					export const modals = {
 | 
				
			||||||
    enterDeadline: EnterDeadlineModal,
 | 
					    enterDeadline: EnterDeadlineModal,
 | 
				
			||||||
@@ -44,5 +45,6 @@ export const modals = {
 | 
				
			|||||||
    servicesKitSelectModal: ServicesKitSelectModal,
 | 
					    servicesKitSelectModal: ServicesKitSelectModal,
 | 
				
			||||||
    selectDealProductsModal: SelectDealProductsModal,
 | 
					    selectDealProductsModal: SelectDealProductsModal,
 | 
				
			||||||
    shippingWarehouseForm: ShippingWarehouseForm,
 | 
					    shippingWarehouseForm: ShippingWarehouseForm,
 | 
				
			||||||
    marketplaceFormModal: MarketplaceFormModal
 | 
					    marketplaceFormModal: MarketplaceFormModal,
 | 
				
			||||||
}
 | 
					    servicePriceCategoryForm: ServicePriceCategoryForm,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,8 +24,8 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
        DealService.updateDealService({
 | 
					        DealService.updateDealService({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                dealId: selectedDeal.id,
 | 
					                dealId: selectedDeal.id,
 | 
				
			||||||
                service
 | 
					                service,
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }).then(async ({ ok, message }) => {
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!ok) {
 | 
					            if (!ok) {
 | 
				
			||||||
@@ -33,9 +33,9 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                .then(setSelectedDeal)
 | 
					                .then(setSelectedDeal);
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onServiceDelete = (service: DealServiceSchema) => {
 | 
					    const onServiceDelete = (service: DealServiceSchema) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        modals.openConfirmModal({
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
@@ -56,23 +56,23 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
                DealService.deleteDealService({
 | 
					                DealService.deleteDealService({
 | 
				
			||||||
                    requestBody: {
 | 
					                    requestBody: {
 | 
				
			||||||
                        dealId: selectedDeal.id,
 | 
					                        dealId: selectedDeal.id,
 | 
				
			||||||
                        serviceId: service.service.id
 | 
					                        serviceId: service.service.id,
 | 
				
			||||||
                    }
 | 
					                    },
 | 
				
			||||||
                }).then(async ({ ok, message }) => {
 | 
					                }).then(async ({ ok, message }) => {
 | 
				
			||||||
                    if (!ok) {
 | 
					                    if (!ok) {
 | 
				
			||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        return;
 | 
					                        return;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                        .then(setSelectedDeal)
 | 
					                        .then(setSelectedDeal);
 | 
				
			||||||
                })
 | 
					                });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                cancel: "Отмена",
 | 
					                cancel: "Отмена",
 | 
				
			||||||
                confirm: "Удалить"
 | 
					                confirm: "Удалить",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onServiceCreate = (service: DealServiceSchema) => {
 | 
					    const onServiceCreate = (service: DealServiceSchema) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        DealService.addDealService({
 | 
					        DealService.addDealService({
 | 
				
			||||||
@@ -80,17 +80,17 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
                dealId: selectedDeal.id,
 | 
					                dealId: selectedDeal.id,
 | 
				
			||||||
                serviceId: service.service.id,
 | 
					                serviceId: service.service.id,
 | 
				
			||||||
                quantity: service.quantity,
 | 
					                quantity: service.quantity,
 | 
				
			||||||
                price: service.price
 | 
					                price: service.price,
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }).then(async ({ ok, message }) => {
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
            if (!ok) {
 | 
					            if (!ok) {
 | 
				
			||||||
                notifications.guess(ok, { message });
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                .then(setSelectedDeal)
 | 
					                .then(setSelectedDeal);
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onsServiceMultipleDelete = (items: DealServiceSchema[]) => {
 | 
					    const onsServiceMultipleDelete = (items: DealServiceSchema[]) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        modals.openConfirmModal({
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
@@ -106,23 +106,23 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
                DealService.deleteMultipleDealServices({
 | 
					                DealService.deleteMultipleDealServices({
 | 
				
			||||||
                    requestBody: {
 | 
					                    requestBody: {
 | 
				
			||||||
                        dealId: selectedDeal.id,
 | 
					                        dealId: selectedDeal.id,
 | 
				
			||||||
                        serviceIds: items.map(item => item.service.id)
 | 
					                        serviceIds: items.map(item => item.service.id),
 | 
				
			||||||
                    }
 | 
					                    },
 | 
				
			||||||
                }).then(async ({ ok, message }) => {
 | 
					                }).then(async ({ ok, message }) => {
 | 
				
			||||||
                    if (!ok) {
 | 
					                    if (!ok) {
 | 
				
			||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        return;
 | 
					                        return;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                        .then(setSelectedDeal)
 | 
					                        .then(setSelectedDeal);
 | 
				
			||||||
                })
 | 
					                });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                cancel: "Отмена",
 | 
					                cancel: "Отмена",
 | 
				
			||||||
                confirm: "Удалить"
 | 
					                confirm: "Удалить",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        onServiceUpdate,
 | 
					        onServiceUpdate,
 | 
				
			||||||
@@ -130,9 +130,9 @@ const useDealServicesTableState = () => {
 | 
				
			|||||||
        onServiceCreate,
 | 
					        onServiceCreate,
 | 
				
			||||||
        onsServiceMultipleDelete,
 | 
					        onsServiceMultipleDelete,
 | 
				
			||||||
        tableRef,
 | 
					        tableRef,
 | 
				
			||||||
        services: selectedDeal?.services || []
 | 
					        services: selectedDeal?.services || [],
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
const DealEditDrawerServicesTable = () => {
 | 
					const DealEditDrawerServicesTable = () => {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        services,
 | 
					        services,
 | 
				
			||||||
@@ -140,7 +140,7 @@ const DealEditDrawerServicesTable = () => {
 | 
				
			|||||||
        onServiceCreate,
 | 
					        onServiceCreate,
 | 
				
			||||||
        onServiceUpdate,
 | 
					        onServiceUpdate,
 | 
				
			||||||
        onServiceDelete,
 | 
					        onServiceDelete,
 | 
				
			||||||
        onsServiceMultipleDelete
 | 
					        onsServiceMultipleDelete,
 | 
				
			||||||
    } = useDealServicesTableState();
 | 
					    } = useDealServicesTableState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (<DealServicesTable
 | 
					    return (<DealServicesTable
 | 
				
			||||||
@@ -150,8 +150,8 @@ const DealEditDrawerServicesTable = () => {
 | 
				
			|||||||
        onDelete={onServiceDelete}
 | 
					        onDelete={onServiceDelete}
 | 
				
			||||||
        onCreate={onServiceCreate}
 | 
					        onCreate={onServiceCreate}
 | 
				
			||||||
        onMultipleDelete={onsServiceMultipleDelete}
 | 
					        onMultipleDelete={onsServiceMultipleDelete}
 | 
				
			||||||
    />)
 | 
					    />);
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useDealProductTableState = () => {
 | 
					const useDealProductTableState = () => {
 | 
				
			||||||
    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
					    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
				
			||||||
@@ -161,15 +161,15 @@ const useDealProductTableState = () => {
 | 
				
			|||||||
        DealService.updateDealProduct({
 | 
					        DealService.updateDealProduct({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                dealId: selectedDeal.id,
 | 
					                dealId: selectedDeal.id,
 | 
				
			||||||
                product: product
 | 
					                product: product,
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }).then(async ({ ok, message }) => {
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
            notifications.guess(ok, { message });
 | 
					            notifications.guess(ok, { message });
 | 
				
			||||||
            if (!ok) return;
 | 
					            if (!ok) return;
 | 
				
			||||||
            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                .then(setSelectedDeal)
 | 
					                .then(setSelectedDeal);
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onProductDelete = (product: DealProductSchema) => {
 | 
					    const onProductDelete = (product: DealProductSchema) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        modals.openConfirmModal({
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
@@ -190,39 +190,39 @@ const useDealProductTableState = () => {
 | 
				
			|||||||
                DealService.deleteDealProduct({
 | 
					                DealService.deleteDealProduct({
 | 
				
			||||||
                    requestBody: {
 | 
					                    requestBody: {
 | 
				
			||||||
                        dealId: selectedDeal.id,
 | 
					                        dealId: selectedDeal.id,
 | 
				
			||||||
                        productId: product.product.id
 | 
					                        productId: product.product.id,
 | 
				
			||||||
                    }
 | 
					                    },
 | 
				
			||||||
                }).then(async ({ ok, message }) => {
 | 
					                }).then(async ({ ok, message }) => {
 | 
				
			||||||
                    if (!ok) {
 | 
					                    if (!ok) {
 | 
				
			||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        return;
 | 
					                        return;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                        .then(setSelectedDeal)
 | 
					                        .then(setSelectedDeal);
 | 
				
			||||||
                })
 | 
					                });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                cancel: "Отмена",
 | 
					                cancel: "Отмена",
 | 
				
			||||||
                confirm: "Удалить"
 | 
					                confirm: "Удалить",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onProductCreate = (product: DealProductSchema) => {
 | 
					    const onProductCreate = (product: DealProductSchema) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        DealService.addDealProduct({
 | 
					        DealService.addDealProduct({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                dealId: selectedDeal.id,
 | 
					                dealId: selectedDeal.id,
 | 
				
			||||||
                product: product
 | 
					                product: product,
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        }).then(async ({ ok, message }) => {
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
            if (!ok) {
 | 
					            if (!ok) {
 | 
				
			||||||
                notifications.guess(ok, { message });
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					            await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                .then(setSelectedDeal)
 | 
					                .then(setSelectedDeal);
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onProductMultipleDelete = (items: DealProductSchema[]) => {
 | 
					    const onProductMultipleDelete = (items: DealProductSchema[]) => {
 | 
				
			||||||
        if (!selectedDeal) return;
 | 
					        if (!selectedDeal) return;
 | 
				
			||||||
        modals.openConfirmModal({
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
@@ -238,32 +238,32 @@ const useDealProductTableState = () => {
 | 
				
			|||||||
                DealService.deleteMultipleDealProducts({
 | 
					                DealService.deleteMultipleDealProducts({
 | 
				
			||||||
                    requestBody: {
 | 
					                    requestBody: {
 | 
				
			||||||
                        dealId: selectedDeal.id,
 | 
					                        dealId: selectedDeal.id,
 | 
				
			||||||
                        productIds: items.map(item => item.product.id)
 | 
					                        productIds: items.map(item => item.product.id),
 | 
				
			||||||
                    }
 | 
					                    },
 | 
				
			||||||
                }).then(async ({ ok, message }) => {
 | 
					                }).then(async ({ ok, message }) => {
 | 
				
			||||||
                    if (!ok) {
 | 
					                    if (!ok) {
 | 
				
			||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        return;
 | 
					                        return;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
					                    await DealService.getDealById({ dealId: selectedDeal.id })
 | 
				
			||||||
                        .then(setSelectedDeal)
 | 
					                        .then(setSelectedDeal);
 | 
				
			||||||
                })
 | 
					                });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                cancel: "Отмена",
 | 
					                cancel: "Отмена",
 | 
				
			||||||
                confirm: "Удалить"
 | 
					                confirm: "Удалить",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        clientId: selectedDeal?.clientId || -1,
 | 
					        clientId: selectedDeal?.clientId || -1,
 | 
				
			||||||
        products: selectedDeal?.products || [],
 | 
					        products: selectedDeal?.products || [],
 | 
				
			||||||
        onProductUpdate,
 | 
					        onProductUpdate,
 | 
				
			||||||
        onProductDelete,
 | 
					        onProductDelete,
 | 
				
			||||||
        onProductCreate,
 | 
					        onProductCreate,
 | 
				
			||||||
        onProductMultipleDelete
 | 
					        onProductMultipleDelete,
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
const DealEditDrawerProductsTable = () => {
 | 
					const DealEditDrawerProductsTable = () => {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        products,
 | 
					        products,
 | 
				
			||||||
@@ -283,38 +283,38 @@ const DealEditDrawerProductsTable = () => {
 | 
				
			|||||||
            onCreate={onProductCreate}
 | 
					            onCreate={onProductCreate}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useDealStatusChangeState = () => {
 | 
					const useDealStatusChangeState = () => {
 | 
				
			||||||
    const { selectedDeal } = useDealPageContext();
 | 
					    const { selectedDeal } = useDealPageContext();
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        statusHistory: selectedDeal?.statusHistory || []
 | 
					        statusHistory: selectedDeal?.statusHistory || [],
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
const DealEditDrawerStatusChangeTable = () => {
 | 
					const DealEditDrawerStatusChangeTable = () => {
 | 
				
			||||||
    const { statusHistory } = useDealStatusChangeState();
 | 
					    const { statusHistory } = useDealStatusChangeState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <DealStatusChangeTable
 | 
					        <DealStatusChangeTable
 | 
				
			||||||
            items={statusHistory}
 | 
					            items={statusHistory}
 | 
				
			||||||
        />)
 | 
					        />);
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useDealEditDrawerState = () => {
 | 
					const useDealEditDrawerState = () => {
 | 
				
			||||||
    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
					    const { selectedDeal, setSelectedDeal } = useDealPageContext();
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        isVisible: selectedDeal !== undefined,
 | 
					        isVisible: selectedDeal !== undefined,
 | 
				
			||||||
        onClose: () => setSelectedDeal(undefined)
 | 
					        onClose: () => setSelectedDeal(undefined),
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DealEditDrawer: FC = () => {
 | 
					const DealEditDrawer: FC = () => {
 | 
				
			||||||
    const { isVisible, onClose } = useDealEditDrawerState();
 | 
					    const { isVisible, onClose } = useDealEditDrawerState();
 | 
				
			||||||
    const queryClient = useQueryClient();
 | 
					    const queryClient = useQueryClient();
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (isVisible) return;
 | 
					        if (isVisible) return;
 | 
				
			||||||
        queryClient.invalidateQueries({queryKey: ["getDealSummaries"]})
 | 
					        queryClient.invalidateQueries({ queryKey: ["getDealSummaries"] });
 | 
				
			||||||
    }, [isVisible]);
 | 
					    }, [isVisible]);
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Drawer
 | 
					        <Drawer
 | 
				
			||||||
@@ -324,16 +324,23 @@ const DealEditDrawer: FC = () => {
 | 
				
			|||||||
            removeScrollProps={{ allowPinchZoom: true }}
 | 
					            removeScrollProps={{ allowPinchZoom: true }}
 | 
				
			||||||
            withCloseButton={false}
 | 
					            withCloseButton={false}
 | 
				
			||||||
            opened={isVisible}
 | 
					            opened={isVisible}
 | 
				
			||||||
            styles={{body: {height: '100%'}}}
 | 
					            styles={{
 | 
				
			||||||
 | 
					                body: {
 | 
				
			||||||
 | 
					                    height: "100%",
 | 
				
			||||||
 | 
					                    display: "flex",
 | 
				
			||||||
 | 
					                    flexDirection: "column", gap: rem(10),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <Tabs
 | 
					            <Tabs
 | 
				
			||||||
                defaultValue={"general"}
 | 
					                defaultValue={"general"}
 | 
				
			||||||
                h={'100%'}
 | 
					                flex={1}
 | 
				
			||||||
                variant={"outline"}
 | 
					                variant={"outline"}
 | 
				
			||||||
                orientation={"vertical"}
 | 
					                orientation={"vertical"}
 | 
				
			||||||
                keepMounted={false}
 | 
					                keepMounted={false}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <Tabs.List
 | 
					                <Tabs.List
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                    <Tabs.Tab value={"general"} leftSection={<IconSettings />}>
 | 
					                    <Tabs.Tab value={"general"} leftSection={<IconSettings />}>
 | 
				
			||||||
@@ -398,6 +405,6 @@ const DealEditDrawer: FC = () => {
 | 
				
			|||||||
            </Tabs>
 | 
					            </Tabs>
 | 
				
			||||||
        </Drawer>
 | 
					        </Drawer>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default DealEditDrawer;
 | 
					export default DealEditDrawer;
 | 
				
			||||||
@@ -103,7 +103,7 @@ const Content: FC<Props> = ({ deal }) => {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
 | 
					        <form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
 | 
				
			||||||
            <Flex direction={"column"}>
 | 
					            <Flex direction={"column"} justify={"space-between"} h={"100%"}>
 | 
				
			||||||
                <Fieldset legend={`Общие параметры [ID: ${deal.id}]`}>
 | 
					                <Fieldset legend={`Общие параметры [ID: ${deal.id}]`}>
 | 
				
			||||||
                    <Flex direction={"column"} gap={rem(10)}>
 | 
					                    <Flex direction={"column"} gap={rem(10)}>
 | 
				
			||||||
                        <TextInput
 | 
					                        <TextInput
 | 
				
			||||||
@@ -122,6 +122,15 @@ const Content: FC<Props> = ({ deal }) => {
 | 
				
			|||||||
                            placeholder={"Текущий статус"}
 | 
					                            placeholder={"Текущий статус"}
 | 
				
			||||||
                            label={"Текущий статус"}
 | 
					                            label={"Текущий статус"}
 | 
				
			||||||
                            value={DealStatusDictionary[deal.currentStatus as DealStatus]} />
 | 
					                            value={DealStatusDictionary[deal.currentStatus as DealStatus]} />
 | 
				
			||||||
 | 
					                        {deal.category && (
 | 
				
			||||||
 | 
					                            <TextInput
 | 
				
			||||||
 | 
					                                disabled
 | 
				
			||||||
 | 
					                                placeholder={"Категория"}
 | 
				
			||||||
 | 
					                                label={"Категория"}
 | 
				
			||||||
 | 
					                                value={deal.category.name}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
                        <Textarea
 | 
					                        <Textarea
 | 
				
			||||||
                            label={"Коментарий к сделке"}
 | 
					                            label={"Коментарий к сделке"}
 | 
				
			||||||
                            placeholder={"Введите коментарий к сделке"}
 | 
					                            placeholder={"Введите коментарий к сделке"}
 | 
				
			||||||
@@ -141,34 +150,6 @@ const Content: FC<Props> = ({ deal }) => {
 | 
				
			|||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    </Flex>
 | 
					                    </Flex>
 | 
				
			||||||
                </Fieldset>
 | 
					                </Fieldset>
 | 
				
			||||||
                <Fieldset legend={"Клиент"}>
 | 
					 | 
				
			||||||
                    <TextInput
 | 
					 | 
				
			||||||
                        disabled
 | 
					 | 
				
			||||||
                        placeholder={"Название"}
 | 
					 | 
				
			||||||
                        label={"Название"}
 | 
					 | 
				
			||||||
                        value={deal.client.name}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <TextInput
 | 
					 | 
				
			||||||
                        placeholder={"Введите телефон"}
 | 
					 | 
				
			||||||
                        label={"Телефон клиента"}
 | 
					 | 
				
			||||||
                        {...form.getInputProps("client.details.phoneNumber")}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <TextInput
 | 
					 | 
				
			||||||
                        placeholder={"Введите email"}
 | 
					 | 
				
			||||||
                        label={"Email"}
 | 
					 | 
				
			||||||
                        {...form.getInputProps("client.details.email")}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <TextInput
 | 
					 | 
				
			||||||
                        placeholder={"Введите телеграм"}
 | 
					 | 
				
			||||||
                        label={"Телеграм"}
 | 
					 | 
				
			||||||
                        {...form.getInputProps("client.details.telegram")}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                    <TextInput
 | 
					 | 
				
			||||||
                        placeholder={"Введите ИНН"}
 | 
					 | 
				
			||||||
                        label={"ИНН"}
 | 
					 | 
				
			||||||
                        {...form.getInputProps("client.details.inn")}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                </Fieldset>
 | 
					 | 
				
			||||||
                <Flex mt={"md"} gap={rem(10)} align={"center"} justify={"flex-end"}>
 | 
					                <Flex mt={"md"} gap={rem(10)} align={"center"} justify={"flex-end"}>
 | 
				
			||||||
                    <Flex align={"center"} gap={rem(10)} justify={"center"}>
 | 
					                    <Flex align={"center"} gap={rem(10)} justify={"center"}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -199,10 +180,7 @@ const Content: FC<Props> = ({ deal }) => {
 | 
				
			|||||||
                                    :
 | 
					                                    :
 | 
				
			||||||
                                    <ButtonCopyControlled
 | 
					                                    <ButtonCopyControlled
 | 
				
			||||||
                                        onCopyClick={() => {
 | 
					                                        onCopyClick={() => {
 | 
				
			||||||
                                            // get current datetime for filename, replaced dots with _
 | 
					 | 
				
			||||||
                                            const date = getCurrentDateTimeForFilename();
 | 
					                                            const date = getCurrentDateTimeForFilename();
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                                            FileSaver.saveAs(`${import.meta.env.VITE_API_URL}/deal/document/${deal.id}`,
 | 
					                                            FileSaver.saveAs(`${import.meta.env.VITE_API_URL}/deal/document/${deal.id}`,
 | 
				
			||||||
                                                `bill_${deal.id}_${date}.pdf`);
 | 
					                                                `bill_${deal.id}_${date}.pdf`);
 | 
				
			||||||
                                        }}
 | 
					                                        }}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,9 @@ import {ContextModalProps} from "@mantine/modals";
 | 
				
			|||||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import { DealProductSchema, DealProductServiceSchema } from "../../../client";
 | 
					import { DealProductSchema, DealProductServiceSchema } from "../../../client";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import {Fieldset, NumberInput} from "@mantine/core";
 | 
					import { NumberInput } from "@mantine/core";
 | 
				
			||||||
import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
 | 
					import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
 | 
				
			||||||
import DealProductServiceTable from "../components/DealProductsTable/DealProductServiceTable.tsx";
 | 
					 | 
				
			||||||
import { omit } from "lodash";
 | 
					import { omit } from "lodash";
 | 
				
			||||||
import {BaseFormInputProps} from "../../../types/utils.ts";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    clientId: number;
 | 
					    clientId: number;
 | 
				
			||||||
@@ -65,13 +63,13 @@ const AddDealProductModal = ({
 | 
				
			|||||||
                        min={1}
 | 
					                        min={1}
 | 
				
			||||||
                        {...form.getInputProps('quantity')}
 | 
					                        {...form.getInputProps('quantity')}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <Fieldset legend={'Услуги'}>
 | 
					                    {/*<Fieldset legend={'Услуги'}>*/}
 | 
				
			||||||
                        <DealProductServiceTable
 | 
					                    {/*    <DealProductServiceTable*/}
 | 
				
			||||||
                            quantity={form.values.quantity || 1}
 | 
					                    {/*        quantity={form.values.quantity || 1}*/}
 | 
				
			||||||
                            {...form.getInputProps('services') as
 | 
					                    {/*        {...form.getInputProps('services') as*/}
 | 
				
			||||||
                                BaseFormInputProps<DealProductServiceSchema[]>}
 | 
					                    {/*            BaseFormInputProps<DealProductServiceSchema[]>}*/}
 | 
				
			||||||
                        />
 | 
					                    {/*    />*/}
 | 
				
			||||||
                    </Fieldset>
 | 
					                    {/*</Fieldset>*/}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                </>
 | 
					                </>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import {ContextModalProps} from "@mantine/modals";
 | 
					import {ContextModalProps} from "@mantine/modals";
 | 
				
			||||||
import BaseFormModal, {CreateEditFormProps} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, {CreateEditFormProps} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import {DealServiceSchema} from "../../../client";
 | 
					import { DealServiceSchema, ServicePriceCategorySchema } from "../../../client";
 | 
				
			||||||
import {useForm} from "@mantine/form";
 | 
					import {useForm} from "@mantine/form";
 | 
				
			||||||
import {ComboboxItem, ComboboxItemGroup, NumberInput, OptionsFilter} from "@mantine/core";
 | 
					import {ComboboxItem, ComboboxItemGroup, NumberInput, OptionsFilter} from "@mantine/core";
 | 
				
			||||||
import ServiceWithPriceInput from "../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
					import ServiceWithPriceInput from "../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
				
			||||||
@@ -10,6 +10,7 @@ import {RootState} from "../../../redux/store.ts";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    serviceIds?: number[];
 | 
					    serviceIds?: number[];
 | 
				
			||||||
 | 
					    category?: ServicePriceCategorySchema;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type Props = CreateEditFormProps<Partial<DealServiceSchema>> & RestProps;
 | 
					type Props = CreateEditFormProps<Partial<DealServiceSchema>> & RestProps;
 | 
				
			||||||
const AddDealServiceModal = ({
 | 
					const AddDealServiceModal = ({
 | 
				
			||||||
@@ -18,7 +19,7 @@ const AddDealServiceModal = ({
 | 
				
			|||||||
                                 innerProps
 | 
					                                 innerProps
 | 
				
			||||||
                             }: ContextModalProps<Props>) => {
 | 
					                             }: ContextModalProps<Props>) => {
 | 
				
			||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
 | 
					    console.log(innerProps.category)
 | 
				
			||||||
    const isEditing = 'element' in innerProps;
 | 
					    const isEditing = 'element' in innerProps;
 | 
				
			||||||
    const form = useForm<Partial<DealServiceSchema>>({
 | 
					    const form = useForm<Partial<DealServiceSchema>>({
 | 
				
			||||||
        initialValues: isEditing ? innerProps.element : {
 | 
					        initialValues: isEditing ? innerProps.element : {
 | 
				
			||||||
@@ -54,6 +55,7 @@ const AddDealServiceModal = ({
 | 
				
			|||||||
            <BaseFormModal.Body>
 | 
					            <BaseFormModal.Body>
 | 
				
			||||||
                <>
 | 
					                <>
 | 
				
			||||||
                    <ServiceWithPriceInput
 | 
					                    <ServiceWithPriceInput
 | 
				
			||||||
 | 
					                        category={innerProps.category}
 | 
				
			||||||
                        serviceProps={{
 | 
					                        serviceProps={{
 | 
				
			||||||
                            ...form.getInputProps('service'),
 | 
					                            ...form.getInputProps('service'),
 | 
				
			||||||
                            label: "Услуга",
 | 
					                            label: "Услуга",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import {DealProductServiceSchema, ServiceSchema} from "../../../client";
 | 
					import { DealProductServiceSchema, ServicePriceCategorySchema, ServiceSchema } from "../../../client";
 | 
				
			||||||
import { ContextModalProps } from "@mantine/modals";
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
import { useForm, UseFormReturnType } from "@mantine/form";
 | 
					import { useForm, UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
import { isNil, isNumber } from "lodash";
 | 
					import { isNil, isNumber } from "lodash";
 | 
				
			||||||
@@ -12,31 +12,32 @@ import {RootState} from "../../../redux/store.ts";
 | 
				
			|||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    quantity: number;
 | 
					    quantity: number;
 | 
				
			||||||
    serviceIds: number[];
 | 
					    serviceIds: number[];
 | 
				
			||||||
 | 
					    category?: ServicePriceCategorySchema;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type Props = CreateEditFormProps<DealProductServiceSchema> & RestProps;
 | 
					type Props = CreateEditFormProps<DealProductServiceSchema> & RestProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProductServiceFormModal = ({
 | 
					const ProductServiceFormModal = ({
 | 
				
			||||||
                                     context,
 | 
					                                     context,
 | 
				
			||||||
                                     id, innerProps
 | 
					                                     id, innerProps,
 | 
				
			||||||
                                 }: ContextModalProps<Props>) => {
 | 
					                                 }: ContextModalProps<Props>) => {
 | 
				
			||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isEditing = 'onChange' in innerProps;
 | 
					    const isEditing = "onChange" in innerProps;
 | 
				
			||||||
    const initialValues: Partial<DealProductServiceSchema> = isEditing ? innerProps.element : {
 | 
					    const initialValues: Partial<DealProductServiceSchema> = isEditing ? innerProps.element : {
 | 
				
			||||||
        service: undefined,
 | 
					        service: undefined,
 | 
				
			||||||
        price: undefined,
 | 
					        price: undefined,
 | 
				
			||||||
        employees: []
 | 
					        employees: [],
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const form = useForm<Partial<DealProductServiceSchema>>({
 | 
					    const form = useForm<Partial<DealProductServiceSchema>>({
 | 
				
			||||||
        initialValues,
 | 
					        initialValues,
 | 
				
			||||||
        validate: {
 | 
					        validate: {
 | 
				
			||||||
            service: (service?: ServiceSchema) => isNil(service) || service.id < 0 ? 'Укажите услугу' : null,
 | 
					            service: (service?: ServiceSchema) => isNil(service) || service.id < 0 ? "Укажите услугу" : null,
 | 
				
			||||||
            price: (price?: number) => !isNumber(price) || price < 0 ? 'Укажите цену' : null
 | 
					            price: (price?: number) => !isNumber(price) || price < 0 ? "Укажите цену" : null,
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    })
 | 
					    });
 | 
				
			||||||
    const onClose = () => {
 | 
					    const onClose = () => {
 | 
				
			||||||
        context.closeContextModal(id);
 | 
					        context.closeContextModal(id);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <BaseFormModal
 | 
					        <BaseFormModal
 | 
				
			||||||
            {...innerProps}
 | 
					            {...innerProps}
 | 
				
			||||||
@@ -49,25 +50,26 @@ const ProductServiceFormModal = ({
 | 
				
			|||||||
                    <Flex w={"100%"}>
 | 
					                    <Flex w={"100%"}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <ServiceWithPriceInput
 | 
					                        <ServiceWithPriceInput
 | 
				
			||||||
 | 
					                            category={innerProps.category}
 | 
				
			||||||
                            serviceProps={{
 | 
					                            serviceProps={{
 | 
				
			||||||
                                ...form.getInputProps('service'),
 | 
					                                ...form.getInputProps("service"),
 | 
				
			||||||
                                label: "Услуга",
 | 
					                                label: "Услуга",
 | 
				
			||||||
                                placeholder: "Выберите услугу",
 | 
					                                placeholder: "Выберите услугу",
 | 
				
			||||||
                                disabled: isEditing,
 | 
					                                disabled: isEditing,
 | 
				
			||||||
                                filterBy: (item) => !innerProps.serviceIds.includes(item.id) || isEditing,
 | 
					                                filterBy: (item) => !innerProps.serviceIds.includes(item.id) || isEditing,
 | 
				
			||||||
                                style: {width: "100%"}
 | 
					                                style: { width: "100%" },
 | 
				
			||||||
                            }}
 | 
					                            }}
 | 
				
			||||||
                            priceProps={{
 | 
					                            priceProps={{
 | 
				
			||||||
                                ...form.getInputProps('price'),
 | 
					                                ...form.getInputProps("price"),
 | 
				
			||||||
                                label: "Цена",
 | 
					                                label: "Цена",
 | 
				
			||||||
                                placeholder: "Введите цену",
 | 
					                                placeholder: "Введите цену",
 | 
				
			||||||
                                style: { width: "100%" },
 | 
					                                style: { width: "100%" },
 | 
				
			||||||
                                disabled: authState.isGuest
 | 
					                                disabled: authState.isGuest,
 | 
				
			||||||
                            }}
 | 
					                            }}
 | 
				
			||||||
                            filterType={ServiceType.PRODUCT_SERVICE}
 | 
					                            filterType={ServiceType.PRODUCT_SERVICE}
 | 
				
			||||||
                            containerProps={{
 | 
					                            containerProps={{
 | 
				
			||||||
                                direction: "column",
 | 
					                                direction: "column",
 | 
				
			||||||
                                style: {width: "100%"}
 | 
					                                style: { width: "100%" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            }}
 | 
					                            }}
 | 
				
			||||||
                            lockOnEdit={isEditing}
 | 
					                            lockOnEdit={isEditing}
 | 
				
			||||||
@@ -79,6 +81,6 @@ const ProductServiceFormModal = ({
 | 
				
			|||||||
            </BaseFormModal.Body>
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
        </BaseFormModal>
 | 
					        </BaseFormModal>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
export default ProductServiceFormModal;
 | 
					export default ProductServiceFormModal;
 | 
				
			||||||
@@ -27,68 +27,70 @@ const DealServicesTable: FC<Props> = ({items, onDelete, onCreate, onChange, onKi
 | 
				
			|||||||
    const onDeleteClick = (item: DealServiceSchema) => {
 | 
					    const onDeleteClick = (item: DealServiceSchema) => {
 | 
				
			||||||
        if (!onDelete) return;
 | 
					        if (!onDelete) return;
 | 
				
			||||||
        onDelete(item);
 | 
					        onDelete(item);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    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",
 | 
				
			||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onCreate: onCreate,
 | 
					                onCreate: onCreate,
 | 
				
			||||||
                serviceIds
 | 
					                serviceIds,
 | 
				
			||||||
 | 
					                category: dealState.deal?.category || undefined,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            withCloseButton: false
 | 
					            withCloseButton: false,
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onQuantityChange = (item: DealServiceSchema, quantity: number) => {
 | 
					    const onQuantityChange = (item: DealServiceSchema, quantity: number) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        onChange({
 | 
				
			||||||
            ...item,
 | 
					            ...item,
 | 
				
			||||||
            quantity
 | 
					            quantity,
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onPriceChange = (item: DealServiceSchema, price: number) => {
 | 
					    const onPriceChange = (item: DealServiceSchema, price: number) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        onChange({
 | 
				
			||||||
            ...item,
 | 
					            ...item,
 | 
				
			||||||
            price
 | 
					            price,
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onEmployeeClick = (item: DealServiceSchema) => {
 | 
					    const onEmployeeClick = (item: DealServiceSchema) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        setCurrentService(item);
 | 
					        setCurrentService(item);
 | 
				
			||||||
        setEmployeesModalVisible(true);
 | 
					        setEmployeesModalVisible(true);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onEmployeeModalClose = () => {
 | 
					    const onEmployeeModalClose = () => {
 | 
				
			||||||
        setEmployeesModalVisible(false);
 | 
					        setEmployeesModalVisible(false);
 | 
				
			||||||
        setCurrentService(undefined);
 | 
					        setCurrentService(undefined);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const getCurrentEmployees = (): UserSchema[] => {
 | 
					    const getCurrentEmployees = (): UserSchema[] => {
 | 
				
			||||||
        if (!currentService) return [];
 | 
					        if (!currentService) return [];
 | 
				
			||||||
        const item = items.find(i => i.service.id === currentService.service.id)
 | 
					        const item = items.find(i => i.service.id === currentService.service.id);
 | 
				
			||||||
        if (!item) return [];
 | 
					        if (!item) return [];
 | 
				
			||||||
        return item.employees;
 | 
					        return item.employees;
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onEmployeesChange = (items: UserSchema[]) => {
 | 
					    const onEmployeesChange = (items: UserSchema[]) => {
 | 
				
			||||||
        if (!currentService || !onChange) return;
 | 
					        if (!currentService || !onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        onChange({
 | 
				
			||||||
            ...currentService,
 | 
					            ...currentService,
 | 
				
			||||||
            employees: items
 | 
					            employees: items,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onAddKitClick = () => {
 | 
					    const onAddKitClick = () => {
 | 
				
			||||||
        if (!onKitAdd) return;
 | 
					        if (!onKitAdd) return;
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: "servicesKitSelectModal",
 | 
					            modal: "servicesKitSelectModal",
 | 
				
			||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onSelect: onKitAdd,
 | 
					                onSelect: onKitAdd,
 | 
				
			||||||
                serviceType: ServiceType.DEAL_SERVICE
 | 
					                serviceType: ServiceType.DEAL_SERVICE,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            withCloseButton: false
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <Flex
 | 
					            <Flex
 | 
				
			||||||
@@ -196,6 +198,6 @@ const DealServicesTable: FC<Props> = ({items, onDelete, onCreate, onChange, onKi
 | 
				
			|||||||
            </Modal>
 | 
					            </Modal>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
export default DealServicesTable;
 | 
					export default DealServicesTable;
 | 
				
			||||||
@@ -26,7 +26,7 @@ const ProductServicesTable: FC<Props> = ({
 | 
				
			|||||||
                                             onDelete,
 | 
					                                             onDelete,
 | 
				
			||||||
                                             onChange,
 | 
					                                             onChange,
 | 
				
			||||||
                                             onCopyServices,
 | 
					                                             onCopyServices,
 | 
				
			||||||
                                             onKitAdd
 | 
					                                             onKitAdd,
 | 
				
			||||||
                                         }) => {
 | 
					                                         }) => {
 | 
				
			||||||
    const { dealState } = useDealProductAndServiceTabState();
 | 
					    const { dealState } = useDealProductAndServiceTabState();
 | 
				
			||||||
    const isLocked = Boolean(dealState.deal?.billRequest);
 | 
					    const isLocked = Boolean(dealState.deal?.billRequest);
 | 
				
			||||||
@@ -45,11 +45,12 @@ const ProductServicesTable: FC<Props> = ({
 | 
				
			|||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onCreate: onCreate,
 | 
					                onCreate: onCreate,
 | 
				
			||||||
                serviceIds,
 | 
					                serviceIds,
 | 
				
			||||||
                quantity
 | 
					                quantity,
 | 
				
			||||||
 | 
					                category: dealState.deal?.category || undefined,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            withCloseButton: false
 | 
					            withCloseButton: false,
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onChangeClick = (item: DealProductServiceSchema) => {
 | 
					    const onChangeClick = (item: DealProductServiceSchema) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
@@ -59,33 +60,35 @@ const ProductServicesTable: FC<Props> = ({
 | 
				
			|||||||
                element: item,
 | 
					                element: item,
 | 
				
			||||||
                onChange,
 | 
					                onChange,
 | 
				
			||||||
                serviceIds,
 | 
					                serviceIds,
 | 
				
			||||||
                quantity
 | 
					                quantity,
 | 
				
			||||||
 | 
					                category: dealState.deal?.category || undefined,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            withCloseButton: false
 | 
					            withCloseButton: false,
 | 
				
			||||||
        })
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onEmployeeClick = (item: DealProductServiceSchema) => {
 | 
					    const onEmployeeClick = (item: DealProductServiceSchema) => {
 | 
				
			||||||
        if (!onChange) return;
 | 
					        if (!onChange) return;
 | 
				
			||||||
        setCurrentService(item);
 | 
					        setCurrentService(item);
 | 
				
			||||||
        setEmployeesModalVisible(true);
 | 
					        setEmployeesModalVisible(true);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onEmployeeModalClose = () => {
 | 
					    const onEmployeeModalClose = () => {
 | 
				
			||||||
        setEmployeesModalVisible(false);
 | 
					        setEmployeesModalVisible(false);
 | 
				
			||||||
        setCurrentService(undefined);
 | 
					        setCurrentService(undefined);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const getCurrentEmployees = (): UserSchema[] => {
 | 
					    const getCurrentEmployees = (): UserSchema[] => {
 | 
				
			||||||
        if (!currentService) return [];
 | 
					        if (!currentService) return [];
 | 
				
			||||||
        const item = items.find(i => i.service.id === currentService.service.id)
 | 
					        const item = items.find(i => i.service.id === currentService.service.id);
 | 
				
			||||||
        if (!item) return [];
 | 
					        if (!item) return [];
 | 
				
			||||||
        return item.employees;
 | 
					        return item.employees;
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onEmployeesChange = (items: UserSchema[]) => {
 | 
					    const onEmployeesChange = (items: UserSchema[]) => {
 | 
				
			||||||
        if (!currentService || !onChange) return;
 | 
					        if (!currentService || !onChange) return;
 | 
				
			||||||
        onChange({
 | 
					        onChange({
 | 
				
			||||||
            ...currentService,
 | 
					            ...currentService,
 | 
				
			||||||
            employees: items
 | 
					            employees: items,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <Flex
 | 
					            <Flex
 | 
				
			||||||
@@ -177,6 +180,6 @@ const ProductServicesTable: FC<Props> = ({
 | 
				
			|||||||
            </Modal>
 | 
					            </Modal>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
export default ProductServicesTable;
 | 
					export default ProductServicesTable;
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import { FC, useEffect, useState } from "react";
 | 
					import { FC, useEffect, useState } from "react";
 | 
				
			||||||
import styles from './LeadsPage.module.css';
 | 
					import styles from "./LeadsPage.module.css";
 | 
				
			||||||
import Board from "../../../components/Dnd/Board/Board.tsx";
 | 
					import Board from "../../../components/Dnd/Board/Board.tsx";
 | 
				
			||||||
import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd";
 | 
					import { DragDropContext, Droppable, DropResult } from "@hello-pangea/dnd";
 | 
				
			||||||
import { useDealSummaries } from "../hooks/useDealSummaries.tsx";
 | 
					import { useDealSummaries } from "../hooks/useDealSummaries.tsx";
 | 
				
			||||||
@@ -51,14 +51,14 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        if (!ok) return;
 | 
					                        if (!ok) return;
 | 
				
			||||||
                        await refetch();
 | 
					                        await refetch();
 | 
				
			||||||
                    })
 | 
					                    });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                confirm: "Удалить",
 | 
					                confirm: "Удалить",
 | 
				
			||||||
                cancel: "Отмена"
 | 
					                cancel: "Отмена",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onSuccess = (dealId: number) => {
 | 
					    const onSuccess = (dealId: number) => {
 | 
				
			||||||
        const summary = summaries.find(summary => summary.id == dealId);
 | 
					        const summary = summaries.find(summary => summary.id == dealId);
 | 
				
			||||||
        if (!summary) return;
 | 
					        if (!summary) return;
 | 
				
			||||||
@@ -74,14 +74,14 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        notifications.guess(ok, { message });
 | 
					                        notifications.guess(ok, { message });
 | 
				
			||||||
                        if (!ok) return;
 | 
					                        if (!ok) return;
 | 
				
			||||||
                        await refetch();
 | 
					                        await refetch();
 | 
				
			||||||
                    })
 | 
					                    });
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            labels: {
 | 
					            labels: {
 | 
				
			||||||
                confirm: "Завершить",
 | 
					                confirm: "Завершить",
 | 
				
			||||||
                cancel: "Отмена"
 | 
					                cancel: "Отмена",
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const onDragEnd = async (result: DropResult) => {
 | 
					    const onDragEnd = async (result: DropResult) => {
 | 
				
			||||||
        setIsDragEnded(true);
 | 
					        setIsDragEnded(true);
 | 
				
			||||||
        // If there is no changes
 | 
					        // If there is no changes
 | 
				
			||||||
@@ -97,11 +97,11 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Checking if it is custom actions
 | 
					        // Checking if it is custom actions
 | 
				
			||||||
        const droppableId = result.destination.droppableId;
 | 
					        const droppableId = result.destination.droppableId;
 | 
				
			||||||
        if (droppableId === 'DELETE') {
 | 
					        if (droppableId === "DELETE") {
 | 
				
			||||||
            onDelete(dealId);
 | 
					            onDelete(dealId);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (droppableId === 'SUCCESS') {
 | 
					        if (droppableId === "SUCCESS") {
 | 
				
			||||||
            onSuccess(dealId);
 | 
					            onSuccess(dealId);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -109,8 +109,8 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
        const request: Partial<DealSummaryReorderRequest> = {
 | 
					        const request: Partial<DealSummaryReorderRequest> = {
 | 
				
			||||||
            dealId: dealId,
 | 
					            dealId: dealId,
 | 
				
			||||||
            index: result.destination.index,
 | 
					            index: result.destination.index,
 | 
				
			||||||
            status: status
 | 
					            status: status,
 | 
				
			||||||
        }
 | 
					        };
 | 
				
			||||||
        if (status == summary.status) {
 | 
					        if (status == summary.status) {
 | 
				
			||||||
            DealService.reorderDealSummaries({ requestBody: request as DealSummaryReorderRequest })
 | 
					            DealService.reorderDealSummaries({ requestBody: request as DealSummaryReorderRequest })
 | 
				
			||||||
                .then(async response => {
 | 
					                .then(async response => {
 | 
				
			||||||
@@ -120,7 +120,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: 'enterDeadline',
 | 
					            modal: "enterDeadline",
 | 
				
			||||||
            title: "Необходимо указать дедлайн",
 | 
					            title: "Необходимо указать дедлайн",
 | 
				
			||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onSubmit: (event) => DealService.reorderDealSummaries({ requestBody: event })
 | 
					                onSubmit: (event) => DealService.reorderDealSummaries({ requestBody: event })
 | 
				
			||||||
@@ -128,11 +128,11 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        setSummaries(response.summaries);
 | 
					                        setSummaries(response.summaries);
 | 
				
			||||||
                        await refetch();
 | 
					                        await refetch();
 | 
				
			||||||
                    }),
 | 
					                    }),
 | 
				
			||||||
                request: request
 | 
					                request: request,
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const getTableBody = () => {
 | 
					    const getTableBody = () => {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <motion.div
 | 
					            <motion.div
 | 
				
			||||||
@@ -145,8 +145,8 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                <DealsTable items={data} />
 | 
					                <DealsTable items={data} />
 | 
				
			||||||
            </motion.div>
 | 
					            </motion.div>
 | 
				
			||||||
        )
 | 
					        );
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const getBoardBody = () => {
 | 
					    const getBoardBody = () => {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,7 +154,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                style={{
 | 
					                style={{
 | 
				
			||||||
                    display: "flex",
 | 
					                    display: "flex",
 | 
				
			||||||
                    height: "100%",
 | 
					                    height: "100%",
 | 
				
			||||||
                    flex: 1
 | 
					                    flex: 1,
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
                key={displayMode}
 | 
					                key={displayMode}
 | 
				
			||||||
                initial={{ opacity: 0 }}
 | 
					                initial={{ opacity: 0 }}
 | 
				
			||||||
@@ -173,21 +173,21 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        style={{ flex: 1 }}
 | 
					                        style={{ flex: 1 }}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <div className={styles['boards']}>
 | 
					                        <div className={styles["boards"]}>
 | 
				
			||||||
                            <Board
 | 
					                            <Board
 | 
				
			||||||
                                withCreateButton
 | 
					                                withCreateButton
 | 
				
			||||||
                                summaries={summaries
 | 
					                                summaries={summaries
 | 
				
			||||||
                                    .filter(summary => summary.status == DealStatus.AWAITING_ACCEPTANCE)}
 | 
					                                    .filter(summary => summary.status == DealStatus.AWAITING_ACCEPTANCE)}
 | 
				
			||||||
                                title={"Ожидает приемки"}
 | 
					                                title={"Ожидает приемки"}
 | 
				
			||||||
                                droppableId={"AWAITING_ACCEPTANCE"}
 | 
					                                droppableId={"AWAITING_ACCEPTANCE"}
 | 
				
			||||||
                                color={'#4A90E2'}
 | 
					                                color={"#4A90E2"}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Board
 | 
					                            <Board
 | 
				
			||||||
                                summaries={summaries
 | 
					                                summaries={summaries
 | 
				
			||||||
                                    .filter(summary => summary.status == DealStatus.PACKAGING)}
 | 
					                                    .filter(summary => summary.status == DealStatus.PACKAGING)}
 | 
				
			||||||
                                title={"Упаковка"}
 | 
					                                title={"Упаковка"}
 | 
				
			||||||
                                droppableId={"PACKAGING"}
 | 
					                                droppableId={"PACKAGING"}
 | 
				
			||||||
                                color={'#F5A623'}
 | 
					                                color={"#F5A623"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Board
 | 
					                            <Board
 | 
				
			||||||
@@ -195,7 +195,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                                    .filter(summary => summary.status == DealStatus.AWAITING_SHIPMENT)}
 | 
					                                    .filter(summary => summary.status == DealStatus.AWAITING_SHIPMENT)}
 | 
				
			||||||
                                title={"Ожидает отгрузки"}
 | 
					                                title={"Ожидает отгрузки"}
 | 
				
			||||||
                                droppableId={"AWAITING_SHIPMENT"}
 | 
					                                droppableId={"AWAITING_SHIPMENT"}
 | 
				
			||||||
                                color={'#7ED321'}
 | 
					                                color={"#7ED321"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Board
 | 
					                            <Board
 | 
				
			||||||
@@ -203,7 +203,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                                    .filter(summary => summary.status == DealStatus.AWAITING_PAYMENT)}
 | 
					                                    .filter(summary => summary.status == DealStatus.AWAITING_PAYMENT)}
 | 
				
			||||||
                                title={"Ожидает оплаты"}
 | 
					                                title={"Ожидает оплаты"}
 | 
				
			||||||
                                droppableId={"AWAITING_PAYMENT"}
 | 
					                                droppableId={"AWAITING_PAYMENT"}
 | 
				
			||||||
                                color={'#D0021B'}
 | 
					                                color={"#D0021B"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <Board
 | 
					                            <Board
 | 
				
			||||||
@@ -211,15 +211,15 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                                    .filter(summary => summary.status == DealStatus.COMPLETED)}
 | 
					                                    .filter(summary => summary.status == DealStatus.COMPLETED)}
 | 
				
			||||||
                                title={"Завершена"}
 | 
					                                title={"Завершена"}
 | 
				
			||||||
                                droppableId={"COMPLETED"}
 | 
					                                droppableId={"COMPLETED"}
 | 
				
			||||||
                                color={'#417505'}
 | 
					                                color={"#417505"}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <Flex justify={"space-between"} gap={rem(10)}>
 | 
					                        <Flex justify={"space-between"} gap={rem(10)}>
 | 
				
			||||||
                            <div
 | 
					                            <div
 | 
				
			||||||
                                className={
 | 
					                                className={
 | 
				
			||||||
                                    classNames(
 | 
					                                    classNames(
 | 
				
			||||||
                                        styles['delete'],
 | 
					                                        styles["delete"],
 | 
				
			||||||
                                        isDragEnded && styles['delete-hidden']
 | 
					                                        isDragEnded && styles["delete-hidden"],
 | 
				
			||||||
                                    )
 | 
					                                    )
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
@@ -250,8 +250,8 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                            <div
 | 
					                            <div
 | 
				
			||||||
                                className={
 | 
					                                className={
 | 
				
			||||||
                                    classNames(
 | 
					                                    classNames(
 | 
				
			||||||
                                        styles['delete'],
 | 
					                                        styles["delete"],
 | 
				
			||||||
                                        isDragEnded && styles['delete-hidden']
 | 
					                                        isDragEnded && styles["delete-hidden"],
 | 
				
			||||||
                                    )
 | 
					                                    )
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
@@ -284,11 +284,11 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                </DragDropContext>
 | 
					                </DragDropContext>
 | 
				
			||||||
            </motion.div>
 | 
					            </motion.div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        )
 | 
					        );
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    const getBody = () => {
 | 
					    const getBody = () => {
 | 
				
			||||||
        return displayMode === DisplayMode.TABLE ? getTableBody() : getBoardBody();
 | 
					        return displayMode === DisplayMode.TABLE ? getTableBody() : getBoardBody();
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <PageBlock
 | 
					        <PageBlock
 | 
				
			||||||
            fullHeight
 | 
					            fullHeight
 | 
				
			||||||
@@ -352,7 +352,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        >
 | 
					                        >
 | 
				
			||||||
                            <div
 | 
					                            <div
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                className={styles['top-panel']}
 | 
					                                className={styles["top-panel"]}
 | 
				
			||||||
                                style={{ display: displayMode === DisplayMode.TABLE ? "flex" : "none" }}
 | 
					                                style={{ display: displayMode === DisplayMode.TABLE ? "flex" : "none" }}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                <DealStatusSelect
 | 
					                                <DealStatusSelect
 | 
				
			||||||
@@ -384,7 +384,7 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
                        display: "flex",
 | 
					                        display: "flex",
 | 
				
			||||||
                        flexDirection: "column",
 | 
					                        flexDirection: "column",
 | 
				
			||||||
                        flex: 1,
 | 
					                        flex: 1,
 | 
				
			||||||
                        height: "100%"
 | 
					                        height: "100%",
 | 
				
			||||||
                    }}>
 | 
					                    }}>
 | 
				
			||||||
                    {getBody()}
 | 
					                    {getBody()}
 | 
				
			||||||
                </PageBlock>
 | 
					                </PageBlock>
 | 
				
			||||||
@@ -394,5 +394,5 @@ export const LeadsPage: FC = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        </PageBlock>
 | 
					        </PageBlock>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					import { CRUDTableProps } from "../../../../types/CRUDTable.tsx";
 | 
				
			||||||
 | 
					import { ServicePriceCategorySchema } from "../../../../client";
 | 
				
			||||||
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
 | 
					import useServicePriceCategoryTableColumns from "./columns.tsx";
 | 
				
			||||||
 | 
					import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { ActionIcon, Flex, Tooltip } from "@mantine/core";
 | 
				
			||||||
 | 
					import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CRUDTableProps<ServicePriceCategorySchema>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ServicePriceCategoryTable: FC<Props> = ({ items, onChange, onDelete }) => {
 | 
				
			||||||
 | 
					    const columns = useServicePriceCategoryTableColumns();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <BaseTable
 | 
				
			||||||
 | 
					            data={items}
 | 
				
			||||||
 | 
					            columns={columns}
 | 
				
			||||||
 | 
					            restProps={{
 | 
				
			||||||
 | 
					                enableRowActions: true,
 | 
				
			||||||
 | 
					                renderRowActions: ({ row }) => (
 | 
				
			||||||
 | 
					                    <Flex gap="md">
 | 
				
			||||||
 | 
					                        <Tooltip label="Редактировать">
 | 
				
			||||||
 | 
					                            <ActionIcon
 | 
				
			||||||
 | 
					                                onClick={() => onChange && onChange(row.original)}
 | 
				
			||||||
 | 
					                                variant={"default"}>
 | 
				
			||||||
 | 
					                                <IconEdit />
 | 
				
			||||||
 | 
					                            </ActionIcon>
 | 
				
			||||||
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					                        <Tooltip label="Удалить">
 | 
				
			||||||
 | 
					                            <ActionIcon onClick={() => onDelete && onDelete(row.original)} variant={"default"}>
 | 
				
			||||||
 | 
					                                <IconTrash />
 | 
				
			||||||
 | 
					                            </ActionIcon>
 | 
				
			||||||
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					                    </Flex>
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            } as MRT_TableOptions<ServicePriceCategorySchema>}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServicePriceCategoryTable;
 | 
				
			||||||
@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import { useMemo } from "react";
 | 
				
			||||||
 | 
					import { MRT_ColumnDef } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { ServicePriceCategorySchema } from "../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useServicePriceCategoryTableColumns = () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return useMemo<MRT_ColumnDef<ServicePriceCategorySchema>[]>(() => [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "name",
 | 
				
			||||||
 | 
					            header: "Название",
 | 
				
			||||||
 | 
					            enableColumnActions: false,
 | 
				
			||||||
 | 
					            enableSorting: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ], []);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useServicePriceCategoryTableColumns;
 | 
				
			||||||
@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					import { BaseFormInputProps } from "../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import type { ServiceCategoryPriceSchema, ServicePriceCategorySchema } from "../../../../client";
 | 
				
			||||||
 | 
					import { FC, useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { Flex, NumberInput, rem } from "@mantine/core";
 | 
				
			||||||
 | 
					import ServicePriceCategorySelect
 | 
				
			||||||
 | 
					    from "../../../../components/Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type PriceCategoryInputProps = BaseFormInputProps<ServiceCategoryPriceSchema[]>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PriceCategoryInput: FC<PriceCategoryInputProps> = (props: PriceCategoryInputProps) => {
 | 
				
			||||||
 | 
					    const [innerState, setInnerState] = useState<ServiceCategoryPriceSchema[]>(props.value || []);
 | 
				
			||||||
 | 
					    const [category, setCategory] = useState<ServicePriceCategorySchema | undefined>(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getValue = (): number | undefined | string => {
 | 
				
			||||||
 | 
					        if (category === undefined) return undefined;
 | 
				
			||||||
 | 
					        const value = innerState.find(item => item.category.id === category.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return value?.price || "";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const handleChange = (value: number | string) => {
 | 
				
			||||||
 | 
					        // remove value if is string
 | 
				
			||||||
 | 
					        if (typeof value === "string") {
 | 
				
			||||||
 | 
					            setInnerState(innerState.filter(item => item.category.id !== category?.id));
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const newValue = {
 | 
				
			||||||
 | 
					            category: category as ServicePriceCategorySchema,
 | 
				
			||||||
 | 
					            price: value,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        const newInnerState = innerState.filter(item => item.category.id !== category?.id);
 | 
				
			||||||
 | 
					        setInnerState([...newInnerState, newValue]);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (props.value === innerState) return;
 | 
				
			||||||
 | 
					        props.onChange(innerState);
 | 
				
			||||||
 | 
					    }, [innerState]);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Flex direction={"column"} gap={rem(10)}>
 | 
				
			||||||
 | 
					            <ServicePriceCategorySelect
 | 
				
			||||||
 | 
					                label={"Категория цены"}
 | 
				
			||||||
 | 
					                placeholder={"Выберите категорию цены"}
 | 
				
			||||||
 | 
					                onChange={setCategory}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <NumberInput
 | 
				
			||||||
 | 
					                label={"Цена"}
 | 
				
			||||||
 | 
					                placeholder={"Введите цену"}
 | 
				
			||||||
 | 
					                value={getValue()}
 | 
				
			||||||
 | 
					                onChange={handleChange}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					        </Flex>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PriceCategoryInput;
 | 
				
			||||||
@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					import { SegmentedControl, SegmentedControlProps } from "@mantine/core";
 | 
				
			||||||
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					import { omit } from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum ServicePriceType {
 | 
				
			||||||
 | 
					    DEFAULT,
 | 
				
			||||||
 | 
					    BY_RANGE,
 | 
				
			||||||
 | 
					    BY_CATEGORY,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RestProps = {
 | 
				
			||||||
 | 
					    onChange: (value: ServicePriceType) => void;
 | 
				
			||||||
 | 
					    value?: ServicePriceType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					type Props = Omit<SegmentedControlProps, "data" | "value" | "onChange"> & RestProps;
 | 
				
			||||||
 | 
					const ServicePriceTypeSegmentedControl: FC<Props> = (props) => {
 | 
				
			||||||
 | 
					    const { onChange, value } = props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const data = [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            label: "По умолчанию",
 | 
				
			||||||
 | 
					            value: ServicePriceType.DEFAULT.toString(),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            label: "По диапазону",
 | 
				
			||||||
 | 
					            value: ServicePriceType.BY_RANGE.toString(),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            label: "По категории",
 | 
				
			||||||
 | 
					            value: ServicePriceType.BY_CATEGORY.toString(),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    const handleChange = (value: string) => {
 | 
				
			||||||
 | 
					        onChange(Number(value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const restProps = omit(props, ["onChange", "value"]);
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <SegmentedControl
 | 
				
			||||||
 | 
					            data={data}
 | 
				
			||||||
 | 
					            value={value?.toString()}
 | 
				
			||||||
 | 
					            onChange={handleChange}
 | 
				
			||||||
 | 
					            {...restProps}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServicePriceTypeSegmentedControl;
 | 
				
			||||||
@@ -1,27 +1,33 @@
 | 
				
			|||||||
import { FC } from "react";
 | 
					import { FC } from "react";
 | 
				
			||||||
import { SegmentedControl, SegmentedControlProps } from "@mantine/core";
 | 
					import { SegmentedControl, SegmentedControlProps } from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum ServicesTab {
 | 
					export enum ServicesTab {
 | 
				
			||||||
    DEAL_SERVICE,
 | 
					    DEAL_SERVICE,
 | 
				
			||||||
    PRODUCT_SERVICE,
 | 
					    PRODUCT_SERVICE,
 | 
				
			||||||
    SERVICES_KITS
 | 
					    SERVICES_KITS,
 | 
				
			||||||
 | 
					    SERVICES_PRICE_CATEGORIES
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = Omit<SegmentedControlProps, 'data'>;
 | 
					type Props = Omit<SegmentedControlProps, "data">;
 | 
				
			||||||
const data = [
 | 
					const data = [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        label: 'Для товара',
 | 
					        label: "Для товара",
 | 
				
			||||||
        value: ServicesTab.PRODUCT_SERVICE.toString()
 | 
					        value: ServicesTab.PRODUCT_SERVICE.toString(),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        label: 'Для сделки',
 | 
					        label: "Для сделки",
 | 
				
			||||||
        value: ServicesTab.DEAL_SERVICE.toString()
 | 
					        value: ServicesTab.DEAL_SERVICE.toString(),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        label: 'Наборы услуг',
 | 
					        label: "Наборы услуг",
 | 
				
			||||||
        value: ServicesTab.SERVICES_KITS.toString()
 | 
					        value: ServicesTab.SERVICES_KITS.toString(),
 | 
				
			||||||
    }
 | 
					    },
 | 
				
			||||||
]
 | 
					    {
 | 
				
			||||||
 | 
					        label: "Категории цен",
 | 
				
			||||||
 | 
					        value: ServicesTab.SERVICES_PRICE_CATEGORIES.toString(),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
const ServiceTypeSegmentedControl: FC<Props> = (props) => {
 | 
					const ServiceTypeSegmentedControl: FC<Props> = (props) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
@@ -29,6 +35,6 @@ const ServiceTypeSegmentedControl: FC<Props> = (props) => {
 | 
				
			|||||||
            data={data}
 | 
					            data={data}
 | 
				
			||||||
            {...props}
 | 
					            {...props}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
export default ServiceTypeSegmentedControl
 | 
					export default ServiceTypeSegmentedControl;
 | 
				
			||||||
@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					import ObjectList from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					import { ServiceService } from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useServicePriceCategoriesList = () => ObjectList({
 | 
				
			||||||
 | 
					    queryFn: ServiceService.getAllPriceCategories,
 | 
				
			||||||
 | 
					    getObjectsFn: (response) => response.priceCategories,
 | 
				
			||||||
 | 
					    queryKey: "getAllPriceCategories",
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useServicePriceCategoriesList;
 | 
				
			||||||
@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import UseObjectState from "../../../types/UseObjectState.ts";
 | 
				
			||||||
 | 
					import { type ServicePriceCategorySchema, ServiceService } from "../../../client";
 | 
				
			||||||
 | 
					import useServicePriceCategoriesList from "./useServicePriceCategoriesList.tsx";
 | 
				
			||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { notifications } from "../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useServicePriceCategoryState = (): UseObjectState<ServicePriceCategorySchema> => {
 | 
				
			||||||
 | 
					    const { objects, refetch } = useServicePriceCategoriesList();
 | 
				
			||||||
 | 
					    const onCreateClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "servicePriceCategoryForm",
 | 
				
			||||||
 | 
					            title: "Создание категории цен",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onCreate,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onCreate = (values: ServicePriceCategorySchema) => {
 | 
				
			||||||
 | 
					        console.log(ServiceService);
 | 
				
			||||||
 | 
					        ServiceService.createPriceCategory({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                name: values.name,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					            notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					            if (!ok) return;
 | 
				
			||||||
 | 
					            await refetch();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onDelete = (item: ServicePriceCategorySchema) => {
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление категории",
 | 
				
			||||||
 | 
					            children: "Вы уверены, что хотите удалить категорию?",
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ServiceService.deletePriceCategory({
 | 
				
			||||||
 | 
					                    requestBody: {
 | 
				
			||||||
 | 
					                        id: item.id,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                    notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					                    if (!ok) return;
 | 
				
			||||||
 | 
					                    await refetch();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onChange = (item: ServicePriceCategorySchema) => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "servicePriceCategoryForm",
 | 
				
			||||||
 | 
					            title: "Изменение категории цен",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onChange: (values: ServicePriceCategorySchema) => {
 | 
				
			||||||
 | 
					                    ServiceService.updatePriceCategory({
 | 
				
			||||||
 | 
					                        requestBody: {
 | 
				
			||||||
 | 
					                            id: item.id,
 | 
				
			||||||
 | 
					                            name: values.name,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                        notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					                        if (!ok) return;
 | 
				
			||||||
 | 
					                        await refetch();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                element: item,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        onCreateClick,
 | 
				
			||||||
 | 
					        onCreate,
 | 
				
			||||||
 | 
					        onDelete,
 | 
				
			||||||
 | 
					        onChange,
 | 
				
			||||||
 | 
					        objects,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export default useServicePriceCategoryState;
 | 
				
			||||||
							
								
								
									
										57
									
								
								src/pages/ServicesPage/hooks/useServicesKitsState.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/pages/ServicesPage/hooks/useServicesKitsState.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					import { GetServiceKitSchema, ServiceService } from "../../../client";
 | 
				
			||||||
 | 
					import { omit } from "lodash";
 | 
				
			||||||
 | 
					import { notifications } from "../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					import useServicesKitsList from "./useServicesKitsList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useServicesKitsState = () => {
 | 
				
			||||||
 | 
					    const { objects: servicesKits, refetch: refetchKits } = useServicesKitsList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onKitCreate = (kit: GetServiceKitSchema) => {
 | 
				
			||||||
 | 
					        ServiceService.createServicesKit({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                data: {
 | 
				
			||||||
 | 
					                    ...omit(kit, ["services", "id"]),
 | 
				
			||||||
 | 
					                    servicesIds: kit.services.map(service => service.id),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					            notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					            if (!ok) return;
 | 
				
			||||||
 | 
					            await refetchKits();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onKitCreateClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "serviceKitModalForm",
 | 
				
			||||||
 | 
					            title: "Создание набора услуг",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onCreate: onKitCreate,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onKitUpdate = (kit: GetServiceKitSchema) => {
 | 
				
			||||||
 | 
					        ServiceService.updateServicesKit({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                data: {
 | 
				
			||||||
 | 
					                    ...omit(kit, ["services"]),
 | 
				
			||||||
 | 
					                    servicesIds: kit.services.map(service => service.id),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }).then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					            notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					            if (!ok) return;
 | 
				
			||||||
 | 
					            await refetchKits();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        onKitCreateClick,
 | 
				
			||||||
 | 
					        onKitUpdate,
 | 
				
			||||||
 | 
					        servicesKits,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useServicesKitsState;
 | 
				
			||||||
							
								
								
									
										89
									
								
								src/pages/ServicesPage/hooks/useServicesState.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/pages/ServicesPage/hooks/useServicesState.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { ServiceCategorySchema, ServiceSchema, ServiceService } from "../../../client";
 | 
				
			||||||
 | 
					import { notifications } from "../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import useServicesList from "./useServicesList.tsx";
 | 
				
			||||||
 | 
					import { Text } from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useServicesState = () => {
 | 
				
			||||||
 | 
					    const { services, refetch } = useServicesList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onCreateClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "createService",
 | 
				
			||||||
 | 
					            title: "Создание услуги",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onCreate,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onCreate = (values: ServiceSchema) => {
 | 
				
			||||||
 | 
					        ServiceService.createService({ requestBody: { service: values } })
 | 
				
			||||||
 | 
					            .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					                if (!ok) return;
 | 
				
			||||||
 | 
					                await refetch();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onCreateCategoryClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "createServiceCategory",
 | 
				
			||||||
 | 
					            title: "Создание категории",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onCreate: onCategoryCreate,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onCategoryCreate = (category: ServiceCategorySchema) => {
 | 
				
			||||||
 | 
					        ServiceService.createServiceCategory({ requestBody: { category: category } })
 | 
				
			||||||
 | 
					            .then(({ ok, message }) =>
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message: message }));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onServiceDelete = (service: ServiceSchema) => {
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: "Удаление услуги",
 | 
				
			||||||
 | 
					            children: (<Text>
 | 
				
			||||||
 | 
					                Вы уверены, что хотите удалить услугу "{service.name}"?
 | 
				
			||||||
 | 
					            </Text>),
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                ServiceService.deleteService({ requestBody: { serviceId: service.id } })
 | 
				
			||||||
 | 
					                    .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                        notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					                        if (!ok) return;
 | 
				
			||||||
 | 
					                        await refetch();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            labels: {
 | 
				
			||||||
 | 
					                confirm: "Удалить",
 | 
				
			||||||
 | 
					                cancel: "Отмена",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onServiceUpdate = (service: ServiceSchema) => {
 | 
				
			||||||
 | 
					        ServiceService
 | 
				
			||||||
 | 
					            .updateService({
 | 
				
			||||||
 | 
					                requestBody: {
 | 
				
			||||||
 | 
					                    data: service,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message: message });
 | 
				
			||||||
 | 
					                if (!ok) return;
 | 
				
			||||||
 | 
					                await refetch();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        services,
 | 
				
			||||||
 | 
					        onCreateClick,
 | 
				
			||||||
 | 
					        onServiceDelete,
 | 
				
			||||||
 | 
					        onServiceUpdate,
 | 
				
			||||||
 | 
					        onCreateCategoryClick,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useServicesState;
 | 
				
			||||||
@@ -2,11 +2,16 @@ import {ServicePriceRangeSchema, ServiceSchema} from "../../../client";
 | 
				
			|||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { ContextModalProps } from "@mantine/modals";
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import {NumberInput, TextInput} from "@mantine/core";
 | 
					import { Fieldset, Flex, rem, TextInput } from "@mantine/core";
 | 
				
			||||||
import ServiceCategorySelect from "../components/ServiceCategorySelect/ServiceCategorySelect.tsx";
 | 
					import ServiceCategorySelect from "../components/ServiceCategorySelect/ServiceCategorySelect.tsx";
 | 
				
			||||||
import ServiceTypeSelect from "../components/ServiceTypeSelect/ServiceTypeSelect.tsx";
 | 
					import ServiceTypeSelect from "../components/ServiceTypeSelect/ServiceTypeSelect.tsx";
 | 
				
			||||||
import ServicePriceInput from "../components/ServicePriceInput/ServicePriceInput.tsx";
 | 
					import ServicePriceTypeSegmentedControl, {
 | 
				
			||||||
import {PriceRangeInputType} from "../components/ServicePriceInput/RangePriceInput.tsx";
 | 
					    ServicePriceType,
 | 
				
			||||||
 | 
					} from "../components/ServicePriceTypeSegmentedControl/ServicePriceTypeSegmentedControl.tsx";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import RangePriceInput, { PriceRangeInputType } from "../components/ServicePriceInput/RangePriceInput.tsx";
 | 
				
			||||||
 | 
					import SinglePriceInput from "../components/ServicePriceInput/SinglePriceInput.tsx";
 | 
				
			||||||
 | 
					import PriceCategoryInput, { PriceCategoryInputProps } from "../components/ServicePriceInput/PriceCategoryInput.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = CreateEditFormProps<ServiceSchema>
 | 
					type Props = CreateEditFormProps<ServiceSchema>
 | 
				
			||||||
const CreateServiceModal = ({
 | 
					const CreateServiceModal = ({
 | 
				
			||||||
@@ -14,40 +19,61 @@ const CreateServiceModal = ({
 | 
				
			|||||||
                                id,
 | 
					                                id,
 | 
				
			||||||
                                innerProps,
 | 
					                                innerProps,
 | 
				
			||||||
                            }: ContextModalProps<Props>) => {
 | 
					                            }: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					    const [priceType, setPriceType] = useState<ServicePriceType>(ServicePriceType.DEFAULT);
 | 
				
			||||||
    const isEditing = 'onChange' in innerProps;
 | 
					    const isEditing = "onChange" in innerProps;
 | 
				
			||||||
    const initialValues: ServiceSchema = isEditing ? innerProps.element : {
 | 
					    const initialValues: ServiceSchema = isEditing ? innerProps.element : {
 | 
				
			||||||
        id: -1,
 | 
					        id: -1,
 | 
				
			||||||
        name: '',
 | 
					        name: "",
 | 
				
			||||||
        price: 0,
 | 
					        price: 0,
 | 
				
			||||||
        category: {
 | 
					        category: {
 | 
				
			||||||
            id: -1,
 | 
					            id: -1,
 | 
				
			||||||
            name: ''
 | 
					            name: "",
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        serviceType: -1,
 | 
					        serviceType: -1,
 | 
				
			||||||
        priceRanges: [] as ServicePriceRangeSchema[],
 | 
					        priceRanges: [] as ServicePriceRangeSchema[],
 | 
				
			||||||
        cost: null
 | 
					        cost: null,
 | 
				
			||||||
    }
 | 
					        categoryPrices: [],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const form = useForm<ServiceSchema>({
 | 
					    const form = useForm<ServiceSchema>({
 | 
				
			||||||
        initialValues: initialValues,
 | 
					        initialValues: initialValues,
 | 
				
			||||||
        validate: {
 | 
					        validate: {
 | 
				
			||||||
            name: (name: string) => name.trim() !== '' ? null : "Необходимо ввести название услуги",
 | 
					            name: (name: string) => name.trim() !== "" ? null : "Необходимо ввести название услуги",
 | 
				
			||||||
            category: (category: {
 | 
					            category: (category: {
 | 
				
			||||||
                id: number,
 | 
					                id: number,
 | 
				
			||||||
                name: string
 | 
					                name: string
 | 
				
			||||||
            }) => category.id !== -1 ? null : "Необходимо выбрать категорию",
 | 
					            }) => category.id !== -1 ? null : "Необходимо выбрать категорию",
 | 
				
			||||||
            serviceType: (serviceType: number) => serviceType !== -1 ? null : "Необходимо выбрать тип услуги",
 | 
					            serviceType: (serviceType: number) => serviceType !== -1 ? null : "Необходимо выбрать тип услуги",
 | 
				
			||||||
            priceRanges: (value, values) => value.length > 0 || values.price > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
 | 
					            priceRanges: (value, values) => value.length > 0 || values.price > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
 | 
				
			||||||
            price: (value, values) => value > 0 || values.priceRanges.length > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги"
 | 
					            price: (value, values) => value > 0 || values.priceRanges.length > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        console.log(form.values.categoryPrices);
 | 
				
			||||||
 | 
					    }, [form.values]);
 | 
				
			||||||
 | 
					    const getPriceBody = () => {
 | 
				
			||||||
 | 
					        switch (priceType) {
 | 
				
			||||||
 | 
					            case ServicePriceType.DEFAULT:
 | 
				
			||||||
 | 
					                return <SinglePriceInput
 | 
				
			||||||
 | 
					                    placeholder={"Введите стоимость услуги"}
 | 
				
			||||||
 | 
					                    label={"Cтоимость услуги"}
 | 
				
			||||||
 | 
					                    hideControls
 | 
				
			||||||
 | 
					                    {...form.getInputProps("cost")}
 | 
				
			||||||
 | 
					                />;
 | 
				
			||||||
 | 
					            case ServicePriceType.BY_RANGE:
 | 
				
			||||||
 | 
					                return <RangePriceInput
 | 
				
			||||||
 | 
					                    {...form.getInputProps("priceRanges") as PriceRangeInputType}
 | 
				
			||||||
 | 
					                />;
 | 
				
			||||||
 | 
					            case ServicePriceType.BY_CATEGORY:
 | 
				
			||||||
 | 
					                return <PriceCategoryInput
 | 
				
			||||||
 | 
					                    {...form.getInputProps("categoryPrices") as PriceCategoryInputProps}
 | 
				
			||||||
 | 
					                />;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    })
 | 
					    };
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const onCancelClick = () => {
 | 
					    const onCancelClick = () => {
 | 
				
			||||||
        context.closeContextModal(id);
 | 
					        context.closeContextModal(id);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <BaseFormModal
 | 
					        <BaseFormModal
 | 
				
			||||||
            {...innerProps}
 | 
					            {...innerProps}
 | 
				
			||||||
@@ -57,43 +83,39 @@ const CreateServiceModal = ({
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
            <BaseFormModal.Body>
 | 
					            <BaseFormModal.Body>
 | 
				
			||||||
                <>
 | 
					                <>
 | 
				
			||||||
 | 
					                    <Fieldset legend={"Общие параметры"}>
 | 
				
			||||||
                        <ServiceCategorySelect
 | 
					                        <ServiceCategorySelect
 | 
				
			||||||
                            placeholder={"Выберите категорию"}
 | 
					                            placeholder={"Выберите категорию"}
 | 
				
			||||||
                            label={"Категория услуги"}
 | 
					                            label={"Категория услуги"}
 | 
				
			||||||
                        {...form.getInputProps('category')}
 | 
					                            {...form.getInputProps("category")}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <TextInput
 | 
					                        <TextInput
 | 
				
			||||||
 | 
					 | 
				
			||||||
                            placeholder={"Введите название услуги"}
 | 
					                            placeholder={"Введите название услуги"}
 | 
				
			||||||
                            label={"Название услуги"}
 | 
					                            label={"Название услуги"}
 | 
				
			||||||
                        {...form.getInputProps('name')}
 | 
					                            {...form.getInputProps("name")}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <ServiceTypeSelect
 | 
					                        <ServiceTypeSelect
 | 
				
			||||||
                            placeholder={"Выберите тип услуги"}
 | 
					                            placeholder={"Выберите тип услуги"}
 | 
				
			||||||
                            label={"Тип услуги"}
 | 
					                            label={"Тип услуги"}
 | 
				
			||||||
                        {...form.getInputProps('serviceType')}
 | 
					                            {...form.getInputProps("serviceType")}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    <NumberInput
 | 
					                    </Fieldset>
 | 
				
			||||||
                        placeholder={"Введите себестоимость услуги"}
 | 
					                    <Fieldset legend={"Стоимость"}>
 | 
				
			||||||
                        label={"Себестоимость услуги"}
 | 
					                        <Flex direction={"column"} gap={rem(10)} justify={"center"}>
 | 
				
			||||||
                        hideControls
 | 
					                            <ServicePriceTypeSegmentedControl
 | 
				
			||||||
                        {...form.getInputProps('cost')}
 | 
					                                value={priceType}
 | 
				
			||||||
                    />
 | 
					                                onChange={setPriceType}
 | 
				
			||||||
                    <ServicePriceInput
 | 
					 | 
				
			||||||
                        singlePriceInputProps={{
 | 
					 | 
				
			||||||
                            hideControls: true,
 | 
					 | 
				
			||||||
                            label: "Цена за единицу услуги",
 | 
					 | 
				
			||||||
                            placeholder: "Введите цену за одну услугу",
 | 
					 | 
				
			||||||
                            ...form.getInputProps('price'),
 | 
					 | 
				
			||||||
                        }}
 | 
					 | 
				
			||||||
                        priceRangeInputProps={{
 | 
					 | 
				
			||||||
                            ...form.getInputProps('priceRanges')
 | 
					 | 
				
			||||||
                        } as PriceRangeInputType}
 | 
					 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
 | 
					                            {getPriceBody()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        </Flex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                </>
 | 
					                </>
 | 
				
			||||||
            </BaseFormModal.Body>
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
        </BaseFormModal>
 | 
					        </BaseFormModal>
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default CreateServiceModal;
 | 
					export default CreateServiceModal;
 | 
				
			||||||
							
								
								
									
										38
									
								
								src/pages/ServicesPage/modals/ServicePriceCategoryForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/pages/ServicesPage/modals/ServicePriceCategoryForm.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import { ServicePriceCategorySchema } from "../../../client";
 | 
				
			||||||
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { TextInput } from "@mantine/core";
 | 
				
			||||||
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CreateEditFormProps<ServicePriceCategorySchema>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ServicePriceCategoryForm = ({ context, id, innerProps }: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					    const isEditing = "element" in innerProps;
 | 
				
			||||||
 | 
					    const initialValues: Partial<ServicePriceCategorySchema> = isEditing ? innerProps.element : {
 | 
				
			||||||
 | 
					        name: "",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const form = useForm<Partial<ServicePriceCategorySchema>>({
 | 
				
			||||||
 | 
					        initialValues,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <BaseFormModal
 | 
				
			||||||
 | 
					            {...innerProps}
 | 
				
			||||||
 | 
					            form={form}
 | 
				
			||||||
 | 
					            closeOnSubmit
 | 
				
			||||||
 | 
					            onClose={() => context.closeContextModal(id)}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <BaseFormModal.Body>
 | 
				
			||||||
 | 
					                <>
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        label={"Название"}
 | 
				
			||||||
 | 
					                        placeholder={"Введите название категории"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("name")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </>
 | 
				
			||||||
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
 | 
					        </BaseFormModal>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServicePriceCategoryForm;
 | 
				
			||||||
@@ -13,17 +13,17 @@ const ServiceKitModalForm = ({
 | 
				
			|||||||
                                 id,
 | 
					                                 id,
 | 
				
			||||||
                                 innerProps,
 | 
					                                 innerProps,
 | 
				
			||||||
                             }: ContextModalProps<Props>) => {
 | 
					                             }: ContextModalProps<Props>) => {
 | 
				
			||||||
    const isEditing = 'element' in innerProps;
 | 
					    const isEditing = "element" in innerProps;
 | 
				
			||||||
    const initialValues: Partial<GetServiceKitSchema> = isEditing ? innerProps.element : {
 | 
					    const initialValues: Partial<GetServiceKitSchema> = isEditing ? innerProps.element : {
 | 
				
			||||||
        name: "",
 | 
					        name: "",
 | 
				
			||||||
        serviceType: ServiceType.DEAL_SERVICE,
 | 
					        serviceType: ServiceType.DEAL_SERVICE,
 | 
				
			||||||
        services: []
 | 
					        services: [],
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const form = useForm<Partial<GetServiceKitSchema>>(
 | 
					    const form = useForm<Partial<GetServiceKitSchema>>(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            initialValues
 | 
					            initialValues,
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <BaseFormModal
 | 
					        <BaseFormModal
 | 
				
			||||||
@@ -54,7 +54,7 @@ const ServiceKitModalForm = ({
 | 
				
			|||||||
                </>
 | 
					                </>
 | 
				
			||||||
            </BaseFormModal.Body>
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
        </BaseFormModal>
 | 
					        </BaseFormModal>
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ServiceKitModalForm;
 | 
					export default ServiceKitModalForm;
 | 
				
			||||||
@@ -1,173 +1,90 @@
 | 
				
			|||||||
import { FC, useState } from "react";
 | 
					import { FC, useState } from "react";
 | 
				
			||||||
import ServicesTable from "../components/ServicesTable/ServicesTable.tsx";
 | 
					import ServicesTable from "../components/ServicesTable/ServicesTable.tsx";
 | 
				
			||||||
import useServicesList from "../hooks/useServicesList.tsx";
 | 
					 | 
				
			||||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
					import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
				
			||||||
import styles from './ServicesPage.module.css';
 | 
					import styles from "./ServicesPage.module.css";
 | 
				
			||||||
import {Button, Text} from "@mantine/core";
 | 
					import { Button } from "@mantine/core";
 | 
				
			||||||
import {GetServiceKitSchema, ServiceCategorySchema, ServiceSchema, ServiceService} from "../../../client";
 | 
					 | 
				
			||||||
import {notifications} from "../../../shared/lib/notifications.ts";
 | 
					 | 
				
			||||||
import {modals} from "@mantine/modals";
 | 
					 | 
				
			||||||
import ServiceTypeSegmentedControl, {
 | 
					import ServiceTypeSegmentedControl, {
 | 
				
			||||||
    ServicesTab
 | 
					    ServicesTab,
 | 
				
			||||||
} from "../components/ServiceTypeSegmentedControl/ServiceTypeSegmentedControl.tsx";
 | 
					} from "../components/ServiceTypeSegmentedControl/ServiceTypeSegmentedControl.tsx";
 | 
				
			||||||
import useServicesKitsList from "../hooks/useServicesKitsList.tsx";
 | 
					 | 
				
			||||||
import ServicesKitsTable from "../components/ServicesKitsTable/ServicesKitsTable.tsx";
 | 
					import ServicesKitsTable from "../components/ServicesKitsTable/ServicesKitsTable.tsx";
 | 
				
			||||||
import {omit} from "lodash";
 | 
					import ServicePriceCategoryTable from "../components/ServicePriceCategoryTable/ServicePriceCategoryTable.tsx";
 | 
				
			||||||
 | 
					import useServicesState from "../hooks/useServicesState.tsx";
 | 
				
			||||||
 | 
					import useServicesKitsState from "../hooks/useServicesKitsState.tsx";
 | 
				
			||||||
 | 
					import useServicePriceCategoryState from "../hooks/useServicePriceCategoryState.tsx";
 | 
				
			||||||
 | 
					import { ObjectStateToTableProps } from "../../../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ServicesPage: FC = () => {
 | 
					export const ServicesPage: FC = () => {
 | 
				
			||||||
    const {services, refetch} = useServicesList();
 | 
					    const [serviceType, setServiceType] = useState(ServicesTab.DEAL_SERVICE);
 | 
				
			||||||
    const {objects: servicesKits, refetch: refetchKits} = useServicesKitsList();
 | 
					    const { services, onServiceDelete, onServiceUpdate, onCreateClick, onCreateCategoryClick } = useServicesState();
 | 
				
			||||||
    const [serviceType, setServiceType] = useState(ServicesTab.DEAL_SERVICE)
 | 
					    const { servicesKits, onKitUpdate, onKitCreateClick } = useServicesKitsState();
 | 
				
			||||||
    // region Service create
 | 
					    const { onCreateClick: onCreatePriceCategoryClick, ...priceCategoryRestProps } = useServicePriceCategoryState();
 | 
				
			||||||
    const onCreateClick = () => {
 | 
					    const getBody = () => {
 | 
				
			||||||
        modals.openContextModal({
 | 
					        switch (serviceType) {
 | 
				
			||||||
            modal: 'createService',
 | 
					            case ServicesTab.SERVICES_KITS:
 | 
				
			||||||
            title: 'Создание услуги',
 | 
					                return (
 | 
				
			||||||
            withCloseButton: false,
 | 
					                    <ServicesKitsTable
 | 
				
			||||||
            innerProps: {
 | 
					                        items={servicesKits}
 | 
				
			||||||
                onCreate
 | 
					                        onChange={onKitUpdate}
 | 
				
			||||||
            }
 | 
					                    />
 | 
				
			||||||
        })
 | 
					                );
 | 
				
			||||||
    }
 | 
					            case ServicesTab.DEAL_SERVICE:
 | 
				
			||||||
    const onCreate = (values: ServiceSchema) => {
 | 
					            case ServicesTab.PRODUCT_SERVICE:
 | 
				
			||||||
        ServiceService.createService({requestBody: {service: values}})
 | 
					                return (
 | 
				
			||||||
            .then(async ({ok, message}) => {
 | 
					                    <ServicesTable
 | 
				
			||||||
                notifications.guess(ok, {message: message});
 | 
					                        onDelete={onServiceDelete}
 | 
				
			||||||
                if (!ok) return;
 | 
					                        onChange={onServiceUpdate}
 | 
				
			||||||
                await refetch();
 | 
					                        items={services.filter(service => service.serviceType == serviceType)}
 | 
				
			||||||
            })
 | 
					                    />
 | 
				
			||||||
    }
 | 
					                );
 | 
				
			||||||
    // endregion
 | 
					            case ServicesTab.SERVICES_PRICE_CATEGORIES:
 | 
				
			||||||
 | 
					                return (
 | 
				
			||||||
    // region Category create
 | 
					                    <ServicePriceCategoryTable
 | 
				
			||||||
    const onCreateCategoryClick = () => {
 | 
					                        {...ObjectStateToTableProps(priceCategoryRestProps)}
 | 
				
			||||||
        modals.openContextModal({
 | 
					                    />
 | 
				
			||||||
            modal: "createServiceCategory",
 | 
					                );
 | 
				
			||||||
            title: 'Создание категории',
 | 
					        }
 | 
				
			||||||
            withCloseButton: false,
 | 
					    };
 | 
				
			||||||
            innerProps: {
 | 
					
 | 
				
			||||||
                onCreate: onCategoryCreate
 | 
					    const getControls = () => {
 | 
				
			||||||
            }
 | 
					        switch (serviceType) {
 | 
				
			||||||
        })
 | 
					            case ServicesTab.SERVICES_KITS:
 | 
				
			||||||
    }
 | 
					                return (
 | 
				
			||||||
    const onCategoryCreate = (category: ServiceCategorySchema) => {
 | 
					                    <Button onClick={onKitCreateClick} variant={"default"}>Создать набор</Button>
 | 
				
			||||||
        ServiceService.createServiceCategory({requestBody: {category: category}})
 | 
					                );
 | 
				
			||||||
            .then(({ok, message}) =>
 | 
					            case ServicesTab.DEAL_SERVICE:
 | 
				
			||||||
                notifications.guess(ok, {message: message}))
 | 
					            case ServicesTab.PRODUCT_SERVICE:
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // endregion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const onServiceDelete = (service: ServiceSchema) => {
 | 
					 | 
				
			||||||
        modals.openConfirmModal({
 | 
					 | 
				
			||||||
            title: 'Удаление услуги',
 | 
					 | 
				
			||||||
            children: (<Text>
 | 
					 | 
				
			||||||
                Вы уверены, что хотите удалить услугу "{service.name}"?
 | 
					 | 
				
			||||||
            </Text>),
 | 
					 | 
				
			||||||
            onConfirm: () => {
 | 
					 | 
				
			||||||
                ServiceService.deleteService({requestBody: {serviceId: service.id}})
 | 
					 | 
				
			||||||
                    .then(async ({ok, message}) => {
 | 
					 | 
				
			||||||
                        notifications.guess(ok, {message: message});
 | 
					 | 
				
			||||||
                        if (!ok) return;
 | 
					 | 
				
			||||||
                        await refetch();
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            labels: {
 | 
					 | 
				
			||||||
                confirm: 'Удалить',
 | 
					 | 
				
			||||||
                cancel: 'Отмена'
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const onServiceUpdate = (service: ServiceSchema) => {
 | 
					 | 
				
			||||||
        ServiceService
 | 
					 | 
				
			||||||
            .updateService({
 | 
					 | 
				
			||||||
                requestBody: {
 | 
					 | 
				
			||||||
                    data: service
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .then(async ({ok, message}) => {
 | 
					 | 
				
			||||||
                notifications.guess(ok, {message: message});
 | 
					 | 
				
			||||||
                if (!ok) return;
 | 
					 | 
				
			||||||
                await refetch();
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const onKitCreate = (kit: GetServiceKitSchema) => {
 | 
					 | 
				
			||||||
        ServiceService.createServicesKit({
 | 
					 | 
				
			||||||
            requestBody: {
 | 
					 | 
				
			||||||
                data: {
 | 
					 | 
				
			||||||
                    ...omit(kit, ["services", "id"]),
 | 
					 | 
				
			||||||
                    servicesIds: kit.services.map(service => service.id)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }).then(async ({ok, message}) => {
 | 
					 | 
				
			||||||
            notifications.guess(ok, {message: message});
 | 
					 | 
				
			||||||
            if (!ok) return;
 | 
					 | 
				
			||||||
            await refetchKits();
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const onKitCreateClick = () => {
 | 
					 | 
				
			||||||
        modals.openContextModal({
 | 
					 | 
				
			||||||
            modal: 'serviceKitModalForm',
 | 
					 | 
				
			||||||
            title: 'Создание набора услуг',
 | 
					 | 
				
			||||||
            withCloseButton: false,
 | 
					 | 
				
			||||||
            innerProps: {
 | 
					 | 
				
			||||||
                onCreate: onKitCreate
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const onKitUpdate = (kit: GetServiceKitSchema) => {
 | 
					 | 
				
			||||||
        ServiceService.updateServicesKit({
 | 
					 | 
				
			||||||
            requestBody: {
 | 
					 | 
				
			||||||
                data: {
 | 
					 | 
				
			||||||
                    ...omit(kit, ["services"]),
 | 
					 | 
				
			||||||
                    servicesIds: kit.services.map(service => service.id)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }).then(async ({ok, message}) => {
 | 
					 | 
				
			||||||
            notifications.guess(ok, {message: message});
 | 
					 | 
				
			||||||
            if (!ok) return;
 | 
					 | 
				
			||||||
            await refetchKits();
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
                return (
 | 
					                return (
 | 
				
			||||||
        <div className={styles['container']}>
 | 
					 | 
				
			||||||
            <PageBlock>
 | 
					 | 
				
			||||||
                <div className={styles['top-panel']}>
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        serviceType === ServicesTab.SERVICES_KITS ?
 | 
					 | 
				
			||||||
                            <Button onClick={onKitCreateClick} variant={"default"}>Создать набор</Button> :
 | 
					 | 
				
			||||||
                    <>
 | 
					                    <>
 | 
				
			||||||
                        <Button onClick={onCreateClick} variant={"default"}>Создать услугу</Button>
 | 
					                        <Button onClick={onCreateClick} variant={"default"}>Создать услугу</Button>
 | 
				
			||||||
                                <Button onClick={onCreateCategoryClick} variant={"default"}>Создать
 | 
					                        <Button onClick={onCreateCategoryClick} variant={"default"}>Создать категорию</Button>
 | 
				
			||||||
                                    категорию</Button>
 | 
					 | 
				
			||||||
                    </>
 | 
					                    </>
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            case ServicesTab.SERVICES_PRICE_CATEGORIES:
 | 
				
			||||||
 | 
					                return (
 | 
				
			||||||
 | 
					                    <Button variant={"default"} onClick={() => {
 | 
				
			||||||
 | 
					                        if (onCreatePriceCategoryClick) {
 | 
				
			||||||
 | 
					                            onCreatePriceCategoryClick();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                    }}>Создать категорию</Button>
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <div className={styles["container"]}>
 | 
				
			||||||
 | 
					            <PageBlock>
 | 
				
			||||||
 | 
					                <div className={styles["top-panel"]}>
 | 
				
			||||||
 | 
					                    {getControls()}
 | 
				
			||||||
                    <ServiceTypeSegmentedControl
 | 
					                    <ServiceTypeSegmentedControl
 | 
				
			||||||
                        className={styles['top-panel-last-item']}
 | 
					                        className={styles["top-panel-last-item"]}
 | 
				
			||||||
                        value={serviceType.toString()}
 | 
					                        value={serviceType.toString()}
 | 
				
			||||||
                        onChange={(event) => setServiceType(parseInt(event))}
 | 
					                        onChange={(event) => setServiceType(parseInt(event))}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </PageBlock>
 | 
					            </PageBlock>
 | 
				
			||||||
            <PageBlock>
 | 
					            <PageBlock>
 | 
				
			||||||
                {
 | 
					                {getBody()}
 | 
				
			||||||
                    serviceType === ServicesTab.SERVICES_KITS ?
 | 
					 | 
				
			||||||
                        <ServicesKitsTable
 | 
					 | 
				
			||||||
                            items={servicesKits}
 | 
					 | 
				
			||||||
                            onChange={onKitUpdate}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        :
 | 
					 | 
				
			||||||
                        <ServicesTable
 | 
					 | 
				
			||||||
                            onDelete={onServiceDelete}
 | 
					 | 
				
			||||||
                            onChange={onServiceUpdate}
 | 
					 | 
				
			||||||
                            items={services.filter(service => service.serviceType == serviceType)}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            </PageBlock>
 | 
					            </PageBlock>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import {BaseMarketplaceSchema} from "../client";
 | 
					import { BaseMarketplaceSchema, ServicePriceCategorySchema } from "../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type QuickDeal = {
 | 
					export type QuickDeal = {
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
@@ -7,5 +7,6 @@ export type QuickDeal = {
 | 
				
			|||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
    acceptanceDate: Date;
 | 
					    acceptanceDate: Date;
 | 
				
			||||||
    shippingWarehouse: string;
 | 
					    shippingWarehouse: string;
 | 
				
			||||||
    baseMarketplace: BaseMarketplaceSchema
 | 
					    baseMarketplace: BaseMarketplaceSchema;
 | 
				
			||||||
 | 
					    category?: ServicePriceCategorySchema;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/types/UseObjectState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/types/UseObjectState.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					type UseObjectState<T> = {
 | 
				
			||||||
 | 
					    onCreateClick?: () => void;
 | 
				
			||||||
 | 
					    onCreate: (values: T) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onDeleteClick?: (item: T) => void;
 | 
				
			||||||
 | 
					    onDelete: (item: T) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onChangeClick?: (item: T) => void;
 | 
				
			||||||
 | 
					    onChange: (item: T) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    objects: T[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UseObjectState;
 | 
				
			||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
import { ProductSchema } from "../client";
 | 
					import { ProductSchema } from "../client";
 | 
				
			||||||
import { isNil } from "lodash";
 | 
					import { isNil } from "lodash";
 | 
				
			||||||
import { ProductFieldNames } from "../pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
					import { ProductFieldNames } from "../pages/LeadsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
				
			||||||
 | 
					import UseObjectState from "./UseObjectState.ts";
 | 
				
			||||||
 | 
					import { CRUDTableProps } from "./CRUDTable.tsx";
 | 
				
			||||||
 | 
					import { MRT_RowData } from "mantine-react-table";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ObjectWithNameAndId = {
 | 
					export type ObjectWithNameAndId = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
@@ -14,12 +17,22 @@ export type BaseFormInputProps<T> = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
export const formatDate = (date: string) => {
 | 
					export const formatDate = (date: string) => {
 | 
				
			||||||
    return new Date(date).toLocaleDateString("ru-RU");
 | 
					    return new Date(date).toLocaleDateString("ru-RU");
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getProductFields = (product: ProductSchema) => {
 | 
					export const getProductFields = (product: ProductSchema) => {
 | 
				
			||||||
    return Object.entries(product).map(([key, value]) => {
 | 
					    return Object.entries(product).map(([key, value]) => {
 | 
				
			||||||
        const fieldName = ProductFieldNames[key as keyof ProductSchema];
 | 
					        const fieldName = ProductFieldNames[key as keyof ProductSchema];
 | 
				
			||||||
        if (!fieldName || isNil(value) || value === '' || !value) return;
 | 
					        if (!fieldName || isNil(value) || value === "" || !value) return;
 | 
				
			||||||
        return [fieldName.toString(), value.toString()];
 | 
					        return [fieldName.toString(), value.toString()];
 | 
				
			||||||
    }).filter(obj => obj !== undefined) || [];
 | 
					    }).filter(obj => obj !== undefined) || [];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ObjectStateToTableProps<T extends MRT_RowData>(state: UseObjectState<T>): CRUDTableProps<T> {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        items: state.objects,
 | 
				
			||||||
 | 
					        onDelete: state.onDelete,
 | 
				
			||||||
 | 
					        onChange: state.onChange,
 | 
				
			||||||
 | 
					        onCreate: state.onCreate,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user