feat: additional expenses
This commit is contained in:
		@@ -132,6 +132,7 @@ export type { DealUpdateServiceQuantityRequest } from './models/DealUpdateServic
 | 
				
			|||||||
export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse';
 | 
					export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse';
 | 
				
			||||||
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 { 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';
 | 
				
			||||||
@@ -145,12 +146,14 @@ export type { DeletePriceCategoryResponse } from './models/DeletePriceCategoryRe
 | 
				
			|||||||
export type { DeleteShiftResponse } from './models/DeleteShiftResponse';
 | 
					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 { 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';
 | 
				
			||||||
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
					export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
				
			||||||
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 { 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';
 | 
				
			||||||
@@ -243,6 +246,9 @@ export type { SynchronizeMarketplaceRequest } from './models/SynchronizeMarketpl
 | 
				
			|||||||
export type { TaskInfoResponse } from './models/TaskInfoResponse';
 | 
					export type { TaskInfoResponse } from './models/TaskInfoResponse';
 | 
				
			||||||
export type { TimeTrackingData } from './models/TimeTrackingData';
 | 
					export type { TimeTrackingData } from './models/TimeTrackingData';
 | 
				
			||||||
export type { TimeTrackingRecord } from './models/TimeTrackingRecord';
 | 
					export type { TimeTrackingRecord } from './models/TimeTrackingRecord';
 | 
				
			||||||
 | 
					export type { UpdateExpenseRequest } from './models/UpdateExpenseRequest';
 | 
				
			||||||
 | 
					export type { UpdateExpenseResponse } from './models/UpdateExpenseResponse';
 | 
				
			||||||
 | 
					export type { UpdateExpenseSchema } from './models/UpdateExpenseSchema';
 | 
				
			||||||
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';
 | 
				
			||||||
@@ -268,6 +274,7 @@ export { BarcodeService } from './services/BarcodeService';
 | 
				
			|||||||
export { BillingService } from './services/BillingService';
 | 
					export { BillingService } from './services/BillingService';
 | 
				
			||||||
export { ClientService } from './services/ClientService';
 | 
					export { ClientService } from './services/ClientService';
 | 
				
			||||||
export { DealService } from './services/DealService';
 | 
					export { DealService } from './services/DealService';
 | 
				
			||||||
 | 
					export { ExpenseService } from './services/ExpenseService';
 | 
				
			||||||
export { MarketplaceService } from './services/MarketplaceService';
 | 
					export { MarketplaceService } from './services/MarketplaceService';
 | 
				
			||||||
export { PayrollService } from './services/PayrollService';
 | 
					export { PayrollService } from './services/PayrollService';
 | 
				
			||||||
export { PositionService } from './services/PositionService';
 | 
					export { PositionService } from './services/PositionService';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/DeleteExpenseResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DeleteExpenseResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type DeleteExpenseResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/client/models/ExpenseSchemaBase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/client/models/ExpenseSchemaBase.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { UserSchema } from './UserSchema';
 | 
				
			||||||
 | 
					export type ExpenseSchemaBase = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    comment: string;
 | 
				
			||||||
 | 
					    amount: number;
 | 
				
			||||||
 | 
					    createdByUser: UserSchema;
 | 
				
			||||||
 | 
					    spentDate: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/client/models/GetAllExpensesResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/client/models/GetAllExpensesResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ExpenseSchemaBase } from './ExpenseSchemaBase';
 | 
				
			||||||
 | 
					import type { PaginationInfoSchema } from './PaginationInfoSchema';
 | 
				
			||||||
 | 
					export type GetAllExpensesResponse = {
 | 
				
			||||||
 | 
					    expenses: Array<ExpenseSchemaBase>;
 | 
				
			||||||
 | 
					    paginationInfo: PaginationInfoSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateExpenseRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateExpenseRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { UpdateExpenseSchema } from './UpdateExpenseSchema';
 | 
				
			||||||
 | 
					export type UpdateExpenseRequest = {
 | 
				
			||||||
 | 
					    expense: UpdateExpenseSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateExpenseResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateExpenseResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateExpenseResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/client/models/UpdateExpenseSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/client/models/UpdateExpenseSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateExpenseSchema = {
 | 
				
			||||||
 | 
					    id?: (number | null);
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    comment?: (string | null);
 | 
				
			||||||
 | 
					    amount: number;
 | 
				
			||||||
 | 
					    spentDate: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										78
									
								
								src/client/services/ExpenseService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/client/services/ExpenseService.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { DeleteExpenseResponse } from '../models/DeleteExpenseResponse';
 | 
				
			||||||
 | 
					import type { GetAllExpensesResponse } from '../models/GetAllExpensesResponse';
 | 
				
			||||||
 | 
					import type { UpdateExpenseRequest } from '../models/UpdateExpenseRequest';
 | 
				
			||||||
 | 
					import type { UpdateExpenseResponse } from '../models/UpdateExpenseResponse';
 | 
				
			||||||
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
 | 
					export class ExpenseService {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All
 | 
				
			||||||
 | 
					     * @returns GetAllExpensesResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllExpenses({
 | 
				
			||||||
 | 
					        page,
 | 
				
			||||||
 | 
					        itemsPerPage,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        page?: (number | null),
 | 
				
			||||||
 | 
					        itemsPerPage?: (number | null),
 | 
				
			||||||
 | 
					    }): CancelablePromise<GetAllExpensesResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/expense/get-all',
 | 
				
			||||||
 | 
					            query: {
 | 
				
			||||||
 | 
					                'page': page,
 | 
				
			||||||
 | 
					                'items_per_page': itemsPerPage,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Expense
 | 
				
			||||||
 | 
					     * @returns UpdateExpenseResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateExpense({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdateExpenseRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateExpenseResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/expense/update',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete Expense
 | 
				
			||||||
 | 
					     * @returns DeleteExpenseResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static deleteExpense({
 | 
				
			||||||
 | 
					        expenseId,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        expenseId: number,
 | 
				
			||||||
 | 
					    }): CancelablePromise<DeleteExpenseResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'DELETE',
 | 
				
			||||||
 | 
					            url: '/expense/delete/{expense_id}',
 | 
				
			||||||
 | 
					            path: {
 | 
				
			||||||
 | 
					                'expense_id': expenseId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -22,6 +22,7 @@ import ShippingWarehouseForm from "../pages/ShippingWarehousesPage/modals/Shippi
 | 
				
			|||||||
import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx";
 | 
					import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx";
 | 
				
			||||||
import ServicePriceCategoryForm from "../pages/ServicesPage/modals/ServicePriceCategoryForm.tsx";
 | 
					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";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const modals = {
 | 
					export const modals = {
 | 
				
			||||||
    enterDeadline: EnterDeadlineModal,
 | 
					    enterDeadline: EnterDeadlineModal,
 | 
				
			||||||
@@ -48,4 +49,5 @@ export const modals = {
 | 
				
			|||||||
    marketplaceFormModal: MarketplaceFormModal,
 | 
					    marketplaceFormModal: MarketplaceFormModal,
 | 
				
			||||||
    servicePriceCategoryForm: ServicePriceCategoryForm,
 | 
					    servicePriceCategoryForm: ServicePriceCategoryForm,
 | 
				
			||||||
    scanningModal: ScanningModal,
 | 
					    scanningModal: ScanningModal,
 | 
				
			||||||
 | 
					    expenseFormModal: ExpenseFormModal,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import { Tabs } from "@mantine/core";
 | 
				
			|||||||
import PageBlock from "../../components/PageBlock/PageBlock.tsx";
 | 
					import PageBlock from "../../components/PageBlock/PageBlock.tsx";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    IconBriefcase,
 | 
					    IconBriefcase,
 | 
				
			||||||
    IconCalendarUser,
 | 
					    IconCalendarUser, IconCoins,
 | 
				
			||||||
    IconCurrencyDollar, IconQrcode,
 | 
					    IconCurrencyDollar, IconQrcode,
 | 
				
			||||||
    IconUser,
 | 
					    IconUser,
 | 
				
			||||||
} from "@tabler/icons-react";
 | 
					} from "@tabler/icons-react";
 | 
				
			||||||
@@ -13,6 +13,7 @@ import { motion } from "framer-motion";
 | 
				
			|||||||
import FinancesTab from "./tabs/Finances/FinancesTab.tsx";
 | 
					import FinancesTab from "./tabs/Finances/FinancesTab.tsx";
 | 
				
			||||||
import WorkTimeTable from "./tabs/WorkTimeTable/ui/WorkTimeTable.tsx";
 | 
					import WorkTimeTable from "./tabs/WorkTimeTable/ui/WorkTimeTable.tsx";
 | 
				
			||||||
import { WorkShiftsTab } from "./tabs/WorkShifts/WorkShiftsTab.tsx";
 | 
					import { WorkShiftsTab } from "./tabs/WorkShifts/WorkShiftsTab.tsx";
 | 
				
			||||||
 | 
					import { ExpensesTab } from "./tabs/Expenses/ExpensesTab.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AdminPage = () => {
 | 
					const AdminPage = () => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
@@ -48,6 +49,11 @@ const AdminPage = () => {
 | 
				
			|||||||
                            leftSection={<IconQrcode />}>
 | 
					                            leftSection={<IconQrcode />}>
 | 
				
			||||||
                            Смены
 | 
					                            Смены
 | 
				
			||||||
                        </Tabs.Tab>
 | 
					                        </Tabs.Tab>
 | 
				
			||||||
 | 
					                        <Tabs.Tab
 | 
				
			||||||
 | 
					                            value={"expenses"}
 | 
				
			||||||
 | 
					                            leftSection={<IconCoins />}>
 | 
				
			||||||
 | 
					                            Расходы
 | 
				
			||||||
 | 
					                        </Tabs.Tab>
 | 
				
			||||||
                    </Tabs.List>
 | 
					                    </Tabs.List>
 | 
				
			||||||
                    <Tabs.Panel value={"users"}>
 | 
					                    <Tabs.Panel value={"users"}>
 | 
				
			||||||
                        <motion.div
 | 
					                        <motion.div
 | 
				
			||||||
@@ -89,6 +95,14 @@ const AdminPage = () => {
 | 
				
			|||||||
                            <WorkShiftsTab />
 | 
					                            <WorkShiftsTab />
 | 
				
			||||||
                        </motion.div>
 | 
					                        </motion.div>
 | 
				
			||||||
                    </Tabs.Panel>
 | 
					                    </Tabs.Panel>
 | 
				
			||||||
 | 
					                    <Tabs.Panel value={"expenses"}>
 | 
				
			||||||
 | 
					                        <motion.div
 | 
				
			||||||
 | 
					                            initial={{ opacity: 0 }}
 | 
				
			||||||
 | 
					                            animate={{ opacity: 1 }}
 | 
				
			||||||
 | 
					                            transition={{ duration: 0.2 }}>
 | 
				
			||||||
 | 
					                            <ExpensesTab />
 | 
				
			||||||
 | 
					                        </motion.div>
 | 
				
			||||||
 | 
					                    </Tabs.Panel>
 | 
				
			||||||
                </Tabs>
 | 
					                </Tabs>
 | 
				
			||||||
            </PageBlock>
 | 
					            </PageBlock>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/pages/AdminPage/hooks/useExpensesList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/pages/AdminPage/hooks/useExpensesList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					import { Pagination } from "../../../types/Pagination.ts";
 | 
				
			||||||
 | 
					import { ObjectListWithPagination } from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					import { ExpenseService } from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useExpensesList = (pagination: Pagination) =>
 | 
				
			||||||
 | 
					    ObjectListWithPagination({
 | 
				
			||||||
 | 
					        queryFn: () => ExpenseService.getAllExpenses(pagination),
 | 
				
			||||||
 | 
					        queryKey: "getExpenses",
 | 
				
			||||||
 | 
					        getObjectsFn: response => response.expenses,
 | 
				
			||||||
 | 
					        pagination,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
							
								
								
									
										134
									
								
								src/pages/AdminPage/tabs/Expenses/ExpensesTab.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/pages/AdminPage/tabs/Expenses/ExpensesTab.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
				
			|||||||
 | 
					import { useExpensesList } from "../../hooks/useExpensesList.tsx";
 | 
				
			||||||
 | 
					import { useExpensesTableColumns } from "./hooks/useExpensesTableColumns.tsx";
 | 
				
			||||||
 | 
					import { ExpenseSchemaBase, ExpenseService } from "../../../../client";
 | 
				
			||||||
 | 
					import { dateToString } from "../../../../types/utils.ts";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
 | 
					import { Pagination, Flex, rem, Button, Tooltip, ActionIcon } from "@mantine/core";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ExpensesTab = () => {
 | 
				
			||||||
 | 
					    const [totalPages, setTotalPages] = useState(10);
 | 
				
			||||||
 | 
					    const [page, setPage] = useState(1);
 | 
				
			||||||
 | 
					    const {
 | 
				
			||||||
 | 
					        pagination: paginationInfo,
 | 
				
			||||||
 | 
					        objects: expenses,
 | 
				
			||||||
 | 
					        refetch,
 | 
				
			||||||
 | 
					    } = useExpensesList({ page: page, itemsPerPage: 10 });
 | 
				
			||||||
 | 
					    const columns = useExpensesTableColumns();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (!paginationInfo) return;
 | 
				
			||||||
 | 
					        setTotalPages(paginationInfo.totalPages);
 | 
				
			||||||
 | 
					    }, [paginationInfo]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onUpdate = (expense: ExpenseSchemaBase) => {
 | 
				
			||||||
 | 
					        ExpenseService.updateExpense({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                expense: {
 | 
				
			||||||
 | 
					                    ...expense,
 | 
				
			||||||
 | 
					                    spentDate: dateToString(new Date(expense.spentDate)) ?? "",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                await refetch();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onCreateClick = () => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "expenseFormModal",
 | 
				
			||||||
 | 
					            title: "Создание записи о расходах",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onCreate: onUpdate,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onEditClick = (expense: ExpenseSchemaBase) => {
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "expenseFormModal",
 | 
				
			||||||
 | 
					            title: "Редактирование записи о расходах",
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onChange: event => onUpdate(event),
 | 
				
			||||||
 | 
					                element: expense,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onDeleteClick = (expense: ExpenseSchemaBase) => {
 | 
				
			||||||
 | 
					        ExpenseService.deleteExpense({
 | 
				
			||||||
 | 
					            expenseId: expense.id,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(async ({ ok, message }) => {
 | 
				
			||||||
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
 | 
					                await refetch();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Flex
 | 
				
			||||||
 | 
					            direction={"column"}
 | 
				
			||||||
 | 
					            h={"100%"}
 | 
				
			||||||
 | 
					            gap={rem(10)}>
 | 
				
			||||||
 | 
					            <BaseTable
 | 
				
			||||||
 | 
					                data={expenses}
 | 
				
			||||||
 | 
					                columns={columns}
 | 
				
			||||||
 | 
					                restProps={
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        enableTopToolbar: true,
 | 
				
			||||||
 | 
					                        enableRowActions: true,
 | 
				
			||||||
 | 
					                        enableSorting: false,
 | 
				
			||||||
 | 
					                        enableColumnActions: false,
 | 
				
			||||||
 | 
					                        renderTopToolbar: (
 | 
				
			||||||
 | 
					                            <Flex p={rem(10)}>
 | 
				
			||||||
 | 
					                                <Button
 | 
				
			||||||
 | 
					                                    variant={"default"}
 | 
				
			||||||
 | 
					                                    onClick={() => onCreateClick()}>
 | 
				
			||||||
 | 
					                                    Создать запись о расходах
 | 
				
			||||||
 | 
					                                </Button>
 | 
				
			||||||
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        renderRowActions: ({ row }) => (
 | 
				
			||||||
 | 
					                            <Flex gap="md">
 | 
				
			||||||
 | 
					                                <Tooltip label="Редактировать">
 | 
				
			||||||
 | 
					                                    <ActionIcon
 | 
				
			||||||
 | 
					                                        onClick={() => onEditClick(row.original)}
 | 
				
			||||||
 | 
					                                        variant={"default"}>
 | 
				
			||||||
 | 
					                                        <IconEdit />
 | 
				
			||||||
 | 
					                                    </ActionIcon>
 | 
				
			||||||
 | 
					                                </Tooltip>
 | 
				
			||||||
 | 
					                                <Tooltip label="Удалить">
 | 
				
			||||||
 | 
					                                    <ActionIcon
 | 
				
			||||||
 | 
					                                        onClick={() => onDeleteClick(row.original)}
 | 
				
			||||||
 | 
					                                        variant={"default"}>
 | 
				
			||||||
 | 
					                                        <IconTrash />
 | 
				
			||||||
 | 
					                                    </ActionIcon>
 | 
				
			||||||
 | 
					                                </Tooltip>
 | 
				
			||||||
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                    } as MRT_TableOptions<ExpenseSchemaBase>
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					            {totalPages > 1 && (
 | 
				
			||||||
 | 
					                <Pagination
 | 
				
			||||||
 | 
					                    style={{ alignSelf: "flex-end" }}
 | 
				
			||||||
 | 
					                    withEdges
 | 
				
			||||||
 | 
					                    onChange={event => setPage(event)}
 | 
				
			||||||
 | 
					                    value={page}
 | 
				
			||||||
 | 
					                    total={totalPages}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					        </Flex>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import { useMemo } from "react";
 | 
				
			||||||
 | 
					import { MRT_ColumnDef } from "mantine-react-table";
 | 
				
			||||||
 | 
					import { ExpenseSchemaBase } from "../../../../../client";
 | 
				
			||||||
 | 
					import { formatDate } from "../../../../../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useExpensesTableColumns = () => {
 | 
				
			||||||
 | 
					    return useMemo<MRT_ColumnDef<ExpenseSchemaBase>[]>(
 | 
				
			||||||
 | 
					        () => [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "spentDate",
 | 
				
			||||||
 | 
					                header: "Дата",
 | 
				
			||||||
 | 
					                Cell: ({ row }) => formatDate(row.original.spentDate as string),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "name",
 | 
				
			||||||
 | 
					                header: "Наименование",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "comment",
 | 
				
			||||||
 | 
					                header: "Комментарий",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "amount",
 | 
				
			||||||
 | 
					                header: "Сумма",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                accessorKey: "createdByUser",
 | 
				
			||||||
 | 
					                header: "Создал запись",
 | 
				
			||||||
 | 
					                Cell: ({ row }) => {
 | 
				
			||||||
 | 
					                    return `${row.original.createdByUser.firstName} ${row.original.createdByUser.secondName}`;
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        [],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
 | 
					import { Flex, NumberInput, rem, TextInput } from "@mantine/core";
 | 
				
			||||||
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
 | 
					import { ExpenseSchemaBase } from "../../../../../client";
 | 
				
			||||||
 | 
					import { DatePickerInput } from "@mantine/dates";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CreateEditFormProps<ExpenseSchemaBase>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ExpenseFormModal = ({
 | 
				
			||||||
 | 
					                              context,
 | 
				
			||||||
 | 
					                              id,
 | 
				
			||||||
 | 
					                              innerProps,
 | 
				
			||||||
 | 
					                          }: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					    const isEditing = "element" in innerProps;
 | 
				
			||||||
 | 
					    const initialValue: Partial<ExpenseSchemaBase> = isEditing
 | 
				
			||||||
 | 
					        ? innerProps.element
 | 
				
			||||||
 | 
					        : {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const form = useForm<Partial<ExpenseSchemaBase>>({
 | 
				
			||||||
 | 
					        initialValues: initialValue,
 | 
				
			||||||
 | 
					        validate: {
 | 
				
			||||||
 | 
					            name: name => !name && "Необходимо указать наименование",
 | 
				
			||||||
 | 
					            amount: amount => !amount && "Необходимо указать сумму",
 | 
				
			||||||
 | 
					            spentDate: spentDate => !spentDate && "Необходимо указать дату",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <BaseFormModal
 | 
				
			||||||
 | 
					            form={form}
 | 
				
			||||||
 | 
					            closeOnSubmit
 | 
				
			||||||
 | 
					            onClose={() => context.closeContextModal(id)}
 | 
				
			||||||
 | 
					            {...innerProps}>
 | 
				
			||||||
 | 
					            <BaseFormModal.Body>
 | 
				
			||||||
 | 
					                <Flex
 | 
				
			||||||
 | 
					                    direction={"column"}
 | 
				
			||||||
 | 
					                    gap={rem(10)}>
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        label={"Наименование"}
 | 
				
			||||||
 | 
					                        placeholder={"Введите наименование"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("name")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        label={"Комментарий"}
 | 
				
			||||||
 | 
					                        placeholder={"Введите комментарий"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("comment")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <NumberInput
 | 
				
			||||||
 | 
					                        label={"Сумма"}
 | 
				
			||||||
 | 
					                        placeholder={"Введите сумму"}
 | 
				
			||||||
 | 
					                        min={0}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("amount")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <DatePickerInput
 | 
				
			||||||
 | 
					                        {...form.getInputProps("spentDate")}
 | 
				
			||||||
 | 
					                        value={form.getInputProps("spentDate").value ? new Date(form.getInputProps("spentDate").value) : null}
 | 
				
			||||||
 | 
					                        label={"Дата"}
 | 
				
			||||||
 | 
					                        placeholder={"Укажите дату расхода"}
 | 
				
			||||||
 | 
					                        valueFormat={"DD.MM.YYYY"}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </Flex>
 | 
				
			||||||
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
 | 
					        </BaseFormModal>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ExpenseFormModal;
 | 
				
			||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
import { ChartFormFilters } from "../../../../../types/ChartFormFilters.ts";
 | 
					import { ChartFormFilters } from "../../../../../types/ChartFormFilters.ts";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { dateToString, getDefaultDates } from "../../../../../utils/dates.ts";
 | 
					import { getDefaultDates } from "../../../../../utils/dates.ts";
 | 
				
			||||||
import { useEffect, useState } from "react";
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
import { ProfitChartDataItem, StatisticsService } from "../../../../../../../client";
 | 
					import { ProfitChartDataItem, StatisticsService } from "../../../../../../../client";
 | 
				
			||||||
import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
					import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
				
			||||||
 | 
					import { dateToString } from "../../../../../../../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useProfitChart = () => {
 | 
					export const useProfitChart = () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { TableFormFilters } from "../../../../../types/TableFormFilters.ts";
 | 
					import { TableFormFilters } from "../../../../../types/TableFormFilters.ts";
 | 
				
			||||||
import { dateToString, getDefaultDates } from "../../../../../utils/dates.ts";
 | 
					import { getDefaultDates } from "../../../../../utils/dates.ts";
 | 
				
			||||||
import { GroupStatisticsTable } from "../../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
					import { GroupStatisticsTable } from "../../ProfitTableSegmentedControl/ProfitTableSegmentedControl.tsx";
 | 
				
			||||||
import { useEffect, useState } from "react";
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
import { ProfitTableDataItem, StatisticsService } from "../../../../../../../client";
 | 
					import { ProfitTableDataItem, StatisticsService } from "../../../../../../../client";
 | 
				
			||||||
import { useProfitMantineTable } from "./useProfitMantineTable.tsx";
 | 
					import { useProfitMantineTable } from "./useProfitMantineTable.tsx";
 | 
				
			||||||
import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
					import { defaultDealStatus } from "../../../../../utils/defaultFilterValues.ts";
 | 
				
			||||||
 | 
					import { dateToString } from "../../../../../../../types/utils.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useProfitTable = () => {
 | 
					export const useProfitTable = () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,11 +5,3 @@ export const getDefaultDates = (): [Date, Date] => {
 | 
				
			|||||||
    return [dateFrom, dateTo];
 | 
					    return [dateFrom, dateTo];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dateToString = (date: Date | null) => {
 | 
					 | 
				
			||||||
    if (date === null) return null;
 | 
					 | 
				
			||||||
    const month = date.getMonth() + 1;
 | 
					 | 
				
			||||||
    const day = date.getDate();
 | 
					 | 
				
			||||||
    const monthStr = month < 10 ? `0${month}` : month;
 | 
					 | 
				
			||||||
    const dayStr = day < 10 ? `0${day}` : day;
 | 
					 | 
				
			||||||
    return `${date.getFullYear()}-${monthStr}-${dayStr}`;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,3 +57,12 @@ export const strTimeToFloatHours = (time: string): number => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return hours + minutes / 60;
 | 
					    return hours + minutes / 60;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const dateToString = (date: Date | null) => {
 | 
				
			||||||
 | 
					    if (date === null) return null;
 | 
				
			||||||
 | 
					    const month = date.getMonth() + 1;
 | 
				
			||||||
 | 
					    const day = date.getDate();
 | 
				
			||||||
 | 
					    const monthStr = month < 10 ? `0${month}` : month;
 | 
				
			||||||
 | 
					    const dayStr = day < 10 ? `0${day}` : day;
 | 
				
			||||||
 | 
					    return `${date.getFullYear()}-${monthStr}-${dayStr}`;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Reference in New Issue
	
	Block a user