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}`;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -56,4 +56,13 @@ export const strTimeToFloatHours = (time: string): number => {
|
|||||||
const minutes = parseInt(values[1]);
|
const minutes = parseInt(values[1]);
|
||||||
|
|
||||||
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