feat: tags for expenses, filters by tags in statistics
This commit is contained in:
		@@ -25,6 +25,7 @@ export type { BarcodeTemplateUpdateRequest } from './models/BarcodeTemplateUpdat
 | 
				
			|||||||
export type { BarcodeTemplateUpdateResponse } from './models/BarcodeTemplateUpdateResponse';
 | 
					export type { BarcodeTemplateUpdateResponse } from './models/BarcodeTemplateUpdateResponse';
 | 
				
			||||||
export type { BaseEnumListSchema } from './models/BaseEnumListSchema';
 | 
					export type { BaseEnumListSchema } from './models/BaseEnumListSchema';
 | 
				
			||||||
export type { BaseEnumSchema } from './models/BaseEnumSchema';
 | 
					export type { BaseEnumSchema } from './models/BaseEnumSchema';
 | 
				
			||||||
 | 
					export type { BaseExpenseTagSchema } from './models/BaseExpenseTagSchema';
 | 
				
			||||||
export type { BaseMarketplaceSchema } from './models/BaseMarketplaceSchema';
 | 
					export type { BaseMarketplaceSchema } from './models/BaseMarketplaceSchema';
 | 
				
			||||||
export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
 | 
					export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
 | 
				
			||||||
export type { BillPaymentStatus } from './models/BillPaymentStatus';
 | 
					export type { BillPaymentStatus } from './models/BillPaymentStatus';
 | 
				
			||||||
@@ -47,6 +48,7 @@ export type { CreateBarcodeTemplateAttributeRequest } from './models/CreateBarco
 | 
				
			|||||||
export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse';
 | 
					export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse';
 | 
				
			||||||
export type { CreateDealBillRequest } from './models/CreateDealBillRequest';
 | 
					export type { CreateDealBillRequest } from './models/CreateDealBillRequest';
 | 
				
			||||||
export type { CreateDealBillResponse } from './models/CreateDealBillResponse';
 | 
					export type { CreateDealBillResponse } from './models/CreateDealBillResponse';
 | 
				
			||||||
 | 
					export type { CreateExpenseTagRequest } from './models/CreateExpenseTagRequest';
 | 
				
			||||||
export type { CreateMarketplaceRequest } from './models/CreateMarketplaceRequest';
 | 
					export type { CreateMarketplaceRequest } from './models/CreateMarketplaceRequest';
 | 
				
			||||||
export type { CreateMarketplaceResponse } from './models/CreateMarketplaceResponse';
 | 
					export type { CreateMarketplaceResponse } from './models/CreateMarketplaceResponse';
 | 
				
			||||||
export type { CreatePaymentRecordRequest } from './models/CreatePaymentRecordRequest';
 | 
					export type { CreatePaymentRecordRequest } from './models/CreatePaymentRecordRequest';
 | 
				
			||||||
@@ -133,6 +135,7 @@ export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServi
 | 
				
			|||||||
export type { DealUpdateServiceRequest } from './models/DealUpdateServiceRequest';
 | 
					export type { DealUpdateServiceRequest } from './models/DealUpdateServiceRequest';
 | 
				
			||||||
export type { DealUpdateServiceResponse } from './models/DealUpdateServiceResponse';
 | 
					export type { DealUpdateServiceResponse } from './models/DealUpdateServiceResponse';
 | 
				
			||||||
export type { DeleteExpenseResponse } from './models/DeleteExpenseResponse';
 | 
					export type { DeleteExpenseResponse } from './models/DeleteExpenseResponse';
 | 
				
			||||||
 | 
					export type { DeleteExpenseTagResponse } from './models/DeleteExpenseTagResponse';
 | 
				
			||||||
export type { DeleteMarketplaceRequest } from './models/DeleteMarketplaceRequest';
 | 
					export type { DeleteMarketplaceRequest } from './models/DeleteMarketplaceRequest';
 | 
				
			||||||
export type { DeleteMarketplaceResponse } from './models/DeleteMarketplaceResponse';
 | 
					export type { DeleteMarketplaceResponse } from './models/DeleteMarketplaceResponse';
 | 
				
			||||||
export type { DeletePaymentRecordRequest } from './models/DeletePaymentRecordRequest';
 | 
					export type { DeletePaymentRecordRequest } from './models/DeletePaymentRecordRequest';
 | 
				
			||||||
@@ -147,6 +150,7 @@ export type { DeleteShiftResponse } from './models/DeleteShiftResponse';
 | 
				
			|||||||
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 { ExpenseSchemaBase } from './models/ExpenseSchemaBase';
 | 
					export type { ExpenseSchemaBase } from './models/ExpenseSchemaBase';
 | 
				
			||||||
 | 
					export type { ExpenseTagSchema } from './models/ExpenseTagSchema';
 | 
				
			||||||
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
 | 
					export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
 | 
				
			||||||
export type { FinishShiftResponse } from './models/FinishShiftResponse';
 | 
					export type { FinishShiftResponse } from './models/FinishShiftResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
					export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
				
			||||||
@@ -154,6 +158,7 @@ export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeT
 | 
				
			|||||||
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
 | 
					export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
 | 
				
			||||||
export type { GetAllBaseMarketplacesResponse } from './models/GetAllBaseMarketplacesResponse';
 | 
					export type { GetAllBaseMarketplacesResponse } from './models/GetAllBaseMarketplacesResponse';
 | 
				
			||||||
export type { GetAllExpensesResponse } from './models/GetAllExpensesResponse';
 | 
					export type { GetAllExpensesResponse } from './models/GetAllExpensesResponse';
 | 
				
			||||||
 | 
					export type { GetAllExpenseTagsResponse } from './models/GetAllExpenseTagsResponse';
 | 
				
			||||||
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';
 | 
				
			||||||
@@ -249,6 +254,8 @@ export type { TimeTrackingRecord } from './models/TimeTrackingRecord';
 | 
				
			|||||||
export type { UpdateExpenseRequest } from './models/UpdateExpenseRequest';
 | 
					export type { UpdateExpenseRequest } from './models/UpdateExpenseRequest';
 | 
				
			||||||
export type { UpdateExpenseResponse } from './models/UpdateExpenseResponse';
 | 
					export type { UpdateExpenseResponse } from './models/UpdateExpenseResponse';
 | 
				
			||||||
export type { UpdateExpenseSchema } from './models/UpdateExpenseSchema';
 | 
					export type { UpdateExpenseSchema } from './models/UpdateExpenseSchema';
 | 
				
			||||||
 | 
					export type { UpdateExpenseTagRequest } from './models/UpdateExpenseTagRequest';
 | 
				
			||||||
 | 
					export type { UpdateExpenseTagResponse } from './models/UpdateExpenseTagResponse';
 | 
				
			||||||
export type { UpdateMarketplaceRequest } from './models/UpdateMarketplaceRequest';
 | 
					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';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								src/client/models/BaseExpenseTagSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/BaseExpenseTagSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type BaseExpenseTagSchema = {
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/CreateExpenseTagRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/CreateExpenseTagRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { BaseExpenseTagSchema } from './BaseExpenseTagSchema';
 | 
				
			||||||
 | 
					export type CreateExpenseTagRequest = {
 | 
				
			||||||
 | 
					    tag: BaseExpenseTagSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/DeleteExpenseTagResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DeleteExpenseTagResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DeleteExpenseTagResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ExpenseTagSchema } from './ExpenseTagSchema';
 | 
				
			||||||
import type { UserSchema } from './UserSchema';
 | 
					import type { UserSchema } from './UserSchema';
 | 
				
			||||||
export type ExpenseSchemaBase = {
 | 
					export type ExpenseSchemaBase = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
@@ -10,5 +11,6 @@ export type ExpenseSchemaBase = {
 | 
				
			|||||||
    amount: number;
 | 
					    amount: number;
 | 
				
			||||||
    createdByUser: UserSchema;
 | 
					    createdByUser: UserSchema;
 | 
				
			||||||
    spentDate: string;
 | 
					    spentDate: string;
 | 
				
			||||||
 | 
					    tags: Array<ExpenseTagSchema>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/ExpenseTagSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ExpenseTagSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type ExpenseTagSchema = {
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/GetAllExpenseTagsResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/GetAllExpenseTagsResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ExpenseTagSchema } from './ExpenseTagSchema';
 | 
				
			||||||
 | 
					export type GetAllExpenseTagsResponse = {
 | 
				
			||||||
 | 
					    tags: Array<ExpenseTagSchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
export type PaginationInfoSchema = {
 | 
					export type PaginationInfoSchema = {
 | 
				
			||||||
    totalPages: number;
 | 
					    totalPages?: number;
 | 
				
			||||||
    totalItems: number;
 | 
					    totalItems?: number;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,5 +8,6 @@ export type UpdateExpenseSchema = {
 | 
				
			|||||||
    comment?: (string | null);
 | 
					    comment?: (string | null);
 | 
				
			||||||
    amount: number;
 | 
					    amount: number;
 | 
				
			||||||
    spentDate: string;
 | 
					    spentDate: string;
 | 
				
			||||||
 | 
					    tags?: Array<string>;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateExpenseTagRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateExpenseTagRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ExpenseTagSchema } from './ExpenseTagSchema';
 | 
				
			||||||
 | 
					export type UpdateExpenseTagRequest = {
 | 
				
			||||||
 | 
					    tag: ExpenseTagSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateExpenseTagResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateExpenseTagResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateExpenseTagResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,10 +2,15 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { CreateExpenseTagRequest } from '../models/CreateExpenseTagRequest';
 | 
				
			||||||
import type { DeleteExpenseResponse } from '../models/DeleteExpenseResponse';
 | 
					import type { DeleteExpenseResponse } from '../models/DeleteExpenseResponse';
 | 
				
			||||||
 | 
					import type { DeleteExpenseTagResponse } from '../models/DeleteExpenseTagResponse';
 | 
				
			||||||
import type { GetAllExpensesResponse } from '../models/GetAllExpensesResponse';
 | 
					import type { GetAllExpensesResponse } from '../models/GetAllExpensesResponse';
 | 
				
			||||||
 | 
					import type { GetAllExpenseTagsResponse } from '../models/GetAllExpenseTagsResponse';
 | 
				
			||||||
import type { UpdateExpenseRequest } from '../models/UpdateExpenseRequest';
 | 
					import type { UpdateExpenseRequest } from '../models/UpdateExpenseRequest';
 | 
				
			||||||
import type { UpdateExpenseResponse } from '../models/UpdateExpenseResponse';
 | 
					import type { UpdateExpenseResponse } from '../models/UpdateExpenseResponse';
 | 
				
			||||||
 | 
					import type { UpdateExpenseTagRequest } from '../models/UpdateExpenseTagRequest';
 | 
				
			||||||
 | 
					import type { UpdateExpenseTagResponse } from '../models/UpdateExpenseTagResponse';
 | 
				
			||||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
import { OpenAPI } from '../core/OpenAPI';
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
import { request as __request } from '../core/request';
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
@@ -75,4 +80,76 @@ export class ExpenseService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All
 | 
				
			||||||
 | 
					     * @returns GetAllExpenseTagsResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllExpenseTags(): CancelablePromise<GetAllExpenseTagsResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/expense/get-all-tags',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Expense
 | 
				
			||||||
 | 
					     * @returns UpdateExpenseTagResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static createExpenseTag({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: CreateExpenseTagRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateExpenseTagResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/expense/create-tag',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Expense
 | 
				
			||||||
 | 
					     * @returns UpdateExpenseTagResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateExpenseTag({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdateExpenseTagRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateExpenseTagResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/expense/update-tag',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Expense
 | 
				
			||||||
 | 
					     * @returns DeleteExpenseTagResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static deleteExpenseTag({
 | 
				
			||||||
 | 
					        tagId,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        tagId: number,
 | 
				
			||||||
 | 
					    }): CancelablePromise<DeleteExpenseTagResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'DELETE',
 | 
				
			||||||
 | 
					            url: '/expense/delete-tag/{tag_id}',
 | 
				
			||||||
 | 
					            path: {
 | 
				
			||||||
 | 
					                'tag_id': tagId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
type Props<T> = {
 | 
					type Props<T, C = void> = {
 | 
				
			||||||
    onCreate: (element: T) => void;
 | 
					    onCreate: (element: T | C) => void;
 | 
				
			||||||
    onChange: (element: T) => void;
 | 
					    onChange: (element: T) => void;
 | 
				
			||||||
    onDelete: (element: T) => void;
 | 
					    onDelete: (element: T) => void;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useCRUD<T>(props: Props<T>) {
 | 
					export function useCRUD<T, C>(props: Props<T, C>) {
 | 
				
			||||||
    const onCreate = (element: T) => {
 | 
					    const onCreate = (element: T | C) => {
 | 
				
			||||||
        props.onCreate(element);
 | 
					        props.onCreate(element);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onChange = (element: T) => {
 | 
					    const onChange = (element: T) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFo
 | 
				
			|||||||
import ServicePriceCategoryForm from "../pages/ServicesPage/modals/ServicePriceCategoryForm.tsx";
 | 
					import ServicePriceCategoryForm from "../pages/ServicesPage/modals/ServicePriceCategoryForm.tsx";
 | 
				
			||||||
import ScanningModal from "./ScanningModal/ScanningModal.tsx";
 | 
					import ScanningModal from "./ScanningModal/ScanningModal.tsx";
 | 
				
			||||||
import ExpenseFormModal from "../pages/AdminPage/tabs/Expenses/modals/ExpenseFormModal.tsx";
 | 
					import ExpenseFormModal from "../pages/AdminPage/tabs/Expenses/modals/ExpenseFormModal.tsx";
 | 
				
			||||||
 | 
					import ExpenseTagsModal from "../pages/AdminPage/tabs/Expenses/modals/ExpenseTagsModal.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const modals = {
 | 
					export const modals = {
 | 
				
			||||||
    enterDeadline: EnterDeadlineModal,
 | 
					    enterDeadline: EnterDeadlineModal,
 | 
				
			||||||
@@ -50,4 +51,5 @@ export const modals = {
 | 
				
			|||||||
    servicePriceCategoryForm: ServicePriceCategoryForm,
 | 
					    servicePriceCategoryForm: ServicePriceCategoryForm,
 | 
				
			||||||
    scanningModal: ScanningModal,
 | 
					    scanningModal: ScanningModal,
 | 
				
			||||||
    expenseFormModal: ExpenseFormModal,
 | 
					    expenseFormModal: ExpenseFormModal,
 | 
				
			||||||
 | 
					    expenseTagsModal: ExpenseTagsModal,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/pages/AdminPage/hooks/useExpenseTagsList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/pages/AdminPage/hooks/useExpenseTagsList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					import ObjectList from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					import { ExpenseService } from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useExpenseTagsList = () =>
 | 
				
			||||||
 | 
					    ObjectList({
 | 
				
			||||||
 | 
					        queryFn: ExpenseService.getAllExpenseTags,
 | 
				
			||||||
 | 
					        getObjectsFn: response => response.tags,
 | 
				
			||||||
 | 
					        queryKey: "getAllExpenseTags",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					export default useExpenseTagsList;
 | 
				
			||||||
@@ -9,6 +9,7 @@ import { Pagination, Flex, rem, Button, Tooltip, ActionIcon } from "@mantine/cor
 | 
				
			|||||||
import { useEffect, useState } from "react";
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
					import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
import { MRT_TableOptions } from "mantine-react-table";
 | 
					import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { Expense } from "./types/Expense.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ExpensesTab = () => {
 | 
					export const ExpensesTab = () => {
 | 
				
			||||||
@@ -22,11 +23,12 @@ export const ExpensesTab = () => {
 | 
				
			|||||||
    const columns = useExpensesTableColumns();
 | 
					    const columns = useExpensesTableColumns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (!paginationInfo) return;
 | 
					        if (!paginationInfo ) return;
 | 
				
			||||||
        setTotalPages(paginationInfo.totalPages);
 | 
					        if (!paginationInfo.totalPages) setTotalPages(0);
 | 
				
			||||||
 | 
					        else setTotalPages(paginationInfo.totalPages);
 | 
				
			||||||
    }, [paginationInfo]);
 | 
					    }, [paginationInfo]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onUpdate = (expense: ExpenseSchemaBase) => {
 | 
					    const onUpdate = (expense: Expense) => {
 | 
				
			||||||
        ExpenseService.updateExpense({
 | 
					        ExpenseService.updateExpense({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                expense: {
 | 
					                expense: {
 | 
				
			||||||
@@ -54,13 +56,14 @@ export const ExpensesTab = () => {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onEditClick = (expense: ExpenseSchemaBase) => {
 | 
					    const onEditClick = (expense: ExpenseSchemaBase) => {
 | 
				
			||||||
 | 
					        const expenseToEdit = { ...expense, tags: expense.tags.map(tag => tag.name) };
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: "expenseFormModal",
 | 
					            modal: "expenseFormModal",
 | 
				
			||||||
            title: "Редактирование записи о расходах",
 | 
					            title: "Редактирование записи о расходах",
 | 
				
			||||||
            withCloseButton: false,
 | 
					            withCloseButton: false,
 | 
				
			||||||
            innerProps: {
 | 
					            innerProps: {
 | 
				
			||||||
                onChange: event => onUpdate(event),
 | 
					                onChange: event => onUpdate(event),
 | 
				
			||||||
                element: expense,
 | 
					                element: expenseToEdit,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -76,6 +79,19 @@ export const ExpensesTab = () => {
 | 
				
			|||||||
            .catch(err => console.log(err));
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onTagChange = async () => {
 | 
				
			||||||
 | 
					        await refetch();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onTagsEditClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "expenseTagsModal",
 | 
				
			||||||
 | 
					            title: "Редактирование тегов",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: { onChange: onTagChange },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Flex
 | 
					        <Flex
 | 
				
			||||||
            direction={"column"}
 | 
					            direction={"column"}
 | 
				
			||||||
@@ -91,12 +107,17 @@ export const ExpensesTab = () => {
 | 
				
			|||||||
                        enableSorting: false,
 | 
					                        enableSorting: false,
 | 
				
			||||||
                        enableColumnActions: false,
 | 
					                        enableColumnActions: false,
 | 
				
			||||||
                        renderTopToolbar: (
 | 
					                        renderTopToolbar: (
 | 
				
			||||||
                            <Flex p={rem(10)}>
 | 
					                            <Flex p={rem(10)} gap={rem(10)}>
 | 
				
			||||||
                                <Button
 | 
					                                <Button
 | 
				
			||||||
                                    variant={"default"}
 | 
					                                    variant={"default"}
 | 
				
			||||||
                                    onClick={() => onCreateClick()}>
 | 
					                                    onClick={() => onCreateClick()}>
 | 
				
			||||||
                                    Создать запись о расходах
 | 
					                                    Создать запись о расходах
 | 
				
			||||||
                                </Button>
 | 
					                                </Button>
 | 
				
			||||||
 | 
					                                <Button
 | 
				
			||||||
 | 
					                                    variant={"default"}
 | 
				
			||||||
 | 
					                                    onClick={() => onTagsEditClick()}>
 | 
				
			||||||
 | 
					                                    Редактировать теги
 | 
				
			||||||
 | 
					                                </Button>
 | 
				
			||||||
                            </Flex>
 | 
					                            </Flex>
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                        renderRowActions: ({ row }) => (
 | 
					                        renderRowActions: ({ row }) => (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import { BaseExpenseTagSchema } from "../../../../../client";
 | 
				
			||||||
 | 
					import { Button, Stack, TextInput } from "@mantine/core";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					    onCreate: (tag: BaseExpenseTagSchema) => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CreateExpenseTagForm = ({ onCreate }: Props) => {
 | 
				
			||||||
 | 
					    const [expenseTag, setExpenseTag] = useState<string>("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onCreateClick = () => {
 | 
				
			||||||
 | 
					        if (expenseTag.length === 0) {
 | 
				
			||||||
 | 
					            notifications.error({ message: "Нельзя добавить тег без названия" });
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        onCreate({ name: expenseTag });
 | 
				
			||||||
 | 
					        setExpenseTag("");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Stack>
 | 
				
			||||||
 | 
					            <TextInput
 | 
				
			||||||
 | 
					                label={"Добавить тег"}
 | 
				
			||||||
 | 
					                value={expenseTag}
 | 
				
			||||||
 | 
					                onChange={event => setExpenseTag(event.target.value)}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            <Button
 | 
				
			||||||
 | 
					                variant={"default"}
 | 
				
			||||||
 | 
					                onClick={onCreateClick}>
 | 
				
			||||||
 | 
					                Добавить
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					        </Stack>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CreateExpenseTagForm;
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { TagsInput, TagsInputProps } from "@mantine/core";
 | 
				
			||||||
 | 
					import useExpenseTagsList from "../../../hooks/useExpenseTagsList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<TagsInputProps, "data">;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ExpenseTagsInput = (props: Props) => {
 | 
				
			||||||
 | 
					    const { objects } = useExpenseTagsList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <TagsInput
 | 
				
			||||||
 | 
					            data={objects.map(object => object.name)}
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					            label={"Теги"}
 | 
				
			||||||
 | 
					            placeholder={"Выберите теги"}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ExpenseTagsInput;
 | 
				
			||||||
@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					import { CRUDTableProps } from "../../../../../types/CRUDTable.tsx";
 | 
				
			||||||
 | 
					import { BaseExpenseTagSchema, ExpenseTagSchema } from "../../../../../client";
 | 
				
			||||||
 | 
					import { FC, useState } from "react";
 | 
				
			||||||
 | 
					import { ActionIcon, Flex, Stack, Tooltip } from "@mantine/core";
 | 
				
			||||||
 | 
					import { IconCheck, IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
 | 
					import { useExpenseTagsTableColumns } from "../hooks/useExpenseTagsTableColumns.tsx";
 | 
				
			||||||
 | 
					import CreateExpenseTagForm from "./CreateExpenseTagForm.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CRUDTableProps<ExpenseTagSchema, BaseExpenseTagSchema>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ExpenseTagsTable: FC<Props> = ({ items, onCreate, onDelete, onChange }) => {
 | 
				
			||||||
 | 
					    const [editingTagId, setEditingTagId] = useState<number>(-1);
 | 
				
			||||||
 | 
					    const [tagName, setTagName] = useState<string>("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const columns = useExpenseTagsTableColumns({ editingTagId, setTagName });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onStartEditing = (tag: ExpenseTagSchema) => {
 | 
				
			||||||
 | 
					        setEditingTagId(tag.id);
 | 
				
			||||||
 | 
					        setTagName(tag.name);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onFinishEditing = (tag: ExpenseTagSchema) => {
 | 
				
			||||||
 | 
					        if (!onChange) return;
 | 
				
			||||||
 | 
					        if (tag.name !== tagName) {
 | 
				
			||||||
 | 
					            onChange({
 | 
				
			||||||
 | 
					                id: editingTagId,
 | 
				
			||||||
 | 
					                name: tagName,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setEditingTagId(-1);
 | 
				
			||||||
 | 
					        setTagName("");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Stack>
 | 
				
			||||||
 | 
					            <CreateExpenseTagForm onCreate={item => onCreate && onCreate(item)} />
 | 
				
			||||||
 | 
					            <BaseTable
 | 
				
			||||||
 | 
					                data={items}
 | 
				
			||||||
 | 
					                columns={columns}
 | 
				
			||||||
 | 
					                restProps={
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        enableRowActions: true,
 | 
				
			||||||
 | 
					                        enableSorting: false,
 | 
				
			||||||
 | 
					                        enableColumnActions: false,
 | 
				
			||||||
 | 
					                        renderRowActions: ({ row }) => (
 | 
				
			||||||
 | 
					                            <Flex gap="md">
 | 
				
			||||||
 | 
					                                <Tooltip label="Редактировать">
 | 
				
			||||||
 | 
					                                    {
 | 
				
			||||||
 | 
					                                        editingTagId === row.original.id ? (
 | 
				
			||||||
 | 
					                                            <ActionIcon
 | 
				
			||||||
 | 
					                                                onClick={() => onFinishEditing(row.original)}
 | 
				
			||||||
 | 
					                                                variant={"default"}>
 | 
				
			||||||
 | 
					                                                <IconCheck />
 | 
				
			||||||
 | 
					                                            </ActionIcon>
 | 
				
			||||||
 | 
					                                        ) : (
 | 
				
			||||||
 | 
					                                            <ActionIcon
 | 
				
			||||||
 | 
					                                                onClick={() => onStartEditing(row.original)}
 | 
				
			||||||
 | 
					                                                variant={"default"}>
 | 
				
			||||||
 | 
					                                                <IconEdit />
 | 
				
			||||||
 | 
					                                            </ActionIcon>
 | 
				
			||||||
 | 
					                                        )
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                </Tooltip>
 | 
				
			||||||
 | 
					                                <Tooltip label="Удалить">
 | 
				
			||||||
 | 
					                                    <ActionIcon
 | 
				
			||||||
 | 
					                                        onClick={() => onDelete && onDelete(row.original)}
 | 
				
			||||||
 | 
					                                        variant={"default"}>
 | 
				
			||||||
 | 
					                                        <IconTrash />
 | 
				
			||||||
 | 
					                                    </ActionIcon>
 | 
				
			||||||
 | 
					                                </Tooltip>
 | 
				
			||||||
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    } as MRT_TableOptions<ExpenseTagSchema>
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					        </Stack>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ExpenseTagsTable;
 | 
				
			||||||
@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import { useMemo } from "react";
 | 
				
			||||||
 | 
					import { MRT_ColumnDef } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { ExpenseTagSchema } from "../../../../../client";
 | 
				
			||||||
 | 
					import { TextInput } from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					    editingTagId: number;
 | 
				
			||||||
 | 
					    setTagName: (tagName: string) => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useExpenseTagsTableColumns = ({
 | 
				
			||||||
 | 
					                                               editingTagId, setTagName,
 | 
				
			||||||
 | 
					                                           }: Props) => {
 | 
				
			||||||
 | 
					    return useMemo<MRT_ColumnDef<ExpenseTagSchema>[]>(
 | 
				
			||||||
 | 
					        () => [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "name",
 | 
				
			||||||
 | 
					                header: "Наименование",
 | 
				
			||||||
 | 
					                Cell: ({ row }) => {
 | 
				
			||||||
 | 
					                    if (row.original.id === editingTagId) {
 | 
				
			||||||
 | 
					                        return (
 | 
				
			||||||
 | 
					                            <TextInput
 | 
				
			||||||
 | 
					                                defaultValue={row.original.name}
 | 
				
			||||||
 | 
					                                onChange={event => setTagName(event.target.value)}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        );
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return row.original.name;
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        [editingTagId],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -24,6 +24,11 @@ export const useExpensesTableColumns = () => {
 | 
				
			|||||||
                accessorKey: "amount",
 | 
					                accessorKey: "amount",
 | 
				
			||||||
                header: "Сумма",
 | 
					                header: "Сумма",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "tags",
 | 
				
			||||||
 | 
					                header: "Теги",
 | 
				
			||||||
 | 
					                Cell: ({ row }) => row.original.tags.map(tag => tag.name).join(", "),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                accessorKey: "createdByUser",
 | 
					                accessorKey: "createdByUser",
 | 
				
			||||||
                header: "Создал запись",
 | 
					                header: "Создал запись",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,11 @@ import { ContextModalProps } from "@mantine/modals";
 | 
				
			|||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { Flex, NumberInput, rem, TextInput } from "@mantine/core";
 | 
					import { Flex, NumberInput, rem, TextInput } from "@mantine/core";
 | 
				
			||||||
import BaseFormModal, { CreateEditFormProps } from "../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import { ExpenseSchemaBase } from "../../../../../client";
 | 
					 | 
				
			||||||
import { DatePickerInput } from "@mantine/dates";
 | 
					import { DatePickerInput } from "@mantine/dates";
 | 
				
			||||||
 | 
					import ExpenseTagsInput from "../components/ExpenseTagsInput.tsx";
 | 
				
			||||||
 | 
					import { Expense } from "../types/Expense.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = CreateEditFormProps<ExpenseSchemaBase>;
 | 
					type Props = CreateEditFormProps<Expense>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ExpenseFormModal = ({
 | 
					const ExpenseFormModal = ({
 | 
				
			||||||
                              context,
 | 
					                              context,
 | 
				
			||||||
@@ -13,11 +14,11 @@ const ExpenseFormModal = ({
 | 
				
			|||||||
                              innerProps,
 | 
					                              innerProps,
 | 
				
			||||||
                          }: ContextModalProps<Props>) => {
 | 
					                          }: ContextModalProps<Props>) => {
 | 
				
			||||||
    const isEditing = "element" in innerProps;
 | 
					    const isEditing = "element" in innerProps;
 | 
				
			||||||
    const initialValue: Partial<ExpenseSchemaBase> = isEditing
 | 
					    const initialValue: Partial<Expense> = isEditing
 | 
				
			||||||
        ? innerProps.element
 | 
					        ? innerProps.element
 | 
				
			||||||
        : {};
 | 
					        : {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const form = useForm<Partial<ExpenseSchemaBase>>({
 | 
					    const form = useForm<Partial<Expense>>({
 | 
				
			||||||
        initialValues: initialValue,
 | 
					        initialValues: initialValue,
 | 
				
			||||||
        validate: {
 | 
					        validate: {
 | 
				
			||||||
            name: name => !name && "Необходимо указать наименование",
 | 
					            name: name => !name && "Необходимо указать наименование",
 | 
				
			||||||
@@ -58,6 +59,9 @@ const ExpenseFormModal = ({
 | 
				
			|||||||
                        placeholder={"Укажите дату расхода"}
 | 
					                        placeholder={"Укажите дату расхода"}
 | 
				
			||||||
                        valueFormat={"DD.MM.YYYY"}
 | 
					                        valueFormat={"DD.MM.YYYY"}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
 | 
					                    <ExpenseTagsInput
 | 
				
			||||||
 | 
					                        {...form.getInputProps("tags")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
                </Flex>
 | 
					                </Flex>
 | 
				
			||||||
            </BaseFormModal.Body>
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
        </BaseFormModal>
 | 
					        </BaseFormModal>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { BaseExpenseTagSchema, ExpenseService, ExpenseTagSchema } from "../../../../../client";
 | 
				
			||||||
 | 
					import useExpenseTagsList from "../../../hooks/useExpenseTagsList.tsx";
 | 
				
			||||||
 | 
					import ExpenseTagsTable from "../components/ExpenseTagsTable.tsx";
 | 
				
			||||||
 | 
					import { useCRUD } from "../../../../../hooks/useCRUD.tsx";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = {
 | 
				
			||||||
 | 
					    onChange: () => Promise<void>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ExpenseTagsModal = ({
 | 
				
			||||||
 | 
					                              innerProps,
 | 
				
			||||||
 | 
					                          }: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					    const { onChange: onTagChange } = innerProps;
 | 
				
			||||||
 | 
					    const { objects: expenseTags, refetch } = useExpenseTagsList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const crud = useCRUD<ExpenseTagSchema, BaseExpenseTagSchema>({
 | 
				
			||||||
 | 
					        onChange: tag => {
 | 
				
			||||||
 | 
					            ExpenseService.updateExpenseTag({
 | 
				
			||||||
 | 
					                requestBody: {
 | 
				
			||||||
 | 
					                    tag,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					                .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                    notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                    if (!ok) return;
 | 
				
			||||||
 | 
					                    await refetch();
 | 
				
			||||||
 | 
					                    await onTagChange();
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .catch(err => console.log(err));
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onCreate: tag => {
 | 
				
			||||||
 | 
					            ExpenseService.createExpenseTag({
 | 
				
			||||||
 | 
					                requestBody: {
 | 
				
			||||||
 | 
					                    tag,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					                .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                    notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                    if (!ok) return;
 | 
				
			||||||
 | 
					                    await refetch();
 | 
				
			||||||
 | 
					                    await onTagChange();
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .catch(err => console.log(err));
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onDelete: (tag) => {
 | 
				
			||||||
 | 
					            ExpenseService.deleteExpenseTag({
 | 
				
			||||||
 | 
					                tagId: tag.id,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					                .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                    notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                    if (!ok) return;
 | 
				
			||||||
 | 
					                    await refetch();
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .catch(err => console.log(err));
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ExpenseTagsTable {...crud} items={expenseTags} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ExpenseTagsModal;
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/pages/AdminPage/tabs/Expenses/types/Expense.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/pages/AdminPage/tabs/Expenses/types/Expense.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import type { UserSchema } from "../../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Expense = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    comment: string;
 | 
				
			||||||
 | 
					    amount: number;
 | 
				
			||||||
 | 
					    createdByUser: UserSchema;
 | 
				
			||||||
 | 
					    spentDate: string;
 | 
				
			||||||
 | 
					    tags: Array<string>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					import useExpenseTagsList from "../../../AdminPage/hooks/useExpenseTagsList.tsx";
 | 
				
			||||||
 | 
					import { ExpenseTagSchema } from "../../../../client";
 | 
				
			||||||
 | 
					import ObjectSelect, { ObjectSelectProps } from "../../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<
 | 
				
			||||||
 | 
					    ObjectSelectProps<ExpenseTagSchema | null>,
 | 
				
			||||||
 | 
					    "data" | "getValueFn" | "getLabelFn"
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
 | 
					const ExpenseTagSelect: FC<Props> = props => {
 | 
				
			||||||
 | 
					    const { objects: tags } = useExpenseTagsList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ObjectSelect
 | 
				
			||||||
 | 
					            data={tags}
 | 
				
			||||||
 | 
					            getLabelFn={(tag: ExpenseTagSchema) => tag.name}
 | 
				
			||||||
 | 
					            getValueFn={(tag: ExpenseTagSchema) => tag.id.toString()}
 | 
				
			||||||
 | 
					            clearable
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					            onClear={() => props.onChange(null)}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export default ExpenseTagSelect;
 | 
				
			||||||
@@ -1,12 +1,15 @@
 | 
				
			|||||||
import { ProfitChart } from "./components/ProfitChart/ProfitChart.tsx";
 | 
					import { ProfitChart } from "./components/ProfitChart/ProfitChart.tsx";
 | 
				
			||||||
import styles from "../../ui/StatisticsPage.module.css";
 | 
					import styles from "../../ui/StatisticsPage.module.css";
 | 
				
			||||||
import { ProfitTable } from "./components/ProfitTable/ProfitTable.tsx";
 | 
					import { ProfitTable } from "./components/ProfitTable/ProfitTable.tsx";
 | 
				
			||||||
 | 
					import { ProfitTabContextProvider } from "./contexts/ProfitTabContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProfitTab = () => {
 | 
					export const ProfitTab = () => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 | 
					        <ProfitTabContextProvider>
 | 
				
			||||||
            <div className={styles["page-container"]}>
 | 
					            <div className={styles["page-container"]}>
 | 
				
			||||||
                <ProfitChart />
 | 
					                <ProfitChart />
 | 
				
			||||||
                <ProfitTable />
 | 
					                <ProfitTable />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					        </ProfitTabContextProvider>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { DatePickerInput, DatePickerInputProps } from "@mantine/dates";
 | 
					import { DatePickerInput, DatePickerInputProps } from "@mantine/dates";
 | 
				
			||||||
import { Stack, Text } from "@mantine/core";
 | 
					import { Divider, Stack, Text } from "@mantine/core";
 | 
				
			||||||
import ClientSelectNew from "../../../../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
 | 
					import ClientSelectNew from "../../../../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
 | 
				
			||||||
import { BaseMarketplaceSchema, ClientSchema, UserSchema } from "../../../../../../client";
 | 
					import { BaseMarketplaceSchema, ClientSchema, ExpenseTagSchema, UserSchema } from "../../../../../../client";
 | 
				
			||||||
import { ObjectSelectProps } from "../../../../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
					import { ObjectSelectProps } from "../../../../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
import BaseMarketplaceSelect
 | 
					import BaseMarketplaceSelect
 | 
				
			||||||
    from "../../../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
					    from "../../../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
				
			||||||
@@ -9,6 +9,7 @@ import DealStatusSelect from "../../../../../DealsPage/components/DealStatusSele
 | 
				
			|||||||
import { DealStatusType } from "../../../../../../shared/enums/DealStatus.ts";
 | 
					import { DealStatusType } from "../../../../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
import { ProfitTableSegmentedControl } from "../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
					import { ProfitTableSegmentedControl } from "../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
				
			||||||
import ManagerSelect from "../../../../../../components/ManagerSelect/ManagerSelect.tsx";
 | 
					import ManagerSelect from "../../../../../../components/ManagerSelect/ManagerSelect.tsx";
 | 
				
			||||||
 | 
					import ExpenseTagSelect from "../../../../components/ExpenseTagSelect/ExpenseTagSelect.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FiltersProps = {
 | 
					type FiltersProps = {
 | 
				
			||||||
@@ -32,6 +33,12 @@ type FiltersProps = {
 | 
				
			|||||||
    >;
 | 
					    >;
 | 
				
			||||||
    onManagerClear?: () => void;
 | 
					    onManagerClear?: () => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tagSelectProps?: Omit<
 | 
				
			||||||
 | 
					        ObjectSelectProps<ExpenseTagSchema | null>,
 | 
				
			||||||
 | 
					        "data" | "getValueFn" | "getLabelFn"
 | 
				
			||||||
 | 
					    >;
 | 
				
			||||||
 | 
					    onTagClear?: () => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    groupTableByProps?: {
 | 
					    groupTableByProps?: {
 | 
				
			||||||
        value: string,
 | 
					        value: string,
 | 
				
			||||||
        onChange: (value: string) => void,
 | 
					        onChange: (value: string) => void,
 | 
				
			||||||
@@ -49,11 +56,17 @@ export const Filters = (props: FiltersProps) => {
 | 
				
			|||||||
        onDealStatusClear,
 | 
					        onDealStatusClear,
 | 
				
			||||||
        managerSelectProps,
 | 
					        managerSelectProps,
 | 
				
			||||||
        onManagerClear,
 | 
					        onManagerClear,
 | 
				
			||||||
 | 
					        tagSelectProps,
 | 
				
			||||||
 | 
					        onTagClear,
 | 
				
			||||||
        groupTableByProps,
 | 
					        groupTableByProps,
 | 
				
			||||||
    } = props;
 | 
					    } = props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Stack mb={"lg"}>
 | 
					        <Stack mb={"lg"}>
 | 
				
			||||||
 | 
					            <Divider />
 | 
				
			||||||
 | 
					            <Text>
 | 
				
			||||||
 | 
					                Фильтры для выручки и прибыли:
 | 
				
			||||||
 | 
					            </Text>
 | 
				
			||||||
            {datePickerProps &&
 | 
					            {datePickerProps &&
 | 
				
			||||||
                <DatePickerInput
 | 
					                <DatePickerInput
 | 
				
			||||||
                    {...datePickerProps}
 | 
					                    {...datePickerProps}
 | 
				
			||||||
@@ -95,9 +108,21 @@ export const Filters = (props: FiltersProps) => {
 | 
				
			|||||||
                    placeholder={"Выберите менеджера"}
 | 
					                    placeholder={"Выберите менеджера"}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            {tagSelectProps &&
 | 
				
			||||||
 | 
					                <>
 | 
				
			||||||
 | 
					                    <Divider />
 | 
				
			||||||
 | 
					                    <Text>Фильтры для расходов:</Text>
 | 
				
			||||||
 | 
					                    <ExpenseTagSelect
 | 
				
			||||||
 | 
					                        {...tagSelectProps}
 | 
				
			||||||
 | 
					                        onClear={onTagClear}
 | 
				
			||||||
 | 
					                        placeholder={"Выберите тег"}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            {groupTableByProps &&
 | 
					            {groupTableByProps &&
 | 
				
			||||||
                <>
 | 
					                <>
 | 
				
			||||||
                    <Text>Группировать:</Text>
 | 
					                    <Divider />
 | 
				
			||||||
 | 
					                    <Text>Группировка таблицы:</Text>
 | 
				
			||||||
                    <ProfitTableSegmentedControl
 | 
					                    <ProfitTableSegmentedControl
 | 
				
			||||||
                        {...groupTableByProps}
 | 
					                        {...groupTableByProps}
 | 
				
			||||||
                        orientation={"vertical"}
 | 
					                        orientation={"vertical"}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,18 @@
 | 
				
			|||||||
import { AreaChart } from "@mantine/charts";
 | 
					import { AreaChart } from "@mantine/charts";
 | 
				
			||||||
import "@mantine/charts/styles.css";
 | 
					import "@mantine/charts/styles.css";
 | 
				
			||||||
import PageBlock from "../../../../../../components/PageBlock/PageBlock.tsx";
 | 
					import PageBlock from "../../../../../../components/PageBlock/PageBlock.tsx";
 | 
				
			||||||
import { useProfitChart } from "./hooks/useProfitChart.tsx";
 | 
					 | 
				
			||||||
import { Skeleton, Stack } from "@mantine/core";
 | 
					import { Skeleton, Stack } from "@mantine/core";
 | 
				
			||||||
import { ProfitChartFiltersModal } from "../../modals/ProfitChartFiltersModal.tsx";
 | 
					 | 
				
			||||||
import { Total } from "../Total/Total.tsx";
 | 
					import { Total } from "../Total/Total.tsx";
 | 
				
			||||||
import styles from "../../../../ui/StatisticsPage.module.css";
 | 
					import styles from "../../../../ui/StatisticsPage.module.css";
 | 
				
			||||||
import { formatDate } from "../../../../../../types/utils.ts";
 | 
					import { formatDate } from "../../../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import { useProfitTabContext } from "../../contexts/ProfitTabContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProfitChart = () => {
 | 
					export const ProfitChart = () => {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        profitData,
 | 
					        profitChartData: profitData,
 | 
				
			||||||
        form,
 | 
					        isChartLoading: isLoading,
 | 
				
			||||||
        isLoading,
 | 
					    } = useProfitTabContext();
 | 
				
			||||||
    } = useProfitChart();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const formattedProfitData = profitData.map(
 | 
					    const formattedProfitData = profitData.map(
 | 
				
			||||||
        value => {
 | 
					        value => {
 | 
				
			||||||
@@ -35,17 +33,14 @@ export const ProfitChart = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const units = ["₽", "шт"];
 | 
					    const units = ["₽", "шт"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const chartSizes = ["42vh", "28vh"];
 | 
					    const chartSizes = ["47vh", "28vh"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={styles["profit-chart-container"]}>
 | 
					        <div className={styles["profit-chart-container"]}>
 | 
				
			||||||
            <Total profitData={profitData} />
 | 
					            <Total profitData={profitData} />
 | 
				
			||||||
            <PageBlock style={{ padding: "25px" }}>
 | 
					            <PageBlock style={{ padding: "25px" }}>
 | 
				
			||||||
                <ProfitChartFiltersModal
 | 
					 | 
				
			||||||
                    form={form}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
                <Skeleton visible={isLoading}>
 | 
					                <Skeleton visible={isLoading}>
 | 
				
			||||||
                    <Stack gap="20px">
 | 
					                    <Stack gap="4vh">
 | 
				
			||||||
                        {getChartsSeries.map((series, idx) => {
 | 
					                        {getChartsSeries.map((series, idx) => {
 | 
				
			||||||
                            return (
 | 
					                            return (
 | 
				
			||||||
                                <AreaChart
 | 
					                                <AreaChart
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,63 +0,0 @@
 | 
				
			|||||||
import { ChartFormFilters } from "../../../../../types/ChartFormFilters.ts";
 | 
					 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					 | 
				
			||||||
import { getDefaultDates } from "../../../../../utils/dates.ts";
 | 
					 | 
				
			||||||
import { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import { ProfitChartDataItem, StatisticsService } from "../../../../../../../client";
 | 
					 | 
				
			||||||
import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
					 | 
				
			||||||
import { dateToString } from "../../../../../../../types/utils.ts";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useProfitChart = () => {
 | 
					 | 
				
			||||||
    const form = useForm<ChartFormFilters>({
 | 
					 | 
				
			||||||
        mode: "controlled",
 | 
					 | 
				
			||||||
        initialValues: {
 | 
					 | 
				
			||||||
            dateRange: getDefaultDates(),
 | 
					 | 
				
			||||||
            client: null,
 | 
					 | 
				
			||||||
            marketplace: null,
 | 
					 | 
				
			||||||
            dealStatus: defaultDealStatus,
 | 
					 | 
				
			||||||
            manager: null,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    const [profitData, setProfitData] = useState<ProfitChartDataItem[]>([]);
 | 
					 | 
				
			||||||
    const [isLoading, setIsLoading] = useState(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const getFilters = () => {
 | 
					 | 
				
			||||||
        const dateRange = form.values.dateRange;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            dateRange: [
 | 
					 | 
				
			||||||
                dateToString(dateRange[0]),
 | 
					 | 
				
			||||||
                dateToString(dateRange[1]),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            clientId: form.values.client?.id ?? -1,
 | 
					 | 
				
			||||||
            baseMarketplaceKey: form.values.marketplace?.key ?? "all",
 | 
					 | 
				
			||||||
            dealStatusId: form.values.dealStatus?.id ?? -1,
 | 
					 | 
				
			||||||
            managerId: form.values.manager?.id ?? -1,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const fetchProfitData = () => {
 | 
					 | 
				
			||||||
        setIsLoading(true);
 | 
					 | 
				
			||||||
        StatisticsService.getProfitChartData({
 | 
					 | 
				
			||||||
            requestBody: getFilters(),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
            .then(res => {
 | 
					 | 
				
			||||||
                setProfitData(res.data);
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .catch(err => console.log(err))
 | 
					 | 
				
			||||||
            .finally(() => setIsLoading(false));
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(() => {
 | 
					 | 
				
			||||||
        if (form.values.dateRange.length < 2 || form.values.dateRange[1] === null) {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        fetchProfitData();
 | 
					 | 
				
			||||||
    }, [form.values]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        profitData,
 | 
					 | 
				
			||||||
        form,
 | 
					 | 
				
			||||||
        isLoading,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -2,7 +2,7 @@ import PageBlock from "../../../../../../components/PageBlock/PageBlock.tsx";
 | 
				
			|||||||
import { MantineReactTable } from "mantine-react-table";
 | 
					import { MantineReactTable } from "mantine-react-table";
 | 
				
			||||||
import { useProfitTable } from "./hooks/useProfitTable.tsx";
 | 
					import { useProfitTable } from "./hooks/useProfitTable.tsx";
 | 
				
			||||||
import { Skeleton } from "@mantine/core";
 | 
					import { Skeleton } from "@mantine/core";
 | 
				
			||||||
import { ProfitTableFiltersModal } from "../../modals/ProfitTableFiltersModal.tsx";
 | 
					import { ProfitFiltersModal } from "../../modals/ProfitFiltersModal.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProfitTable = () => {
 | 
					export const ProfitTable = () => {
 | 
				
			||||||
@@ -10,7 +10,7 @@ export const ProfitTable = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <PageBlock style={{ flex: 2, minWidth: "600px", padding: "25px" }}>
 | 
					        <PageBlock style={{ flex: 2, minWidth: "600px", padding: "25px" }}>
 | 
				
			||||||
            <ProfitTableFiltersModal form={form} />
 | 
					            <ProfitFiltersModal form={form} />
 | 
				
			||||||
            <Skeleton visible={isLoading}>
 | 
					            <Skeleton visible={isLoading}>
 | 
				
			||||||
                <MantineReactTable table={table} />
 | 
					                <MantineReactTable table={table} />
 | 
				
			||||||
            </Skeleton>
 | 
					            </Skeleton>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
import { GroupStatisticsTable } from "../../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
					 | 
				
			||||||
import { useProfitTableColumns } from "./columns.tsx";
 | 
					 | 
				
			||||||
import { useMantineReactTable } from "mantine-react-table";
 | 
					 | 
				
			||||||
import { ProfitTableDataItem } from "../../../../../../../client";
 | 
					 | 
				
			||||||
import { MRT_Localization_RU } from "mantine-react-table/locales/ru/index.cjs";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Props = {
 | 
					 | 
				
			||||||
    groupTableBy: GroupStatisticsTable;
 | 
					 | 
				
			||||||
    profitData: ProfitTableDataItem[];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const useProfitMantineTable = ({ groupTableBy, profitData }: Props) => {
 | 
					 | 
				
			||||||
    const columns = useProfitTableColumns({
 | 
					 | 
				
			||||||
        groupTableBy,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const defaultSorting = [{ id: "groupedValue", desc: true }];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const table = useMantineReactTable({
 | 
					 | 
				
			||||||
        enablePagination: false,
 | 
					 | 
				
			||||||
        data: profitData,
 | 
					 | 
				
			||||||
        columns,
 | 
					 | 
				
			||||||
        enableTopToolbar: false,
 | 
					 | 
				
			||||||
        enableBottomToolbar: false,
 | 
					 | 
				
			||||||
        enableSorting: true,
 | 
					 | 
				
			||||||
        initialState: {
 | 
					 | 
				
			||||||
            sorting: defaultSorting,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        localization: MRT_Localization_RU,
 | 
					 | 
				
			||||||
        enableRowVirtualization: true,
 | 
					 | 
				
			||||||
        mantineTableContainerProps: { style: { maxHeight: "86vh" } },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return { table };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,69 +1,36 @@
 | 
				
			|||||||
import { useForm } from "@mantine/form";
 | 
					import { useProfitTabContext } from "../../../contexts/ProfitTabContext.tsx";
 | 
				
			||||||
import { TableFormFilters } from "../../../../../types/TableFormFilters.ts";
 | 
					import { useProfitTableColumns } from "./columns.tsx";
 | 
				
			||||||
import { getDefaultDates } from "../../../../../utils/dates.ts";
 | 
					import { useMantineReactTable } from "mantine-react-table";
 | 
				
			||||||
import { GroupStatisticsTable } from "../../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
					import { MRT_Localization_RU } from "mantine-react-table/locales/ru/index.cjs";
 | 
				
			||||||
import { useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import { ProfitTableDataItem, StatisticsService } from "../../../../../../../client";
 | 
					 | 
				
			||||||
import { useProfitMantineTable } from "./useProfitMantineTable.tsx";
 | 
					 | 
				
			||||||
import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
					 | 
				
			||||||
import { dateToString } from "../../../../../../../types/utils.ts";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useProfitTable = () => {
 | 
					export const useProfitTable = () => {
 | 
				
			||||||
    const form = useForm<TableFormFilters>({
 | 
					    const {
 | 
				
			||||||
        mode: "controlled",
 | 
					        form,
 | 
				
			||||||
        initialValues: {
 | 
					        isTableLoading: isLoading,
 | 
				
			||||||
            dateRange: getDefaultDates(),
 | 
					        profitTableData
 | 
				
			||||||
            groupTableBy: GroupStatisticsTable.BY_DATES,
 | 
					    } = useProfitTabContext();
 | 
				
			||||||
            client: null,
 | 
					
 | 
				
			||||||
            marketplace: null,
 | 
					    const columns = useProfitTableColumns({
 | 
				
			||||||
            dealStatus: defaultDealStatus,
 | 
					        groupTableBy: form.values.groupTableBy,
 | 
				
			||||||
            manager: null,
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const defaultSorting = [{ id: "groupedValue", desc: true }];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const table = useMantineReactTable({
 | 
				
			||||||
 | 
					        enablePagination: false,
 | 
				
			||||||
 | 
					        data: profitTableData,
 | 
				
			||||||
 | 
					        columns,
 | 
				
			||||||
 | 
					        enableTopToolbar: false,
 | 
				
			||||||
 | 
					        enableBottomToolbar: false,
 | 
				
			||||||
 | 
					        enableSorting: true,
 | 
				
			||||||
 | 
					        initialState: {
 | 
				
			||||||
 | 
					            sorting: defaultSorting,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        localization: MRT_Localization_RU,
 | 
				
			||||||
 | 
					        enableRowVirtualization: true,
 | 
				
			||||||
 | 
					        mantineTableContainerProps: { style: { maxHeight: "86vh" } },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    const [isLoading, setIsLoading] = useState(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const [profitData, setProfitData] = useState<ProfitTableDataItem[]>([]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { table } = useProfitMantineTable({
 | 
					 | 
				
			||||||
        groupTableBy: form.values.groupTableBy,
 | 
					 | 
				
			||||||
        profitData,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const getFilters = () => {
 | 
					 | 
				
			||||||
        const dateRange = form.values.dateRange;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            dateRange: [
 | 
					 | 
				
			||||||
                dateToString(dateRange[0]),
 | 
					 | 
				
			||||||
                dateToString(dateRange[1]),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            groupTableBy: form.values.groupTableBy,
 | 
					 | 
				
			||||||
            clientId: form.values.client?.id ?? -1,
 | 
					 | 
				
			||||||
            baseMarketplaceKey: form.values.marketplace?.key ?? "all",
 | 
					 | 
				
			||||||
            dealStatusId: form.values.dealStatus?.id ?? -1,
 | 
					 | 
				
			||||||
            managerId: form.values.manager?.id ?? -1,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const fetchProfitData = () => {
 | 
					 | 
				
			||||||
        setIsLoading(true);
 | 
					 | 
				
			||||||
        StatisticsService.getProfitTableData({
 | 
					 | 
				
			||||||
            requestBody: getFilters(),
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
            .then(res => {
 | 
					 | 
				
			||||||
                setProfitData(res.data);
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .catch(err => console.log(err))
 | 
					 | 
				
			||||||
            .finally(() => setIsLoading(false));
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    useEffect(() => {
 | 
					 | 
				
			||||||
        if (form.values.dateRange.length < 2 || form.values.dateRange[1] === null) {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        fetchProfitData();
 | 
					 | 
				
			||||||
    }, [form.values]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        table,
 | 
					        table,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					import { createContext, FC, useContext, useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { ProfitChartDataItem, ProfitTableDataItem, StatisticsService } from "../../../../../client";
 | 
				
			||||||
 | 
					import { useForm, UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
 | 
					import { FormFilters } from "../../../types/FormFilters.ts";
 | 
				
			||||||
 | 
					import { getDefaultDates } from "../../../utils/dates.ts";
 | 
				
			||||||
 | 
					import { GroupStatisticsTable } from "../components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
				
			||||||
 | 
					import { defaultDealStatus } from "../../../utils/defaultFilterValues.ts";
 | 
				
			||||||
 | 
					import { dateToString } from "../../../../../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProfitTabContextState = {
 | 
				
			||||||
 | 
					    form: UseFormReturnType<FormFilters, (values: FormFilters) => FormFilters>;
 | 
				
			||||||
 | 
					    isChartLoading: boolean;
 | 
				
			||||||
 | 
					    isTableLoading: boolean;
 | 
				
			||||||
 | 
					    profitChartData: ProfitChartDataItem[];
 | 
				
			||||||
 | 
					    profitTableData: ProfitTableDataItem[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ProfitTabContext = createContext<ProfitTabContextState | undefined>(
 | 
				
			||||||
 | 
					    undefined,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useProfitTabContextState = () => {
 | 
				
			||||||
 | 
					    const form = useForm<FormFilters>({
 | 
				
			||||||
 | 
					        mode: "controlled",
 | 
				
			||||||
 | 
					        initialValues: {
 | 
				
			||||||
 | 
					            dateRange: getDefaultDates(),
 | 
				
			||||||
 | 
					            groupTableBy: GroupStatisticsTable.BY_DATES,
 | 
				
			||||||
 | 
					            client: null,
 | 
				
			||||||
 | 
					            marketplace: null,
 | 
				
			||||||
 | 
					            dealStatus: defaultDealStatus,
 | 
				
			||||||
 | 
					            manager: null,
 | 
				
			||||||
 | 
					            tag: null,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const [isChartLoading, setIsChartLoading] = useState(false);
 | 
				
			||||||
 | 
					    const [isTableLoading, setIsTableLoading] = useState(false);
 | 
				
			||||||
 | 
					    const [profitChartData, setProfitChartData] = useState<ProfitChartDataItem[]>([]);
 | 
				
			||||||
 | 
					    const [profitTableData, setProfitTableData] = useState<ProfitTableDataItem[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getChartFilters = () => {
 | 
				
			||||||
 | 
					        const dateRange = form.values.dateRange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            dateRange: [
 | 
				
			||||||
 | 
					                dateToString(dateRange[0]),
 | 
				
			||||||
 | 
					                dateToString(dateRange[1]),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            clientId: form.values.client?.id ?? -1,
 | 
				
			||||||
 | 
					            baseMarketplaceKey: form.values.marketplace?.key ?? "all",
 | 
				
			||||||
 | 
					            dealStatusId: form.values.dealStatus?.id ?? -1,
 | 
				
			||||||
 | 
					            managerId: form.values.manager?.id ?? -1,
 | 
				
			||||||
 | 
					            tagId: form.values.tag?.id ?? -1,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const fetchChartProfitData = () => {
 | 
				
			||||||
 | 
					        setIsChartLoading(true);
 | 
				
			||||||
 | 
					        StatisticsService.getProfitChartData({
 | 
				
			||||||
 | 
					            requestBody: getChartFilters(),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                setProfitChartData(res.data);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err))
 | 
				
			||||||
 | 
					            .finally(() => setIsChartLoading(false));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getTableFilters = () => {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            ...getChartFilters(),
 | 
				
			||||||
 | 
					            groupTableBy: form.values.groupTableBy,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const fetchTableProfitData = () => {
 | 
				
			||||||
 | 
					        setIsTableLoading(true);
 | 
				
			||||||
 | 
					        StatisticsService.getProfitTableData({
 | 
				
			||||||
 | 
					            requestBody: getTableFilters(),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                setProfitTableData(res.data);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err))
 | 
				
			||||||
 | 
					            .finally(() => setIsTableLoading(false));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (form.values.dateRange.length < 2 || form.values.dateRange[1] === null) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fetchChartProfitData();
 | 
				
			||||||
 | 
					        fetchTableProfitData();
 | 
				
			||||||
 | 
					    }, [form.values]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        form,
 | 
				
			||||||
 | 
					        isChartLoading,
 | 
				
			||||||
 | 
					        isTableLoading,
 | 
				
			||||||
 | 
					        profitChartData,
 | 
				
			||||||
 | 
					        profitTableData,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProfitTabContextProviderProps = {
 | 
				
			||||||
 | 
					    children: React.ReactNode;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ProfitTabContextProvider: FC<ProfitTabContextProviderProps> = ({ children }) => {
 | 
				
			||||||
 | 
					    const state = useProfitTabContextState();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ProfitTabContext.Provider value={state}>
 | 
				
			||||||
 | 
					            {children}
 | 
				
			||||||
 | 
					        </ProfitTabContext.Provider>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useProfitTabContext = () => {
 | 
				
			||||||
 | 
					    const context = useContext(ProfitTabContext);
 | 
				
			||||||
 | 
					    if (!context) {
 | 
				
			||||||
 | 
					        throw new Error(
 | 
				
			||||||
 | 
					            "useProfitTabContext must be used within a ProfitTabContextProvider",
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return context;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -1,47 +0,0 @@
 | 
				
			|||||||
import { Button, Group, Modal } from "@mantine/core";
 | 
					 | 
				
			||||||
import { IconFilter } from "@tabler/icons-react";
 | 
					 | 
				
			||||||
import { Filters } from "../components/Filters/Filters.tsx";
 | 
					 | 
				
			||||||
import { UseFormReturnType } from "@mantine/form";
 | 
					 | 
				
			||||||
import { useDisclosure } from "@mantine/hooks";
 | 
					 | 
				
			||||||
import { ChartFormFilters } from "../../../types/ChartFormFilters.ts";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Props = {
 | 
					 | 
				
			||||||
    form: UseFormReturnType<ChartFormFilters>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const ProfitChartFiltersModal = ({ form }: Props) => {
 | 
					 | 
				
			||||||
    const [opened, { open, close }] = useDisclosure();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
            <Button
 | 
					 | 
				
			||||||
                variant={"default"}
 | 
					 | 
				
			||||||
                onClick={open}
 | 
					 | 
				
			||||||
                mb={"lg"}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
                <Group gap={"xs"}>
 | 
					 | 
				
			||||||
                    <IconFilter />
 | 
					 | 
				
			||||||
                    Фильтры графиков
 | 
					 | 
				
			||||||
                </Group>
 | 
					 | 
				
			||||||
            </Button>
 | 
					 | 
				
			||||||
            <Modal
 | 
					 | 
				
			||||||
                opened={opened}
 | 
					 | 
				
			||||||
                onClose={close}
 | 
					 | 
				
			||||||
                title={"Фильтры графиков"}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
                <Filters
 | 
					 | 
				
			||||||
                    datePickerProps={form.getInputProps("dateRange")}
 | 
					 | 
				
			||||||
                    clientSelectProps={form.getInputProps("client")}
 | 
					 | 
				
			||||||
                    onClientClear={() => form.setFieldValue("client", null)}
 | 
					 | 
				
			||||||
                    baseMarketplaceSelectProps={form.getInputProps("marketplace")}
 | 
					 | 
				
			||||||
                    onBaseMarketplaceClear={() => form.setFieldValue("marketplace", null)}
 | 
					 | 
				
			||||||
                    dealStatusSelectProps={form.getInputProps("dealStatus")}
 | 
					 | 
				
			||||||
                    onDealStatusClear={() => form.setFieldValue("dealStatus", null)}
 | 
					 | 
				
			||||||
                    managerSelectProps={form.getInputProps("manager")}
 | 
					 | 
				
			||||||
                    onManagerClear={() => form.setFieldValue("manager", null)}
 | 
					 | 
				
			||||||
                />
 | 
					 | 
				
			||||||
            </Modal>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
import { Button, Group, Modal } from "@mantine/core";
 | 
					import { Button, Group, Modal } from "@mantine/core";
 | 
				
			||||||
import { IconFilter } from "@tabler/icons-react";
 | 
					import { IconFilter } from "@tabler/icons-react";
 | 
				
			||||||
import { Filters } from "../components/Filters/Filters.tsx";
 | 
					import { Filters } from "../components/Filters/Filters.tsx";
 | 
				
			||||||
import { TableFormFilters } from "../../../types/TableFormFilters.ts";
 | 
					import { FormFilters } from "../../../types/FormFilters.ts";
 | 
				
			||||||
import { UseFormReturnType } from "@mantine/form";
 | 
					import { UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
import { useDisclosure } from "@mantine/hooks";
 | 
					import { useDisclosure } from "@mantine/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    form: UseFormReturnType<TableFormFilters>;
 | 
					    form: UseFormReturnType<FormFilters>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProfitTableFiltersModal = ({ form }: Props) => {
 | 
					export const ProfitFiltersModal = ({ form }: Props) => {
 | 
				
			||||||
    const [opened, { open, close }] = useDisclosure();
 | 
					    const [opened, { open, close }] = useDisclosure();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
@@ -22,13 +22,13 @@ export const ProfitTableFiltersModal = ({ form }: Props) => {
 | 
				
			|||||||
            >
 | 
					            >
 | 
				
			||||||
                <Group gap={"xs"}>
 | 
					                <Group gap={"xs"}>
 | 
				
			||||||
                    <IconFilter />
 | 
					                    <IconFilter />
 | 
				
			||||||
                    Фильтры таблицы
 | 
					                    Фильтры
 | 
				
			||||||
                </Group>
 | 
					                </Group>
 | 
				
			||||||
            </Button>
 | 
					            </Button>
 | 
				
			||||||
            <Modal
 | 
					            <Modal
 | 
				
			||||||
                opened={opened}
 | 
					                opened={opened}
 | 
				
			||||||
                onClose={close}
 | 
					                onClose={close}
 | 
				
			||||||
                title={"Фильтры таблицы"}
 | 
					                title={"Фильтры"}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                <Filters
 | 
					                <Filters
 | 
				
			||||||
                    datePickerProps={form.getInputProps("dateRange")}
 | 
					                    datePickerProps={form.getInputProps("dateRange")}
 | 
				
			||||||
@@ -44,6 +44,8 @@ export const ProfitTableFiltersModal = ({ form }: Props) => {
 | 
				
			|||||||
                    onDealStatusClear={() => form.setFieldValue("dealStatus", null)}
 | 
					                    onDealStatusClear={() => form.setFieldValue("dealStatus", null)}
 | 
				
			||||||
                    managerSelectProps={form.getInputProps("manager")}
 | 
					                    managerSelectProps={form.getInputProps("manager")}
 | 
				
			||||||
                    onManagerClear={() => form.setFieldValue("manager", null)}
 | 
					                    onManagerClear={() => form.setFieldValue("manager", null)}
 | 
				
			||||||
 | 
					                    tagSelectProps={form.getInputProps("tag")}
 | 
				
			||||||
 | 
					                    onTagClear={() => form.setFieldValue("tag", null)}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </Modal>
 | 
					            </Modal>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
@@ -1,14 +1,15 @@
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    GroupStatisticsTable,
 | 
					    GroupStatisticsTable,
 | 
				
			||||||
} from "../tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
					} from "../tabs/ProfitTab/components/ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
				
			||||||
import { BaseMarketplaceSchema, ClientSchema, UserSchema } from "../../../client";
 | 
					import { BaseMarketplaceSchema, ClientSchema, ExpenseTagSchema, UserSchema } from "../../../client";
 | 
				
			||||||
import { DealStatusType } from "../../../shared/enums/DealStatus.ts";
 | 
					import { DealStatusType } from "../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface TableFormFilters {
 | 
					export interface FormFilters {
 | 
				
			||||||
    dateRange: [Date | null, Date | null];
 | 
					    dateRange: [Date | null, Date | null];
 | 
				
			||||||
    groupTableBy: GroupStatisticsTable;
 | 
					    groupTableBy: GroupStatisticsTable;
 | 
				
			||||||
    client: ClientSchema | null;
 | 
					    client: ClientSchema | null;
 | 
				
			||||||
    marketplace: BaseMarketplaceSchema | null;
 | 
					    marketplace: BaseMarketplaceSchema | null;
 | 
				
			||||||
    dealStatus: DealStatusType | null;
 | 
					    dealStatus: DealStatusType | null;
 | 
				
			||||||
    manager: UserSchema | null;
 | 
					    manager: UserSchema | null;
 | 
				
			||||||
 | 
					    tag: ExpenseTagSchema | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,9 +2,9 @@ import { RefObject } from "react";
 | 
				
			|||||||
import { BaseTableRef } from "../components/BaseTable/BaseTable.tsx";
 | 
					import { BaseTableRef } from "../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
import { MRT_RowData } from "mantine-react-table";
 | 
					import { MRT_RowData } from "mantine-react-table";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface CRUDTableProps<T extends MRT_RowData> {
 | 
					export interface CRUDTableProps<T extends MRT_RowData, C = void> {
 | 
				
			||||||
    items: T[];
 | 
					    items: T[];
 | 
				
			||||||
    onCreate?: (item: T) => void;
 | 
					    onCreate?: (item: C | T) => void;
 | 
				
			||||||
    onDelete?: (item: T) => void;
 | 
					    onDelete?: (item: T) => void;
 | 
				
			||||||
    onChange?: (item: T) => void;
 | 
					    onChange?: (item: T) => void;
 | 
				
			||||||
    onSelectionChange?: (selectedItems: T[]) => void;
 | 
					    onSelectionChange?: (selectedItems: T[]) => void;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user