feat: generation of modules from the server, moved modules fields from the general tab
This commit is contained in:
		
							
								
								
									
										3
									
								
								generateModules.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								generateModules.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					sudo npx tsc ./src/modules/modulesFileGen/modulesFileGen.ts
 | 
				
			||||||
 | 
					mv -f ./src/modules/modulesFileGen/modulesFileGen.js ./src/modules/modulesFileGen/modulesFileGen.cjs
 | 
				
			||||||
 | 
					sudo node ./src/modules/modulesFileGen/modulesFileGen.cjs
 | 
				
			||||||
@@ -62,6 +62,7 @@
 | 
				
			|||||||
        "@types/eslint__js": "^8.42.3",
 | 
					        "@types/eslint__js": "^8.42.3",
 | 
				
			||||||
        "@types/file-saver": "^2.0.7",
 | 
					        "@types/file-saver": "^2.0.7",
 | 
				
			||||||
        "@types/lodash": "^4.17.7",
 | 
					        "@types/lodash": "^4.17.7",
 | 
				
			||||||
 | 
					        "@types/node": "^22.13.9",
 | 
				
			||||||
        "@types/react": "^18.3.3",
 | 
					        "@types/react": "^18.3.3",
 | 
				
			||||||
        "@types/react-dom": "^18.3.0",
 | 
					        "@types/react-dom": "^18.3.0",
 | 
				
			||||||
        "@typescript-eslint/eslint-plugin": "^7.16.1",
 | 
					        "@typescript-eslint/eslint-plugin": "^7.16.1",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -300,6 +300,9 @@ export type { ProductGenerateBarcodeResponse } from './models/ProductGenerateBar
 | 
				
			|||||||
export type { ProductGetBarcodeImageResponse } from './models/ProductGetBarcodeImageResponse';
 | 
					export type { ProductGetBarcodeImageResponse } from './models/ProductGetBarcodeImageResponse';
 | 
				
			||||||
export type { ProductGetResponse } from './models/ProductGetResponse';
 | 
					export type { ProductGetResponse } from './models/ProductGetResponse';
 | 
				
			||||||
export type { ProductImageSchema } from './models/ProductImageSchema';
 | 
					export type { ProductImageSchema } from './models/ProductImageSchema';
 | 
				
			||||||
 | 
					export type { ProductsAndServicesGeneralInfoRequest } from './models/ProductsAndServicesGeneralInfoRequest';
 | 
				
			||||||
 | 
					export type { ProductsAndServicesGeneralInfoResponse } from './models/ProductsAndServicesGeneralInfoResponse';
 | 
				
			||||||
 | 
					export type { ProductsAndServicesGeneralInfoSchema } from './models/ProductsAndServicesGeneralInfoSchema';
 | 
				
			||||||
export type { ProductSchema } from './models/ProductSchema';
 | 
					export type { ProductSchema } from './models/ProductSchema';
 | 
				
			||||||
export type { ProductUpdateRequest } from './models/ProductUpdateRequest';
 | 
					export type { ProductUpdateRequest } from './models/ProductUpdateRequest';
 | 
				
			||||||
export type { ProductUpdateResponse } from './models/ProductUpdateResponse';
 | 
					export type { ProductUpdateResponse } from './models/ProductUpdateResponse';
 | 
				
			||||||
@@ -357,6 +360,10 @@ export type { UpdateBoardOrderRequest } from './models/UpdateBoardOrderRequest';
 | 
				
			|||||||
export type { UpdateBoardOrderResponse } from './models/UpdateBoardOrderResponse';
 | 
					export type { UpdateBoardOrderResponse } from './models/UpdateBoardOrderResponse';
 | 
				
			||||||
export type { UpdateBoardRequest } from './models/UpdateBoardRequest';
 | 
					export type { UpdateBoardRequest } from './models/UpdateBoardRequest';
 | 
				
			||||||
export type { UpdateBoardResponse } from './models/UpdateBoardResponse';
 | 
					export type { UpdateBoardResponse } from './models/UpdateBoardResponse';
 | 
				
			||||||
 | 
					export type { UpdateCardClientRequest } from './models/UpdateCardClientRequest';
 | 
				
			||||||
 | 
					export type { UpdateCardClientResponse } from './models/UpdateCardClientResponse';
 | 
				
			||||||
 | 
					export type { UpdateCardManagerRequest } from './models/UpdateCardManagerRequest';
 | 
				
			||||||
 | 
					export type { UpdateCardManagerResponse } from './models/UpdateCardManagerResponse';
 | 
				
			||||||
export type { UpdateDepartmentRequest } from './models/UpdateDepartmentRequest';
 | 
					export type { UpdateDepartmentRequest } from './models/UpdateDepartmentRequest';
 | 
				
			||||||
export type { UpdateDepartmentResponse } from './models/UpdateDepartmentResponse';
 | 
					export type { UpdateDepartmentResponse } from './models/UpdateDepartmentResponse';
 | 
				
			||||||
export type { UpdateDepartmentSectionRequest } from './models/UpdateDepartmentSectionRequest';
 | 
					export type { UpdateDepartmentSectionRequest } from './models/UpdateDepartmentSectionRequest';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,6 @@ export type CardGeneralInfoSchema = {
 | 
				
			|||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
    isCompleted: boolean;
 | 
					    isCompleted: boolean;
 | 
				
			||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
    shippingWarehouse?: (string | null);
 | 
					 | 
				
			||||||
    manager?: (UserSchema | null);
 | 
					    manager?: (UserSchema | null);
 | 
				
			||||||
    boardId: number;
 | 
					    boardId: number;
 | 
				
			||||||
    statusId: number;
 | 
					    statusId: number;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ export type ModuleSchema = {
 | 
				
			|||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    key: string;
 | 
					    key: string;
 | 
				
			||||||
    label: string;
 | 
					    label: string;
 | 
				
			||||||
 | 
					    iconName?: (string | null);
 | 
				
			||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								src/client/models/ProductsAndServicesGeneralInfoRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/ProductsAndServicesGeneralInfoRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { ProductsAndServicesGeneralInfoSchema } from './ProductsAndServicesGeneralInfoSchema';
 | 
				
			||||||
 | 
					export type ProductsAndServicesGeneralInfoRequest = {
 | 
				
			||||||
 | 
					    cardId: number;
 | 
				
			||||||
 | 
					    data: ProductsAndServicesGeneralInfoSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type ProductsAndServicesGeneralInfoResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type ProductsAndServicesGeneralInfoSchema = {
 | 
				
			||||||
 | 
					    shippingWarehouse?: (string | null);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateCardClientRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateCardClientRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateCardClientRequest = {
 | 
				
			||||||
 | 
					    cardId: number;
 | 
				
			||||||
 | 
					    clientId: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateCardClientResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateCardClientResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateCardClientResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateCardManagerRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateCardManagerRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateCardManagerRequest = {
 | 
				
			||||||
 | 
					    cardId: number;
 | 
				
			||||||
 | 
					    managerId: (number | null);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateCardManagerResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateCardManagerResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do not edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateCardManagerResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,6 +59,12 @@ import type { GetCardProductsBarcodesPdfResponse } from '../models/GetCardProduc
 | 
				
			|||||||
import type { ManageEmployeeRequest } from '../models/ManageEmployeeRequest';
 | 
					import type { ManageEmployeeRequest } from '../models/ManageEmployeeRequest';
 | 
				
			||||||
import type { ManageEmployeeResponse } from '../models/ManageEmployeeResponse';
 | 
					import type { ManageEmployeeResponse } from '../models/ManageEmployeeResponse';
 | 
				
			||||||
import type { ParseCardsExcelResponse } from '../models/ParseCardsExcelResponse';
 | 
					import type { ParseCardsExcelResponse } from '../models/ParseCardsExcelResponse';
 | 
				
			||||||
 | 
					import type { ProductsAndServicesGeneralInfoRequest } from '../models/ProductsAndServicesGeneralInfoRequest';
 | 
				
			||||||
 | 
					import type { ProductsAndServicesGeneralInfoResponse } from '../models/ProductsAndServicesGeneralInfoResponse';
 | 
				
			||||||
 | 
					import type { UpdateCardClientRequest } from '../models/UpdateCardClientRequest';
 | 
				
			||||||
 | 
					import type { UpdateCardClientResponse } from '../models/UpdateCardClientResponse';
 | 
				
			||||||
 | 
					import type { UpdateCardManagerRequest } from '../models/UpdateCardManagerRequest';
 | 
				
			||||||
 | 
					import type { UpdateCardManagerResponse } from '../models/UpdateCardManagerResponse';
 | 
				
			||||||
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';
 | 
				
			||||||
@@ -236,6 +242,66 @@ export class CardService {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Products And Services General Info
 | 
				
			||||||
 | 
					     * @returns ProductsAndServicesGeneralInfoResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateProductsAndServicesGeneralInfo({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: ProductsAndServicesGeneralInfoRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<ProductsAndServicesGeneralInfoResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/card/update-products-and-services-general-info',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Card Manager
 | 
				
			||||||
 | 
					     * @returns UpdateCardManagerResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateCardManager({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdateCardManagerRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateCardManagerResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/card/update-card-manager',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update Card Client
 | 
				
			||||||
 | 
					     * @returns UpdateCardClientResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateCardClient({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdateCardClientRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateCardClientResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/card/update-card-client',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Add Kit To Card
 | 
					     * Add Kit To Card
 | 
				
			||||||
     * @returns CardAddKitResponse Successful Response
 | 
					     * @returns CardAddKitResponse Successful Response
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import { UseFormReturnType } from "@mantine/form";
 | 
				
			|||||||
import { rem, Stack } from "@mantine/core";
 | 
					import { rem, Stack } from "@mantine/core";
 | 
				
			||||||
import { ReactNode } from "react";
 | 
					import { ReactNode } from "react";
 | 
				
			||||||
import CardAttributeField from "./components/CardAttributeField.tsx";
 | 
					import CardAttributeField from "./components/CardAttributeField.tsx";
 | 
				
			||||||
import { CardGeneralFormType } from "../../pages/CardsPage/tabs/GeneralTab/GeneralTab.tsx";
 | 
					import { CardGeneralFormType } from "../../pages/CardsPage/drawers/CardEditDrawer/tabs/GeneralTab/GeneralTab.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    project: ProjectSchema;
 | 
					    project: ProjectSchema;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import { AttributeSchema } from "../../../client";
 | 
				
			|||||||
import { Checkbox, Group, NumberInput, TextInput, Tooltip } from "@mantine/core";
 | 
					import { Checkbox, Group, NumberInput, TextInput, Tooltip } from "@mantine/core";
 | 
				
			||||||
import { UseFormReturnType } from "@mantine/form";
 | 
					import { UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
import { DatePickerInput, DateTimePicker } from "@mantine/dates";
 | 
					import { DatePickerInput, DateTimePicker } from "@mantine/dates";
 | 
				
			||||||
import { CardGeneralFormType } from "../../../pages/CardsPage/tabs/GeneralTab/GeneralTab.tsx";
 | 
					import { CardGeneralFormType } from "../../../pages/CardsPage/drawers/CardEditDrawer/tabs/GeneralTab/GeneralTab.tsx";
 | 
				
			||||||
import { IconInfoCircle } from "@tabler/icons-react";
 | 
					import { IconInfoCircle } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ type SelectProps = Omit<ObjectSelectProps<StatusSchema | null>, "data" | "getLab
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type Props = OtherProps & SelectProps;
 | 
					type Props = OtherProps & SelectProps;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DealStatusSelect: FC<Props> = ({ board, ...props}) => {
 | 
					const CardStatusSelect: FC<Props> = ({ board, ...props}) => {
 | 
				
			||||||
    const [isInitial, setIsInitial] = useState<boolean>(true);
 | 
					    const [isInitial, setIsInitial] = useState<boolean>(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const filteredData = board?.statuses.filter(
 | 
					    const filteredData = board?.statuses.filter(
 | 
				
			||||||
@@ -37,4 +37,4 @@ const DealStatusSelect: FC<Props> = ({ board, ...props}) => {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export default DealStatusSelect;
 | 
					export default CardStatusSelect;
 | 
				
			||||||
@@ -5,6 +5,8 @@ import { Flex, rem, Text, TextInput, useMantineColorScheme } from "@mantine/core
 | 
				
			|||||||
import { IconGripHorizontal } from "@tabler/icons-react";
 | 
					import { IconGripHorizontal } from "@tabler/icons-react";
 | 
				
			||||||
import { useDebouncedValue } from "@mantine/hooks";
 | 
					import { useDebouncedValue } from "@mantine/hooks";
 | 
				
			||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    cards: CardSummary[];
 | 
					    cards: CardSummary[];
 | 
				
			||||||
@@ -15,6 +17,9 @@ export const CardGroupView: FC<Props> = ({ cards, group }) => {
 | 
				
			|||||||
    const theme = useMantineColorScheme();
 | 
					    const theme = useMantineColorScheme();
 | 
				
			||||||
    const [name, setName] = useState<string>(group.name || "");
 | 
					    const [name, setName] = useState<string>(group.name || "");
 | 
				
			||||||
    const [debouncedName] = useDebouncedValue(name, 200);
 | 
					    const [debouncedName] = useDebouncedValue(name, 200);
 | 
				
			||||||
 | 
					    const { selectedProject } = useProjectsContext();
 | 
				
			||||||
 | 
					    const isServicesAndProductsIncluded = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, selectedProject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const totalPrice = useMemo(() => cards.reduce((acc, card) => acc + card.totalPrice, 0), [cards]);
 | 
					    const totalPrice = useMemo(() => cards.reduce((acc, card) => acc + card.totalPrice, 0), [cards]);
 | 
				
			||||||
    const totalProducts = useMemo(() => cards.reduce((acc, card) => acc + card.totalProducts, 0), [cards]);
 | 
					    const totalProducts = useMemo(() => cards.reduce((acc, card) => acc + card.totalProducts, 0), [cards]);
 | 
				
			||||||
    const updateName = () => {
 | 
					    const updateName = () => {
 | 
				
			||||||
@@ -70,6 +75,7 @@ export const CardGroupView: FC<Props> = ({ cards, group }) => {
 | 
				
			|||||||
                    />
 | 
					                    />
 | 
				
			||||||
                ))}
 | 
					                ))}
 | 
				
			||||||
            </Flex>
 | 
					            </Flex>
 | 
				
			||||||
 | 
					            {isServicesAndProductsIncluded && (
 | 
				
			||||||
                <Flex
 | 
					                <Flex
 | 
				
			||||||
                    p={rem(10)}
 | 
					                    p={rem(10)}
 | 
				
			||||||
                    direction={"column"}
 | 
					                    direction={"column"}
 | 
				
			||||||
@@ -83,6 +89,7 @@ export const CardGroupView: FC<Props> = ({ cards, group }) => {
 | 
				
			|||||||
                        c={"gray.6"}
 | 
					                        c={"gray.6"}
 | 
				
			||||||
                        size={"xs"}>Всего товаров: {totalProducts.toLocaleString("ru-RU")} шт.</Text>
 | 
					                        size={"xs"}>Всего товаров: {totalProducts.toLocaleString("ru-RU")} шт.</Text>
 | 
				
			||||||
                </Flex>
 | 
					                </Flex>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
        </Flex>
 | 
					        </Flex>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -9,7 +9,7 @@ import { faCheck } from "@fortawesome/free-solid-svg-icons";
 | 
				
			|||||||
import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react";
 | 
					import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
import { useContextMenu } from "mantine-contextmenu";
 | 
					import { useContextMenu } from "mantine-contextmenu";
 | 
				
			||||||
import useCardSummaryState from "./useCardSummaryState.tsx";
 | 
					import useCardSummaryState from "./useCardSummaryState.tsx";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
					import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import { groupBy, has, uniq } from "lodash";
 | 
				
			|||||||
import { CardGroupView } from "../CardGroupView/CardGroupView.tsx";
 | 
					import { CardGroupView } from "../CardGroupView/CardGroupView.tsx";
 | 
				
			||||||
import CreateDealsFromFileButton from "../CreateCardsFromFileButton/CreateDealsFromFileButton.tsx";
 | 
					import CreateDealsFromFileButton from "../CreateCardsFromFileButton/CreateDealsFromFileButton.tsx";
 | 
				
			||||||
import DragState from "../../../../pages/CardsPage/enums/DragState.ts";
 | 
					import DragState from "../../../../pages/CardsPage/enums/DragState.ts";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
					import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import { CardService, StatusSchema } from "../../../../client";
 | 
				
			|||||||
import { useQueryClient } from "@tanstack/react-query";
 | 
					import { useQueryClient } from "@tanstack/react-query";
 | 
				
			||||||
import { dateWithoutTimezone } from "../../../../shared/lib/date.ts";
 | 
					import { dateWithoutTimezone } from "../../../../shared/lib/date.ts";
 | 
				
			||||||
import { usePrefillCardContext } from "../../../../pages/CardsPage/contexts/PrefillCardContext.tsx";
 | 
					import { usePrefillCardContext } from "../../../../pages/CardsPage/contexts/PrefillCardContext.tsx";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
					import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import ShippingWarehouseAutocomplete
 | 
				
			|||||||
    from "../../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
					    from "../../../Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
				
			||||||
import BaseMarketplaceSelect from "../../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
					import BaseMarketplaceSelect from "../../../Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
				
			||||||
import { usePrefillCardContext } from "../../../../pages/CardsPage/contexts/PrefillCardContext.tsx";
 | 
					import { usePrefillCardContext } from "../../../../pages/CardsPage/contexts/PrefillCardContext.tsx";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
					import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import DragState from "../../../../pages/CardsPage/enums/DragState.ts";
 | 
				
			|||||||
import { useContextMenu } from "mantine-contextmenu";
 | 
					import { useContextMenu } from "mantine-contextmenu";
 | 
				
			||||||
import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
					import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
import useStatus from "./hooks/useStatus.tsx";
 | 
					import useStatus from "./hooks/useStatus.tsx";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ type Props = Omit<
 | 
				
			|||||||
    ObjectSelectProps<UserSchema | null>,
 | 
					    ObjectSelectProps<UserSchema | null>,
 | 
				
			||||||
    "data" | "getValueFn" | "getLabelFn"
 | 
					    "data" | "getValueFn" | "getLabelFn"
 | 
				
			||||||
>;
 | 
					>;
 | 
				
			||||||
const UserSelect: FC<Props> = props => {
 | 
					const ManagerSelect: FC<Props> = props => {
 | 
				
			||||||
    const { objects: managers } = useManagersList();
 | 
					    const { objects: managers } = useManagersList();
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ObjectSelect
 | 
					        <ObjectSelect
 | 
				
			||||||
@@ -21,4 +21,4 @@ const UserSelect: FC<Props> = props => {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export default UserSelect;
 | 
					export default ManagerSelect;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,9 @@ type Props = {
 | 
				
			|||||||
    withLabel?: boolean;
 | 
					    withLabel?: boolean;
 | 
				
			||||||
    error?: string;
 | 
					    error?: string;
 | 
				
			||||||
    inputContainer?: (children: ReactNode) => ReactNode;
 | 
					    inputContainer?: (children: ReactNode) => ReactNode;
 | 
				
			||||||
 | 
					    disabled?: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
const ClientSelect: FC<Props> = ({ value, onChange, error, inputContainer, withLabel = false }) => {
 | 
					const ClientSelect: FC<Props> = ({ value, onChange, error, inputContainer, withLabel = false, disabled = false }) => {
 | 
				
			||||||
    const { clients } = useClientsList();
 | 
					    const { clients } = useClientsList();
 | 
				
			||||||
    const options = clients.map(client => ({
 | 
					    const options = clients.map(client => ({
 | 
				
			||||||
        label: client.name,
 | 
					        label: client.name,
 | 
				
			||||||
@@ -37,6 +38,7 @@ const ClientSelect: FC<Props> = ({ value, onChange, error, inputContainer, withL
 | 
				
			|||||||
            label={withLabel && "Клиент"}
 | 
					            label={withLabel && "Клиент"}
 | 
				
			||||||
            error={error}
 | 
					            error={error}
 | 
				
			||||||
            inputContainer={inputContainer}
 | 
					            inputContainer={inputContainer}
 | 
				
			||||||
 | 
					            disabled={disabled}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ function usePollingEffect(
 | 
				
			|||||||
): void {
 | 
					): void {
 | 
				
			||||||
    const { interval = 3000, isActive = true, onCleanUp = () => {} } = options;
 | 
					    const { interval = 3000, isActive = true, onCleanUp = () => {} } = options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const timeoutIdRef = useRef<number | null>(null);
 | 
					    const timeoutIdRef = useRef<NodeJS.Timeout | number | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (!isActive) {
 | 
					        if (!isActive) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ import { modals } from "./modals/modals.ts";
 | 
				
			|||||||
import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
					import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx";
 | 
				
			||||||
import { ContextMenuProvider } from "mantine-contextmenu";
 | 
					import { ContextMenuProvider } from "mantine-contextmenu";
 | 
				
			||||||
import { ProjectsContextProvider } from "./contexts/ProjectsContext.tsx";
 | 
					import { ProjectsContextProvider } from "./contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					import { ModulesContextProvider } from "./modules/context/ModulesContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuring router
 | 
					// Configuring router
 | 
				
			||||||
const router = createRouter({ routeTree });
 | 
					const router = createRouter({ routeTree });
 | 
				
			||||||
@@ -56,8 +57,10 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
 | 
				
			|||||||
                        <DatesProvider settings={{ locale: "ru" }}>
 | 
					                        <DatesProvider settings={{ locale: "ru" }}>
 | 
				
			||||||
                            <TasksProvider>
 | 
					                            <TasksProvider>
 | 
				
			||||||
                                <ProjectsContextProvider>
 | 
					                                <ProjectsContextProvider>
 | 
				
			||||||
 | 
					                                    <ModulesContextProvider>
 | 
				
			||||||
                                        <RouterProvider router={router} />
 | 
					                                        <RouterProvider router={router} />
 | 
				
			||||||
                                        <Notifications />
 | 
					                                        <Notifications />
 | 
				
			||||||
 | 
					                                    </ModulesContextProvider>
 | 
				
			||||||
                                </ProjectsContextProvider>
 | 
					                                </ProjectsContextProvider>
 | 
				
			||||||
                            </TasksProvider>
 | 
					                            </TasksProvider>
 | 
				
			||||||
                        </DatesProvider>
 | 
					                        </DatesProvider>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,13 +3,13 @@ import CreateServiceCategoryModal from "../pages/ServicesPage/modals/CreateServi
 | 
				
			|||||||
import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.tsx";
 | 
					import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.tsx";
 | 
				
			||||||
import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx";
 | 
					import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx";
 | 
				
			||||||
import ProductFormModal from "../pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx";
 | 
					import ProductFormModal from "../pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx";
 | 
				
			||||||
import AddCardServiceModal from "../pages/CardsPage/modals/AddCardServiceModal.tsx";
 | 
					import AddCardServiceModal from "../modules/cardModules/cardEditorTabs/ProductAndServiceTab/modals/AddCardServiceModal.tsx";
 | 
				
			||||||
import AddCardProductModal from "../pages/CardsPage/modals/AddCardProductModal.tsx";
 | 
					import AddCardProductModal from "../modules/cardModules/cardEditorTabs/ProductAndServiceTab/modals/AddCardProductModal.tsx";
 | 
				
			||||||
import PrintBarcodeModal from "./PrintBarcodeModal/PrintBarcodeModal.tsx";
 | 
					import PrintBarcodeModal from "./PrintBarcodeModal/PrintBarcodeModal.tsx";
 | 
				
			||||||
import AddBarcodeModal from "./AddBarcodeModal/AddBarcodeModal.tsx";
 | 
					import AddBarcodeModal from "./AddBarcodeModal/AddBarcodeModal.tsx";
 | 
				
			||||||
import BarcodeTemplateFormModal
 | 
					import BarcodeTemplateFormModal
 | 
				
			||||||
    from "../pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx";
 | 
					    from "../pages/BarcodePage/modals/BarcodeTemplateFormModal/BarcodeTemplateFormModal.tsx";
 | 
				
			||||||
import ProductServiceFormModal from "../pages/CardsPage/modals/ProductServiceFormModal.tsx";
 | 
					import ProductServiceFormModal from "../modules/cardModules/cardEditorTabs/ProductAndServiceTab/modals/ProductServiceFormModal.tsx";
 | 
				
			||||||
import UserFormModal from "../pages/AdminPage/modals/UserFormModal/UserFormModal.tsx";
 | 
					import UserFormModal from "../pages/AdminPage/modals/UserFormModal/UserFormModal.tsx";
 | 
				
			||||||
import EmployeeSelectModal from "./EmployeeSelectModal/EmployeeSelectModal.tsx";
 | 
					import EmployeeSelectModal from "./EmployeeSelectModal/EmployeeSelectModal.tsx";
 | 
				
			||||||
import EmployeeTableModal from "./EmployeeTableModal/EmployeeTableModal.tsx";
 | 
					import EmployeeTableModal from "./EmployeeTableModal/EmployeeTableModal.tsx";
 | 
				
			||||||
@@ -24,11 +24,11 @@ import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFo
 | 
				
			|||||||
import ScanningModal from "./ScanningModal/ScanningModal.tsx";
 | 
					import ScanningModal from "./ScanningModal/ScanningModal.tsx";
 | 
				
			||||||
import TransactionFormModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionFormModal.tsx";
 | 
					import TransactionFormModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionFormModal.tsx";
 | 
				
			||||||
import TransactionTagsModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionTagsModal.tsx";
 | 
					import TransactionTagsModal from "../pages/AdminPage/tabs/Transactions/modals/TransactionTagsModal.tsx";
 | 
				
			||||||
import ShippingProductModal from "../pages/CardsPage/tabs/ShippingTab/modals/ShippingProductModal.tsx";
 | 
					import ShippingProductModal from "../modules/cardModules/cardEditorTabs/ShippingTab/modals/ShippingProductModal.tsx";
 | 
				
			||||||
import DepartmentModal from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/DepartmentModal.tsx";
 | 
					import DepartmentModal from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/DepartmentModal.tsx";
 | 
				
			||||||
import AddUserToDepartmentModal
 | 
					import AddUserToDepartmentModal
 | 
				
			||||||
    from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/AddUserToDepartmentModal.tsx";
 | 
					    from "../pages/AdminPage/tabs/OrganizationalStructureTab/modals/AddUserToDepartmentModal.tsx";
 | 
				
			||||||
import AssignEmployeeModal from "../pages/CardsPage/tabs/EmployeesTab/modals/AssignEmployeeModal.tsx";
 | 
					import AssignEmployeeModal from "../modules/cardModules/cardEditorTabs/EmployeesTab/modals/AssignEmployeeModal.tsx";
 | 
				
			||||||
import ResidualProductModal from "../pages/ResiduesPage/modals/ResidualProductModal/ResidualProductModal.tsx";
 | 
					import ResidualProductModal from "../pages/ResiduesPage/modals/ResidualProductModal/ResidualProductModal.tsx";
 | 
				
			||||||
import NewReceiptModal from "../pages/ReceiptPage/components/NewReceipt/modals/NewReceiptModal.tsx";
 | 
					import NewReceiptModal from "../pages/ReceiptPage/components/NewReceipt/modals/NewReceiptModal.tsx";
 | 
				
			||||||
import ReceiptModal from "../pages/ReceiptPage/components/ReceiptEditing/modals/ReceiptModal.tsx";
 | 
					import ReceiptModal from "../pages/ReceiptPage/components/ReceiptEditing/modals/ReceiptModal.tsx";
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										147
									
								
								src/modules/cardModules/cardEditorTabs/ClientTab/ClientTab.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/modules/cardModules/cardEditorTabs/ClientTab/ClientTab.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					import { Button, Fieldset, Group, rem, Stack, Textarea, TextInput } from "@mantine/core";
 | 
				
			||||||
 | 
					import { useCardPageContext } from "../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
 | 
					import { CardService, ClientSchema, ClientService } from "../../../../client";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import ClientSelect from "../../../../components/Selects/ClientSelect/ClientSelect.tsx";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import InlineButton from "../../../../components/InlineButton/InlineButton.tsx";
 | 
				
			||||||
 | 
					import { isEqual } from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ClientTab = () => {
 | 
				
			||||||
 | 
					    const { selectedCard: card, refetchCard } = useCardPageContext();
 | 
				
			||||||
 | 
					    const [initialValues, setInitialValues] = useState<Partial<ClientSchema>>(card?.client ?? {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [client, setClient] = useState<ClientSchema | undefined>(card?.client ?? undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const form = useForm<Partial<ClientSchema>>(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            initialValues,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        const data = card?.client ?? {};
 | 
				
			||||||
 | 
					        setInitialValues(data);
 | 
				
			||||||
 | 
					        form.setValues(data);
 | 
				
			||||||
 | 
					    }, [card]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isEditorDisabled = () => client?.id !== card?.client?.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const handleSubmitClientInfo = (values: ClientSchema) => {
 | 
				
			||||||
 | 
					        ClientService.updateClient({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                data: values,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message }) => {
 | 
				
			||||||
 | 
					                if (!ok) {
 | 
				
			||||||
 | 
					                    notifications.error({ message });
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                refetchCard();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const handleSelectClient = () => {
 | 
				
			||||||
 | 
					        if (!(card && client)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CardService.updateCardClient({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                cardId: card?.id,
 | 
				
			||||||
 | 
					                clientId: client?.id,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message }) => {
 | 
				
			||||||
 | 
					                if (!ok) {
 | 
				
			||||||
 | 
					                    notifications.error({ message });
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                refetchCard();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const clientDataEditor = (
 | 
				
			||||||
 | 
					        <Fieldset legend={"Данные клиента"} flex={1}>
 | 
				
			||||||
 | 
					            <form
 | 
				
			||||||
 | 
					                onSubmit={
 | 
				
			||||||
 | 
					                    form.onSubmit(values => handleSubmitClientInfo(values as ClientSchema))
 | 
				
			||||||
 | 
					                }>
 | 
				
			||||||
 | 
					                <Stack gap={rem(10)}>
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        disabled
 | 
				
			||||||
 | 
					                        placeholder={"Название"}
 | 
				
			||||||
 | 
					                        label={"Название"}
 | 
				
			||||||
 | 
					                        value={card?.client?.name}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        disabled={isEditorDisabled()}
 | 
				
			||||||
 | 
					                        placeholder={"Введите телефон"}
 | 
				
			||||||
 | 
					                        label={"Телефон клиента"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("details.phoneNumber")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        disabled={isEditorDisabled()}
 | 
				
			||||||
 | 
					                        placeholder={"Введите email"}
 | 
				
			||||||
 | 
					                        label={"Email"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("details.email")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        disabled={isEditorDisabled()}
 | 
				
			||||||
 | 
					                        placeholder={"Введите телеграм"}
 | 
				
			||||||
 | 
					                        label={"Телеграм"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("details.telegram")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <TextInput
 | 
				
			||||||
 | 
					                        disabled={isEditorDisabled()}
 | 
				
			||||||
 | 
					                        placeholder={"Введите ИНН"}
 | 
				
			||||||
 | 
					                        label={"ИНН"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("details.inn")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <Textarea
 | 
				
			||||||
 | 
					                        disabled={isEditorDisabled()}
 | 
				
			||||||
 | 
					                        placeholder={"Введите комментарий"}
 | 
				
			||||||
 | 
					                        label={"Комментарий"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("comment")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <Group>
 | 
				
			||||||
 | 
					                        <Button
 | 
				
			||||||
 | 
					                            variant={"default"}
 | 
				
			||||||
 | 
					                            disabled={isEditorDisabled() || isEqual(initialValues, form.values)}
 | 
				
			||||||
 | 
					                            type="submit"
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            Сохранить
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                    </Group>
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
 | 
					            </form>
 | 
				
			||||||
 | 
					        </Fieldset>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Stack flex={1}>
 | 
				
			||||||
 | 
					            <Fieldset legend={"Выбор клиента"} flex={1}>
 | 
				
			||||||
 | 
					                <Stack gap={rem(10)}>
 | 
				
			||||||
 | 
					                    <ClientSelect
 | 
				
			||||||
 | 
					                        value={client}
 | 
				
			||||||
 | 
					                        onChange={setClient}
 | 
				
			||||||
 | 
					                        withLabel
 | 
				
			||||||
 | 
					                        disabled={!isEqual(initialValues, form.values)}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <Group>
 | 
				
			||||||
 | 
					                        <InlineButton
 | 
				
			||||||
 | 
					                            onClick={handleSelectClient}
 | 
				
			||||||
 | 
					                            disabled={!isEditorDisabled()}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            Сохранить
 | 
				
			||||||
 | 
					                        </InlineButton>
 | 
				
			||||||
 | 
					                    </Group>
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
 | 
					            </Fieldset>
 | 
				
			||||||
 | 
					            {clientDataEditor}
 | 
				
			||||||
 | 
					        </Stack>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export default ClientTab;
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
 | 
					import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
import useEmployeeTableColumns from "../hooks/useEmployeesTableColumns.tsx";
 | 
					import useEmployeeTableColumns from "../hooks/useEmployeesTableColumns.tsx";
 | 
				
			||||||
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
 | 
					import { ActionIcon, Flex, Tooltip } from "@mantine/core";
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import { CardEmployeesSchema, CardService } from "../../../../../client";
 | 
					import { CardEmployeesSchema, CardService } from "../../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useEmployeesTab = () => {
 | 
					const useEmployeesTab = () => {
 | 
				
			||||||
@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					import { Button, Fieldset, Group, rem, Stack } from "@mantine/core";
 | 
				
			||||||
 | 
					import { useCardPageContext } from "../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
 | 
					import { CardSchema, CardService, type UserSchema } from "../../../../client";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import ManagerSelect from "../../../../components/ManagerSelect/ManagerSelect.tsx";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { isEqual } from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ManagerForm = {
 | 
				
			||||||
 | 
					    manager?: (UserSchema | null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ManagerTab = () => {
 | 
				
			||||||
 | 
					    const { selectedCard: card, refetchCard } = useCardPageContext();
 | 
				
			||||||
 | 
					    const [initialValues, setInitialValues] = useState<ManagerForm>(card as CardSchema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const form = useForm<ManagerForm>({
 | 
				
			||||||
 | 
					        initialValues,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        const data = card ?? {};
 | 
				
			||||||
 | 
					        setInitialValues(data);
 | 
				
			||||||
 | 
					        form.setValues(data);
 | 
				
			||||||
 | 
					    }, [card]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onSubmit = async (values: ManagerForm) => {
 | 
				
			||||||
 | 
					        if (!card) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return CardService.updateCardManager({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                cardId: card.id,
 | 
				
			||||||
 | 
					                managerId: values.manager?.id ?? null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message }) => {
 | 
				
			||||||
 | 
					                if (!ok) {
 | 
				
			||||||
 | 
					                    notifications.error({ message });
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                refetchCard();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <form onSubmit={form.onSubmit(values => onSubmit(values))}>
 | 
				
			||||||
 | 
					            <Fieldset flex={1}>
 | 
				
			||||||
 | 
					                <Stack gap={rem(10)}>
 | 
				
			||||||
 | 
					                    <ManagerSelect
 | 
				
			||||||
 | 
					                        placeholder={"Укажите менеджера"}
 | 
				
			||||||
 | 
					                        label={"Менеджер"}
 | 
				
			||||||
 | 
					                        {...form.getInputProps("manager")}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <Group>
 | 
				
			||||||
 | 
					                        <Button
 | 
				
			||||||
 | 
					                            type={"submit"}
 | 
				
			||||||
 | 
					                            variant={"default"}
 | 
				
			||||||
 | 
					                            disabled={isEqual(initialValues, form.values)}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            Сохранить
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                    </Group>
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
 | 
					            </Fieldset>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export default ManagerTab;
 | 
				
			||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.products-list {
 | 
					.products-list {
 | 
				
			||||||
    width: 60%;
 | 
					    width: 52%;
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-direction: column;
 | 
					    flex-direction: column;
 | 
				
			||||||
    gap: rem(10);
 | 
					    gap: rem(10);
 | 
				
			||||||
@@ -1,16 +1,8 @@
 | 
				
			|||||||
import { FC } from "react";
 | 
					import { FC } from "react";
 | 
				
			||||||
import styles from "./ProductAndServiceTab.module.css";
 | 
					import styles from "./ProductAndServiceTab.module.css";
 | 
				
			||||||
import ProductView from "./components/ProductView/ProductView.tsx";
 | 
					import ProductView from "./components/ProductView/ProductView.tsx";
 | 
				
			||||||
import {
 | 
					import { Button, Checkbox, Divider, Flex, Group, rem, ScrollArea, Stack, Text, Title } from "@mantine/core";
 | 
				
			||||||
    Button,
 | 
					import CardServicesTable from "./components/CardServicesTable/CardServicesTable.tsx";
 | 
				
			||||||
    Divider,
 | 
					 | 
				
			||||||
    Flex,
 | 
					 | 
				
			||||||
    rem,
 | 
					 | 
				
			||||||
    ScrollArea,
 | 
					 | 
				
			||||||
    Text,
 | 
					 | 
				
			||||||
    Title,
 | 
					 | 
				
			||||||
} from "@mantine/core";
 | 
					 | 
				
			||||||
import CardServicesTable from "./components/DealServicesTable/CardServicesTable.tsx";
 | 
					 | 
				
			||||||
import useCardProductAndServiceTabState from "./hooks/useProductAndServiceTabState.tsx";
 | 
					import useCardProductAndServiceTabState from "./hooks/useProductAndServiceTabState.tsx";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@@ -22,17 +14,19 @@ import {
 | 
				
			|||||||
    ProductService,
 | 
					    ProductService,
 | 
				
			||||||
} from "../../../../client";
 | 
					} from "../../../../client";
 | 
				
			||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
import { CreateProductRequest } from "../../../ProductsPage/types.ts";
 | 
					import { CreateProductRequest } from "../../../../pages/ProductsPage/types.ts";
 | 
				
			||||||
import classNames from "classnames";
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					import GeneralDataForm from "./components/GeneralDataForm/GeneralDataForm.tsx";
 | 
				
			||||||
 | 
					import PrintDealBarcodesButton from "./components/PrintDealBarcodesButton/PrintDealBarcodesButton.tsx";
 | 
				
			||||||
 | 
					import PaymentLinkButton from "./components/PaymentLinkButton/PaymentLinkButton.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProductAndServiceTab: FC = () => {
 | 
					const ProductAndServiceTab: FC = () => {
 | 
				
			||||||
    const { cardState, cardServicesState, cardProductsState } =
 | 
					    const { cardState, cardServicesState, cardProductsState } = useCardProductAndServiceTabState();
 | 
				
			||||||
        useCardProductAndServiceTabState();
 | 
					 | 
				
			||||||
    const isLocked = Boolean(cardState.card?.billRequest || cardState.card?.group?.billRequest);
 | 
					    const isLocked = Boolean(cardState.card?.billRequest || cardState.card?.group?.billRequest);
 | 
				
			||||||
    const onAddProductClick = () => {
 | 
					    const onAddProductClick = () => {
 | 
				
			||||||
        if (!cardProductsState.onCreate || !cardState.card || !cardState.card.clientId) return;
 | 
					        if (!cardProductsState.onCreate || !cardState.card || !cardState.card.clientId) return;
 | 
				
			||||||
        const productIds = cardState.card.products.map(
 | 
					        const productIds = cardState.card.products.map(
 | 
				
			||||||
            product => product.product.id
 | 
					            product => product.product.id,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        modals.openContextModal({
 | 
					        modals.openContextModal({
 | 
				
			||||||
            modal: "addCardProduct",
 | 
					            modal: "addCardProduct",
 | 
				
			||||||
@@ -51,26 +45,26 @@ const ProductAndServiceTab: FC = () => {
 | 
				
			|||||||
                acc +
 | 
					                acc +
 | 
				
			||||||
                row.services.reduce(
 | 
					                row.services.reduce(
 | 
				
			||||||
                    (acc2, row2) => acc2 + row2.price * row.quantity,
 | 
					                    (acc2, row2) => acc2 + row2.price * row.quantity,
 | 
				
			||||||
                    0
 | 
					                    0,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            0
 | 
					            0,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        const cardServicesPrice = cardState.card.services.reduce(
 | 
					        const cardServicesPrice = cardState.card.services.reduce(
 | 
				
			||||||
            (acc, row) => acc + row.price * row.quantity,
 | 
					            (acc, row) => acc + row.price * row.quantity,
 | 
				
			||||||
            0
 | 
					            0,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        return cardServicesPrice + productServicesPrice;
 | 
					        return cardServicesPrice + productServicesPrice;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onCopyServices = (
 | 
					    const onCopyServices = (
 | 
				
			||||||
        sourceProduct: CardProductSchema,
 | 
					        sourceProduct: CardProductSchema,
 | 
				
			||||||
        destinationProducts: CardProductSchema[]
 | 
					        destinationProducts: CardProductSchema[],
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
        if (!cardState.card) return;
 | 
					        if (!cardState.card) return;
 | 
				
			||||||
        CardService.copyProductServices({
 | 
					        CardService.copyProductServices({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                cardId: cardState.card.id,
 | 
					                cardId: cardState.card.id,
 | 
				
			||||||
                destinationProductIds: destinationProducts.map(
 | 
					                destinationProductIds: destinationProducts.map(
 | 
				
			||||||
                    product => product.product.id
 | 
					                    product => product.product.id,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                sourceProductId: sourceProduct.product.id,
 | 
					                sourceProductId: sourceProduct.product.id,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@@ -147,7 +141,7 @@ const ProductAndServiceTab: FC = () => {
 | 
				
			|||||||
                notifications.guess(ok, { message });
 | 
					                notifications.guess(ok, { message });
 | 
				
			||||||
                if (!ok) return;
 | 
					                if (!ok) return;
 | 
				
			||||||
                await cardState.refetch();
 | 
					                await cardState.refetch();
 | 
				
			||||||
            }
 | 
					            },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,11 +206,12 @@ const ProductAndServiceTab: FC = () => {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
            className={classNames(
 | 
					            className={classNames(
 | 
				
			||||||
                styles["container"],
 | 
					                styles["container"],
 | 
				
			||||||
                cardState.card?.billRequest && styles["container-disabled"]
 | 
					                cardState.card?.billRequest && styles["container-disabled"],
 | 
				
			||||||
            )}>
 | 
					            )}>
 | 
				
			||||||
            <div className={styles["products-list"]}>
 | 
					            <div className={styles["products-list"]}>
 | 
				
			||||||
                <ScrollArea offsetScrollbars>
 | 
					                <ScrollArea offsetScrollbars>
 | 
				
			||||||
@@ -235,6 +230,27 @@ const ProductAndServiceTab: FC = () => {
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className={styles["card-container"]}>
 | 
					            <div className={styles["card-container"]}>
 | 
				
			||||||
 | 
					                {cardState.card && (
 | 
				
			||||||
 | 
					                    <Group
 | 
				
			||||||
 | 
					                        className={styles["card-container-wrapper"]}
 | 
				
			||||||
 | 
					                        justify={"space-between"}
 | 
				
			||||||
 | 
					                        wrap={"nowrap"}
 | 
				
			||||||
 | 
					                        mr={"xs"}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <Group wrap={"nowrap"}>
 | 
				
			||||||
 | 
					                            <PrintDealBarcodesButton card={cardState.card} />
 | 
				
			||||||
 | 
					                            <Checkbox
 | 
				
			||||||
 | 
					                                label={"Оплачен"}
 | 
				
			||||||
 | 
					                                checked={cardState.card.billRequest?.paid || cardState.card.group?.billRequest?.paid || false}
 | 
				
			||||||
 | 
					                                disabled
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        </Group>
 | 
				
			||||||
 | 
					                        <PaymentLinkButton card={cardState.card} />
 | 
				
			||||||
 | 
					                    </Group>
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
 | 
					                <Stack className={styles["card-container-wrapper"]} mr={"xs"}>
 | 
				
			||||||
 | 
					                    <GeneralDataForm />
 | 
				
			||||||
 | 
					                </Stack>
 | 
				
			||||||
                <ScrollArea offsetScrollbars>
 | 
					                <ScrollArea offsetScrollbars>
 | 
				
			||||||
                    <Flex
 | 
					                    <Flex
 | 
				
			||||||
                        direction={"column"}
 | 
					                        direction={"column"}
 | 
				
			||||||
@@ -5,7 +5,7 @@ import { ActionIcon, Button, Flex, Modal, NumberInput, rem, Text, Title, Tooltip
 | 
				
			|||||||
import { IconTrash, IconUsersGroup } from "@tabler/icons-react";
 | 
					import { IconTrash, IconUsersGroup } from "@tabler/icons-react";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import { isNumber } from "lodash";
 | 
					import { isNumber } from "lodash";
 | 
				
			||||||
import SimpleUsersTable from "../../../../components/SimpleUsersTable/SimpleUsersTable.tsx";
 | 
					import SimpleUsersTable from "../../../../../../pages/CardsPage/components/SimpleUsersTable/SimpleUsersTable.tsx";
 | 
				
			||||||
import { ServiceType } from "../../../../../../shared/enums/ServiceType.ts";
 | 
					import { ServiceType } from "../../../../../../shared/enums/ServiceType.ts";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { RootState } from "../../../../../../redux/store.ts";
 | 
					import { RootState } from "../../../../../../redux/store.ts";
 | 
				
			||||||
@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					import ShippingWarehouseAutocomplete
 | 
				
			||||||
 | 
					    from "../../../../../../components/Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
				
			||||||
 | 
					import { CardService, ShippingWarehouseSchema } from "../../../../../../client";
 | 
				
			||||||
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
 | 
					import { useCardPageContext } from "../../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
 | 
					import { Button, Checkbox, Stack } from "@mantine/core";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { isEqual } from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GeneralDataFormType = {
 | 
				
			||||||
 | 
					    shippingWarehouse?: ShippingWarehouseSchema | null | string;
 | 
				
			||||||
 | 
					    isServicesProfitAccounted: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const GeneralDataForm = () => {
 | 
				
			||||||
 | 
					    const { selectedCard: card, refetchCard } = useCardPageContext();
 | 
				
			||||||
 | 
					    if (!card) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [initialValues, setInitialValues] = useState<GeneralDataFormType>(card);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const form = useForm<GeneralDataFormType>({
 | 
				
			||||||
 | 
					        initialValues,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        const data = card ?? {};
 | 
				
			||||||
 | 
					        setInitialValues(data);
 | 
				
			||||||
 | 
					        form.setValues(data);
 | 
				
			||||||
 | 
					    }, [card]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isShippingWarehouse = (
 | 
				
			||||||
 | 
					        value: ShippingWarehouseSchema | string | null | undefined,
 | 
				
			||||||
 | 
					    ): value is ShippingWarehouseSchema => {
 | 
				
			||||||
 | 
					        return !!value && !["string"].includes(typeof value);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onSubmit = (values: GeneralDataFormType) => {
 | 
				
			||||||
 | 
					        if (!card) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const shippingWarehouse = isShippingWarehouse(values.shippingWarehouse)
 | 
				
			||||||
 | 
					            ? values.shippingWarehouse.name
 | 
				
			||||||
 | 
					            : values.shippingWarehouse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CardService.updateProductsAndServicesGeneralInfo({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                cardId: card.id,
 | 
				
			||||||
 | 
					                data: {
 | 
				
			||||||
 | 
					                    ...values,
 | 
				
			||||||
 | 
					                    shippingWarehouse,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					            .then(({ ok, message }) => {
 | 
				
			||||||
 | 
					                if (!ok) {
 | 
				
			||||||
 | 
					                    notifications.error({ message });
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                refetchCard();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(err => console.log(err));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <form onSubmit={form.onSubmit(values => onSubmit(values))}>
 | 
				
			||||||
 | 
					            <Stack>
 | 
				
			||||||
 | 
					                <ShippingWarehouseAutocomplete
 | 
				
			||||||
 | 
					                    placeholder={"Введите склад отгрузки"}
 | 
				
			||||||
 | 
					                    label={"Склад отгрузки"}
 | 
				
			||||||
 | 
					                    value={
 | 
				
			||||||
 | 
					                        isShippingWarehouse(
 | 
				
			||||||
 | 
					                            form.values.shippingWarehouse,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                            ? form.values.shippingWarehouse
 | 
				
			||||||
 | 
					                            : undefined
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    onChange={event => {
 | 
				
			||||||
 | 
					                        if (isShippingWarehouse(event)) {
 | 
				
			||||||
 | 
					                            form.getInputProps(
 | 
				
			||||||
 | 
					                                "shippingWarehouse",
 | 
				
			||||||
 | 
					                            ).onChange(event.name);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        form.getInputProps(
 | 
				
			||||||
 | 
					                            "shippingWarehouse",
 | 
				
			||||||
 | 
					                        ).onChange(event);
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <Checkbox
 | 
				
			||||||
 | 
					                    label={"Учет выручки в статистике"}
 | 
				
			||||||
 | 
					                    {...form.getInputProps("isServicesProfitAccounted", { type: "checkbox" })}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <Button
 | 
				
			||||||
 | 
					                    type={"submit"}
 | 
				
			||||||
 | 
					                    variant={"default"}
 | 
				
			||||||
 | 
					                    disabled={isEqual(initialValues, form.values)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                    Сохранить
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					            </Stack>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default GeneralDataForm;
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import { CardSchema } from "../../../../../client";
 | 
					import { CardSchema } from "../../../../../../client";
 | 
				
			||||||
import ButtonCopy from "../../../../../components/ButtonCopy/ButtonCopy.tsx";
 | 
					import ButtonCopy from "../../../../../../components/ButtonCopy/ButtonCopy.tsx";
 | 
				
			||||||
import { ButtonCopyControlled } from "../../../../../components/ButtonCopyControlled/ButtonCopyControlled.tsx";
 | 
					import { ButtonCopyControlled } from "../../../../../../components/ButtonCopyControlled/ButtonCopyControlled.tsx";
 | 
				
			||||||
import { getCurrentDateTimeForFilename } from "../../../../../shared/lib/date.ts";
 | 
					import { getCurrentDateTimeForFilename } from "../../../../../../shared/lib/date.ts";
 | 
				
			||||||
import FileSaver from "file-saver";
 | 
					import FileSaver from "file-saver";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
import { ActionIcon, Tooltip } from "@mantine/core";
 | 
					import { ActionIcon, Group, Tooltip } from "@mantine/core";
 | 
				
			||||||
import styles from "../../../ui/CardsPage.module.css";
 | 
					import styles from "../../../../../../pages/CardsPage/ui/CardsPage.module.css";
 | 
				
			||||||
import { CardSchema, CardService } from "../../../../../client";
 | 
					import { CardSchema, CardService } from "../../../../../../client";
 | 
				
			||||||
import { base64ToBlob } from "../../../../../shared/lib/utils.ts";
 | 
					import { base64ToBlob } from "../../../../../../shared/lib/utils.ts";
 | 
				
			||||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
import { IconBarcode, IconPrinter } from "@tabler/icons-react";
 | 
					import { IconBarcode, IconPrinter } from "@tabler/icons-react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,7 +12,7 @@ type Props = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const PrintDealBarcodesButton = ({ card }: Props) => {
 | 
					const PrintDealBarcodesButton = ({ card }: Props) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <Group wrap={"nowrap"}>
 | 
				
			||||||
            <Tooltip
 | 
					            <Tooltip
 | 
				
			||||||
                className={styles["print-deals-button"]}
 | 
					                className={styles["print-deals-button"]}
 | 
				
			||||||
                label={"Распечатать штрихкоды сделки"}
 | 
					                label={"Распечатать штрихкоды сделки"}
 | 
				
			||||||
@@ -56,7 +56,7 @@ const PrintDealBarcodesButton = ({ card }: Props) => {
 | 
				
			|||||||
                    <IconPrinter />
 | 
					                    <IconPrinter />
 | 
				
			||||||
                </ActionIcon>
 | 
					                </ActionIcon>
 | 
				
			||||||
            </Tooltip>
 | 
					            </Tooltip>
 | 
				
			||||||
        </>
 | 
					        </Group>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7,7 +7,7 @@ import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			|||||||
import { ActionIcon, Button, Flex, Modal, rem, Tooltip } from "@mantine/core";
 | 
					import { ActionIcon, Button, Flex, Modal, rem, Tooltip } from "@mantine/core";
 | 
				
			||||||
import { IconEdit, IconTrash, IconUsersGroup } from "@tabler/icons-react";
 | 
					import { IconEdit, IconTrash, IconUsersGroup } from "@tabler/icons-react";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import SimpleUsersTable from "../../../../components/SimpleUsersTable/SimpleUsersTable.tsx";
 | 
					import SimpleUsersTable from "../../../../../../pages/CardsPage/components/SimpleUsersTable/SimpleUsersTable.tsx";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { RootState } from "../../../../../../redux/store.ts";
 | 
					import { RootState } from "../../../../../../redux/store.ts";
 | 
				
			||||||
import useCardProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
					import useCardProductAndServiceTabState from "../../hooks/useProductAndServiceTabState.tsx";
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { CRUDTableProps } from "../../../../../types/CRUDTable.tsx";
 | 
					import { CRUDTableProps } from "../../../../../types/CRUDTable.tsx";
 | 
				
			||||||
import { CardService, CardServiceSchema, CardProductSchema } from "../../../../../client";
 | 
					import { CardService, CardServiceSchema, CardProductSchema } from "../../../../../client";
 | 
				
			||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useCardState = () => {
 | 
					const useCardState = () => {
 | 
				
			||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
import { ContextModalProps } from "@mantine/modals";
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
import BaseFormModal, {
 | 
					import BaseFormModal, {
 | 
				
			||||||
    CreateEditFormProps,
 | 
					    CreateEditFormProps,
 | 
				
			||||||
} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					} from "../../../../../pages/ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import { CardProductSchema, CardProductServiceSchema } from "../../../client";
 | 
					import { CardProductSchema, CardProductServiceSchema } from "../../../../../client";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { NumberInput } from "@mantine/core";
 | 
					import { NumberInput } from "@mantine/core";
 | 
				
			||||||
import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
 | 
					import ProductSelect from "../../../../../components/ProductSelect/ProductSelect.tsx";
 | 
				
			||||||
import { omit } from "lodash";
 | 
					import { omit } from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
import { ContextModalProps } from "@mantine/modals";
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../../../../pages/ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import { CardServiceSchema } from "../../../client";
 | 
					import { CardServiceSchema } from "../../../../../client";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { ComboboxItem, ComboboxItemGroup, NumberInput, OptionsFilter } from "@mantine/core";
 | 
					import { ComboboxItem, ComboboxItemGroup, NumberInput, OptionsFilter } from "@mantine/core";
 | 
				
			||||||
import ServiceWithPriceInput from "../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
					import ServiceWithPriceInput from "../../../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
				
			||||||
import { ServiceType } from "../../../shared/enums/ServiceType.ts";
 | 
					import { ServiceType } from "../../../../../shared/enums/ServiceType.ts";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { RootState } from "../../../redux/store.ts";
 | 
					import { RootState } from "../../../../../redux/store.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    serviceIds?: number[];
 | 
					    serviceIds?: number[];
 | 
				
			||||||
@@ -1,18 +1,18 @@
 | 
				
			|||||||
import BaseFormModal, {
 | 
					import BaseFormModal, {
 | 
				
			||||||
    CreateEditFormProps,
 | 
					    CreateEditFormProps,
 | 
				
			||||||
} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					} from "../../../../../pages/ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    CardProductServiceSchema,
 | 
					    CardProductServiceSchema,
 | 
				
			||||||
    ServiceSchema,
 | 
					    ServiceSchema,
 | 
				
			||||||
} from "../../../client";
 | 
					} from "../../../../../client";
 | 
				
			||||||
import { ContextModalProps } from "@mantine/modals";
 | 
					import { ContextModalProps } from "@mantine/modals";
 | 
				
			||||||
import { useForm, UseFormReturnType } from "@mantine/form";
 | 
					import { useForm, UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
import { isNil, isNumber } from "lodash";
 | 
					import { isNil, isNumber } from "lodash";
 | 
				
			||||||
import ServiceWithPriceInput from "../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
					import ServiceWithPriceInput from "../../../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
				
			||||||
import { Checkbox, Flex, rem } from "@mantine/core";
 | 
					import { Checkbox, Flex, rem } from "@mantine/core";
 | 
				
			||||||
import { ServiceType } from "../../../shared/enums/ServiceType.ts";
 | 
					import { ServiceType } from "../../../../../shared/enums/ServiceType.ts";
 | 
				
			||||||
import { useSelector } from "react-redux";
 | 
					import { useSelector } from "react-redux";
 | 
				
			||||||
import { RootState } from "../../../redux/store.ts";
 | 
					import { RootState } from "../../../../../redux/store.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps = {
 | 
					type RestProps = {
 | 
				
			||||||
    quantity: number;
 | 
					    quantity: number;
 | 
				
			||||||
@@ -8,7 +8,7 @@ import classes from "../ShippingTab.module.css";
 | 
				
			|||||||
import "mantine-datatable/styles.css";
 | 
					import "mantine-datatable/styles.css";
 | 
				
			||||||
import { useState } from "react";
 | 
					import { useState } from "react";
 | 
				
			||||||
import ShippingProductsTable from "./ShippingProductsTable.tsx";
 | 
					import ShippingProductsTable from "./ShippingProductsTable.tsx";
 | 
				
			||||||
import { Group, rem, Text } from "@mantine/core";
 | 
					import { Flex, rem, Text } from "@mantine/core";
 | 
				
			||||||
import { ShippingProductParentData } from "../types/ShippingProductData.tsx";
 | 
					import { ShippingProductParentData } from "../types/ShippingProductData.tsx";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import InlineShippingButton from "./InlineShippingButton.tsx";
 | 
					import InlineShippingButton from "./InlineShippingButton.tsx";
 | 
				
			||||||
@@ -63,15 +63,15 @@ const BoxesTable = ({ items, onCreateShippingProduct }: Props) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const getBoxActions = (box: BoxSchema) => {
 | 
					    const getBoxActions = (box: BoxSchema) => {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <Group wrap={"nowrap"} gap={rem(10)}>
 | 
					            <Flex wrap={"nowrap"} direction={"row-reverse"} gap={rem(10)}>
 | 
				
			||||||
 | 
					                <InlineShippingButton onClick={() => onDeleteBoxClick(box)}>
 | 
				
			||||||
 | 
					                    <IconTrash />
 | 
				
			||||||
 | 
					                </InlineShippingButton>
 | 
				
			||||||
                <InlineShippingButton onClick={() => onCreateShippingProduct({ boxId: box.id })}>
 | 
					                <InlineShippingButton onClick={() => onCreateShippingProduct({ boxId: box.id })}>
 | 
				
			||||||
                    <IconPlus />
 | 
					                    <IconPlus />
 | 
				
			||||||
                    Товар
 | 
					                    Товар
 | 
				
			||||||
                </InlineShippingButton>
 | 
					                </InlineShippingButton>
 | 
				
			||||||
                <InlineShippingButton onClick={() => onDeleteBoxClick(box)}>
 | 
					            </Flex>
 | 
				
			||||||
                    <IconTrash />
 | 
					 | 
				
			||||||
                </InlineShippingButton>
 | 
					 | 
				
			||||||
            </Group>
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import { Flex, rem, Stack } from "@mantine/core";
 | 
					import { Flex, rem, Stack } from "@mantine/core";
 | 
				
			||||||
import { BoxSchema, PalletSchema, ShippingProductSchema } from "../../../../../client";
 | 
					import { BoxSchema, PalletSchema, ShippingProductSchema } from "../../../../../client";
 | 
				
			||||||
import ShippingProductsTable from "./ShippingProductsTable.tsx";
 | 
					import ShippingProductsTable from "./ShippingProductsTable.tsx";
 | 
				
			||||||
@@ -5,7 +5,7 @@ import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			|||||||
import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import useUpdateCard from "./useUpdateCard.tsx";
 | 
					import useUpdateCard from "./useUpdateCard.tsx";
 | 
				
			||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useShippingTableColumns = () => {
 | 
					const useShippingTableColumns = () => {
 | 
				
			||||||
    const { update } = useUpdateCard();
 | 
					    const { update } = useUpdateCard();
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    CreateBoxInCardSchema,
 | 
					    CreateBoxInCardSchema,
 | 
				
			||||||
    CreateBoxInPalletSchema, PalletSchema,
 | 
					    CreateBoxInPalletSchema, PalletSchema,
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useShippingQrs = () => {
 | 
					const useShippingQrs = () => {
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { useCardPageContext } from "../../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../../pages/CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import { CardService } from "../../../../../client";
 | 
					import { CardService } from "../../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useUpdateCard = () => {
 | 
					const useUpdateCard = () => {
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/modules/connectModules.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/modules/connectModules.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import { ModuleNames } from "./modules.tsx";
 | 
				
			||||||
 | 
					import ClientTab from "./cardModules/cardEditorTabs/ClientTab/ClientTab.tsx";
 | 
				
			||||||
 | 
					import ModulesType from "./types.tsx";
 | 
				
			||||||
 | 
					import ProductAndServiceTab from "./cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx";
 | 
				
			||||||
 | 
					import EmployeesTab from "./cardModules/cardEditorTabs/EmployeesTab/EmployeesTab.tsx";
 | 
				
			||||||
 | 
					import ShippingTab from "./cardModules/cardEditorTabs/ShippingTab/ShippingTab.tsx";
 | 
				
			||||||
 | 
					import ManagerTab from "./cardModules/cardEditorTabs/ManagersTab/ManagersTab.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const connectModules = (modules: ModulesType) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    modules[ModuleNames.CLIENTS].tab = <ClientTab />;
 | 
				
			||||||
 | 
					    modules[ModuleNames.SERVICES_AND_PRODUCTS].tab = <ProductAndServiceTab />;
 | 
				
			||||||
 | 
					    modules[ModuleNames.EMPLOYEES].tab = <EmployeesTab />;
 | 
				
			||||||
 | 
					    modules[ModuleNames.SHIPMENT].tab = <ShippingTab />;
 | 
				
			||||||
 | 
					    modules[ModuleNames.MANAGERS].tab = <ManagerTab />;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return modules;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default connectModules;
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/modules/context/ModulesContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/modules/context/ModulesContext.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					import React, { createContext, FC, useContext, useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { useProjectsContext } from "../../contexts/ProjectsContext.tsx";
 | 
				
			||||||
 | 
					import { MODULES } from "../modules.tsx";
 | 
				
			||||||
 | 
					import { Module } from "../types.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ModulesContextState = {
 | 
				
			||||||
 | 
					    modules: Module[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ModulesContext = createContext<ModulesContextState | undefined>(
 | 
				
			||||||
 | 
					    undefined,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useModulesContextState = () => {
 | 
				
			||||||
 | 
					    const { selectedProject } = useProjectsContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [modules, setModules] = useState<Module[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        const modules = selectedProject?.modules ?? [];
 | 
				
			||||||
 | 
					        const projectModules = modules.map(module => {
 | 
				
			||||||
 | 
					            return MODULES[module.key];
 | 
				
			||||||
 | 
					        }) ?? [];
 | 
				
			||||||
 | 
					        setModules(projectModules);
 | 
				
			||||||
 | 
					    }, [selectedProject?.id]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        modules,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CardPageContextProviderProps = {
 | 
				
			||||||
 | 
					    children: React.ReactNode;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ModulesContextProvider: FC<CardPageContextProviderProps> = ({ children }) => {
 | 
				
			||||||
 | 
					    const state = useModulesContextState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ModulesContext.Provider value={state}>
 | 
				
			||||||
 | 
					            {children}
 | 
				
			||||||
 | 
					        </ModulesContext.Provider>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useModulesContext = () => {
 | 
				
			||||||
 | 
					    const context = useContext(ModulesContext);
 | 
				
			||||||
 | 
					    if (!context) {
 | 
				
			||||||
 | 
					        throw new Error(
 | 
				
			||||||
 | 
					            "useModulesContext must be used within a ModulesContextProvider",
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return context;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/modules/modules.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/modules/modules.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { IconUser, IconBox, IconCubeSend, IconUsersGroup, IconUserCog } from "@tabler/icons-react"
 | 
				
			||||||
 | 
					import ModulesType from "./types.tsx";
 | 
				
			||||||
 | 
					import connectModules from "./connectModules.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum ModuleNames {
 | 
				
			||||||
 | 
						CLIENTS = "clients",
 | 
				
			||||||
 | 
						SERVICES_AND_PRODUCTS = "servicesAndProducts",
 | 
				
			||||||
 | 
						SHIPMENT = "shipment",
 | 
				
			||||||
 | 
						EMPLOYEES = "employees",
 | 
				
			||||||
 | 
						MANAGERS = "managers"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const modules: ModulesType = {
 | 
				
			||||||
 | 
						[ModuleNames.CLIENTS]: { info: { label: "Клиенты", key: "clients", icon: <IconUser /> } },
 | 
				
			||||||
 | 
						[ModuleNames.SERVICES_AND_PRODUCTS]: { info: { label: "Товары и услуги", key: "servicesAndProducts", icon: <IconBox /> } },
 | 
				
			||||||
 | 
						[ModuleNames.SHIPMENT]: { info: { label: "Отгрузка", key: "shipment", icon: <IconCubeSend /> } },
 | 
				
			||||||
 | 
						[ModuleNames.EMPLOYEES]: { info: { label: "Сотрудники", key: "employees", icon: <IconUsersGroup /> } },
 | 
				
			||||||
 | 
						[ModuleNames.MANAGERS]: { info: { label: "Менеджер", key: "managers", icon: <IconUserCog /> } }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const MODULES = connectModules(modules);
 | 
				
			||||||
							
								
								
									
										61
									
								
								src/modules/modulesFileGen/modulesFileGen.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/modules/modulesFileGen/modulesFileGen.cjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					Object.defineProperty(exports, "__esModule", { value: true });
 | 
				
			||||||
 | 
					var axios_1 = require("axios");
 | 
				
			||||||
 | 
					var fs = require("fs");
 | 
				
			||||||
 | 
					// endregion
 | 
				
			||||||
 | 
					var OUTPUT_FILE = "./src/modules/modules.tsx";
 | 
				
			||||||
 | 
					function camelToConstCase(camelStr) {
 | 
				
			||||||
 | 
					    return camelStr
 | 
				
			||||||
 | 
					        .replace(/([a-z])([A-Z])/g, "$1_$2")
 | 
				
			||||||
 | 
					        .toUpperCase();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var writeToFile = function (data) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        fs.writeFileSync(OUTPUT_FILE, data.trim());
 | 
				
			||||||
 | 
					        console.log("File successfully generated.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    catch (error) {
 | 
				
			||||||
 | 
					        console.error(error);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					var getImports = function (modules) {
 | 
				
			||||||
 | 
					    var prefix = "import { ";
 | 
				
			||||||
 | 
					    var postfix = " } from \"@tabler/icons-react\"\n" +
 | 
				
			||||||
 | 
					        "import ModulesType from \"./types.tsx\";\n" +
 | 
				
			||||||
 | 
					        "import connectModules from \"./connectModules.tsx\";";
 | 
				
			||||||
 | 
					    var filteredModules = modules.filter(function (module) { return module.iconName; });
 | 
				
			||||||
 | 
					    var icons = filteredModules.map(function (module) { return module.iconName; }).join(", ");
 | 
				
			||||||
 | 
					    return prefix + icons + postfix;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					var getModuleNames = function (modules) {
 | 
				
			||||||
 | 
					    return modules.map(function (module) {
 | 
				
			||||||
 | 
					        return "".concat(camelToConstCase(module.key), " = \"").concat(module.key, "\"");
 | 
				
			||||||
 | 
					    }).join(",\n\t");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					var getModules = function (modules) {
 | 
				
			||||||
 | 
					    return modules.map(function (module) {
 | 
				
			||||||
 | 
					        var iconStr = "null";
 | 
				
			||||||
 | 
					        if (module.iconName) {
 | 
				
			||||||
 | 
					            iconStr = "<" + module.iconName + " />";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "[ModuleNames.".concat(camelToConstCase(module.key), "]: { info: { label: \"").concat(module.label, "\", key: \"").concat(module.key, "\", icon: ").concat(iconStr, " } }");
 | 
				
			||||||
 | 
					    }).join(",\n\t");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					var generateRows = function (modules) {
 | 
				
			||||||
 | 
					    var imports = getImports(modules);
 | 
				
			||||||
 | 
					    var moduleNames = "\n\nexport enum ModuleNames {\n\t".concat(getModuleNames(modules), "\n}\n");
 | 
				
			||||||
 | 
					    var modulesStr = "\nconst modules: ModulesType = {\n\t".concat(getModules(modules), "\n};\n");
 | 
				
			||||||
 | 
					    var connectModules = "\nexport const MODULES = connectModules(modules);";
 | 
				
			||||||
 | 
					    var result = imports + moduleNames + modulesStr + connectModules;
 | 
				
			||||||
 | 
					    writeToFile(result);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					var modulesFileGen = function () {
 | 
				
			||||||
 | 
					    console.log("Start file generation...");
 | 
				
			||||||
 | 
					    axios_1.default
 | 
				
			||||||
 | 
					        .get("http://127.0.0.1:8000/project/modules")
 | 
				
			||||||
 | 
					        .then(function (response) {
 | 
				
			||||||
 | 
					        generateRows(response.data.modules);
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					        .catch(function (err) { return console.log(err); });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					modulesFileGen();
 | 
				
			||||||
							
								
								
									
										86
									
								
								src/modules/modulesFileGen/modulesFileGen.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/modules/modulesFileGen/modulesFileGen.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					import axios, { AxiosResponse } from "axios";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as fs from 'fs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// region Types
 | 
				
			||||||
 | 
					type Module = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    key: string;
 | 
				
			||||||
 | 
					    label: string;
 | 
				
			||||||
 | 
					    iconName?: string;
 | 
				
			||||||
 | 
					    isDeleted: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ModulesResponse = {
 | 
				
			||||||
 | 
					    modules: Module[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const OUTPUT_FILE = "./src/modules/modules.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function camelToConstCase(camelStr: string): string {
 | 
				
			||||||
 | 
					    return camelStr
 | 
				
			||||||
 | 
					        .replace(/([a-z])([A-Z])/g, "$1_$2")
 | 
				
			||||||
 | 
					        .toUpperCase();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const writeToFile = (data: string) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        fs.writeFileSync(OUTPUT_FILE, data.trim());
 | 
				
			||||||
 | 
					        console.log("File successfully generated.");
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					        console.error(error);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getImports = (modules: Module[]): string => {
 | 
				
			||||||
 | 
					    const prefix = "import { ";
 | 
				
			||||||
 | 
					    const postfix = " } from \"@tabler/icons-react\"\n" +
 | 
				
			||||||
 | 
					        "import ModulesType from \"./types.tsx\";\n" +
 | 
				
			||||||
 | 
					        "import connectModules from \"./connectModules.tsx\";";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const filteredModules = modules.filter(module => module.iconName);
 | 
				
			||||||
 | 
					    const icons = filteredModules.map((module: Module) => module.iconName).join(", ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return prefix + icons + postfix;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getModuleNames = (modules: Module[]) => {
 | 
				
			||||||
 | 
					    return modules.map(module => {
 | 
				
			||||||
 | 
					        return `${camelToConstCase(module.key)} = "${module.key}"`;
 | 
				
			||||||
 | 
					    }).join(",\n\t");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getModules = (modules: Module[]) => {
 | 
				
			||||||
 | 
					    return modules.map(module => {
 | 
				
			||||||
 | 
					        let iconStr = "null";
 | 
				
			||||||
 | 
					        if (module.iconName) {
 | 
				
			||||||
 | 
					            iconStr = "<" + module.iconName + " />";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return `[ModuleNames.${camelToConstCase(module.key)}]: { info: { label: "${module.label}", key: "${module.key}", icon: ${iconStr} } }`;
 | 
				
			||||||
 | 
					    }).join(",\n\t");
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateRows = (modules: Module[]) => {
 | 
				
			||||||
 | 
					    const imports = getImports(modules);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const moduleNames = `\n\nexport enum ModuleNames {\n\t${getModuleNames(modules)}\n}\n`;
 | 
				
			||||||
 | 
					    const modulesStr = `\nconst modules: ModulesType = {\n\t${getModules(modules)}\n};\n`;
 | 
				
			||||||
 | 
					    const connectModules = "\nexport const MODULES = connectModules(modules);";
 | 
				
			||||||
 | 
					    const result: string = imports + moduleNames + modulesStr + connectModules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    writeToFile(result);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const modulesFileGen = () => {
 | 
				
			||||||
 | 
					    console.log("Start file generation...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    axios
 | 
				
			||||||
 | 
					        .get("http://127.0.0.1:8000/project/modules")
 | 
				
			||||||
 | 
					        .then((response: AxiosResponse<ModulesResponse>) => {
 | 
				
			||||||
 | 
					            generateRows(response.data.modules);
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .catch(err => console.log(err));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					modulesFileGen();
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/modules/types.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/modules/types.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import { ReactNode } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Module = {
 | 
				
			||||||
 | 
					    info: {
 | 
				
			||||||
 | 
					        label: string;
 | 
				
			||||||
 | 
					        key: string;
 | 
				
			||||||
 | 
					        icon: ReactNode;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    tab?: ReactNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Modules = {
 | 
				
			||||||
 | 
					    [key: string]: Module;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Modules;
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { ProjectSchema } from "../../../client";
 | 
					import { ProjectSchema } from "../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum Modules {
 | 
					export enum Modules {
 | 
				
			||||||
    SERVICES_AND_PRODUCTS = "servicesAndProducts",
 | 
					    SERVICES_AND_PRODUCTS = "servicesAndProducts",
 | 
				
			||||||
@@ -6,7 +6,6 @@ export enum Modules {
 | 
				
			|||||||
    EMPLOYEES = "employees",
 | 
					    EMPLOYEES = "employees",
 | 
				
			||||||
    CLIENTS = "clients",
 | 
					    CLIENTS = "clients",
 | 
				
			||||||
    MANAGERS = "managers",
 | 
					    MANAGERS = "managers",
 | 
				
			||||||
    MEGA_MODULE = "hui",
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isModuleInProject = (module: Modules, project?: ProjectSchema | null) => {
 | 
					const isModuleInProject = (module: Modules, project?: ProjectSchema | null) => {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { useParams } from "@tanstack/react-router";
 | 
					import { useParams } from "@tanstack/react-router";
 | 
				
			||||||
import { CardPageContextProvider, useCardPageContext } from "../../CardsPage/contexts/CardPageContext.tsx";
 | 
					import { CardPageContextProvider, useCardPageContext } from "../../CardsPage/contexts/CardPageContext.tsx";
 | 
				
			||||||
import ProductAndServiceTab from "../../CardsPage/tabs/ProductAndServiceTab/ProductAndServiceTab.tsx";
 | 
					import ProductAndServiceTab from "../../../modules/cardModules/cardEditorTabs/ProductAndServiceTab/ProductAndServiceTab.tsx";
 | 
				
			||||||
import React, { FC, useEffect } from "react";
 | 
					import React, { FC, useEffect } from "react";
 | 
				
			||||||
import { CardService } from "../../../client";
 | 
					import { CardService } from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,12 @@
 | 
				
			|||||||
import { Box, Drawer, rem, Tabs } from "@mantine/core";
 | 
					import { Box, Drawer, rem, Tabs } from "@mantine/core";
 | 
				
			||||||
import { FC, ReactNode, useEffect } from "react";
 | 
					import { FC, ReactNode, useEffect } from "react";
 | 
				
			||||||
import { useCardPageContext } from "../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../contexts/CardPageContext.tsx";
 | 
				
			||||||
import { IconBox, IconCalendarUser, IconCubeSend, IconSettings, IconUser, IconUsersGroup } from "@tabler/icons-react";
 | 
					import { IconCalendarUser, IconSettings } from "@tabler/icons-react";
 | 
				
			||||||
import CardStatusChangeTable from "../../components/CardStatusChangeTable/CardStatusChangeTable.tsx";
 | 
					import CardStatusChangeTable from "./tabs/CardStatusChangeTable/CardStatusChangeTable.tsx";
 | 
				
			||||||
import GeneralTab from "../../tabs/GeneralTab/GeneralTab.tsx";
 | 
					import GeneralTab from "./tabs/GeneralTab/GeneralTab.tsx";
 | 
				
			||||||
import { useQueryClient } from "@tanstack/react-query";
 | 
					import { useQueryClient } from "@tanstack/react-query";
 | 
				
			||||||
import ProductAndServiceTab from "../../tabs/ProductAndServiceTab/ProductAndServiceTab.tsx";
 | 
					 | 
				
			||||||
import { motion } from "framer-motion";
 | 
					import { motion } from "framer-motion";
 | 
				
			||||||
import ShippingTab from "../../tabs/ShippingTab/ShippingTab.tsx";
 | 
					import { useModulesContext } from "../../../../modules/context/ModulesContext.tsx";
 | 
				
			||||||
import EmployeesTab from "../../tabs/EmployeesTab/EmployeesTab.tsx";
 | 
					 | 
				
			||||||
import ClientTab from "../../tabs/ClientTab/ClientTab.tsx";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useCardStatusChangeState = () => {
 | 
					const useCardStatusChangeState = () => {
 | 
				
			||||||
    const { selectedCard } = useCardPageContext();
 | 
					    const { selectedCard } = useCardPageContext();
 | 
				
			||||||
@@ -36,8 +33,7 @@ const CardEditDrawer: FC = () => {
 | 
				
			|||||||
    const { isVisible, onClose } = useCardEditDrawerState();
 | 
					    const { isVisible, onClose } = useCardEditDrawerState();
 | 
				
			||||||
    const queryClient = useQueryClient();
 | 
					    const queryClient = useQueryClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { selectedCard } = useCardPageContext();
 | 
					    const { modules } = useModulesContext();
 | 
				
			||||||
    const modules = new Set<string>(selectedCard?.board.project.modules.map(module => module.key));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (isVisible) return;
 | 
					        if (isVisible) return;
 | 
				
			||||||
@@ -62,23 +58,27 @@ const CardEditDrawer: FC = () => {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getTab = (
 | 
					    const getTabs = () => {
 | 
				
			||||||
        key: string,
 | 
					        const moduleTabs = modules.map(module => (
 | 
				
			||||||
        icon: ReactNode,
 | 
					            <Tabs.Tab
 | 
				
			||||||
        label: string,
 | 
					                value={module.info.key}
 | 
				
			||||||
        enablingModules: string[] | null = null, // Show if at least one of modules is in project
 | 
					                leftSection={module.info.icon}
 | 
				
			||||||
    ) => {
 | 
					            >
 | 
				
			||||||
        if (!enablingModules) {
 | 
					                {module.info.label}
 | 
				
			||||||
            enablingModules = [key];
 | 
					            </Tabs.Tab>
 | 
				
			||||||
        }
 | 
					        ));
 | 
				
			||||||
        if (!enablingModules.some(key => modules.has(key))) return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <Tabs.Tab
 | 
					            <>{moduleTabs}</>
 | 
				
			||||||
                value={key}
 | 
					        );
 | 
				
			||||||
                leftSection={icon}>
 | 
					    };
 | 
				
			||||||
                {label}
 | 
					
 | 
				
			||||||
            </Tabs.Tab>
 | 
					    const getTabPanels = () => {
 | 
				
			||||||
 | 
					        const moduleTabPanels = modules.map(
 | 
				
			||||||
 | 
					            module => getTabPanel(module.info.key, module.tab),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            <>{moduleTabPanels}</>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,18 +115,12 @@ const CardEditDrawer: FC = () => {
 | 
				
			|||||||
                        leftSection={<IconCalendarUser />}>
 | 
					                        leftSection={<IconCalendarUser />}>
 | 
				
			||||||
                        История
 | 
					                        История
 | 
				
			||||||
                    </Tabs.Tab>
 | 
					                    </Tabs.Tab>
 | 
				
			||||||
                    {getTab("clients", <IconUser />, "Клиент", ["servicesAndProducts", "clients"])}
 | 
					                    {getTabs()}
 | 
				
			||||||
                    {getTab("servicesAndProducts", <IconBox />, "Товары и услуги")}
 | 
					 | 
				
			||||||
                    {getTab("shipment", <IconCubeSend />, "Отгрузка")}
 | 
					 | 
				
			||||||
                    {getTab("employees", <IconUsersGroup />, "Исполнители")}
 | 
					 | 
				
			||||||
                </Tabs.List>
 | 
					                </Tabs.List>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                {getTabPanel("general", <GeneralTab />)}
 | 
					                {getTabPanel("general", <GeneralTab />)}
 | 
				
			||||||
                {getTabPanel("clients", <ClientTab />)}
 | 
					 | 
				
			||||||
                {getTabPanel("history", <CardEditDrawerStatusChangeTable />)}
 | 
					                {getTabPanel("history", <CardEditDrawerStatusChangeTable />)}
 | 
				
			||||||
                {getTabPanel("servicesAndProducts", <ProductAndServiceTab />)}
 | 
					                {getTabPanels()}
 | 
				
			||||||
                {getTabPanel("shipment", <ShippingTab />)}
 | 
					 | 
				
			||||||
                {getTabPanel("employees", <EmployeesTab />)}
 | 
					 | 
				
			||||||
            </Tabs>
 | 
					            </Tabs>
 | 
				
			||||||
        </Drawer>
 | 
					        </Drawer>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { CardStatusHistorySchema } from "../../../../client";
 | 
					import { CardStatusHistorySchema } from "../../../../../../client";
 | 
				
			||||||
import { useDealStatusChangeTableColumns } from "./columns.tsx";
 | 
					import { useDealStatusChangeTableColumns } from "./columns.tsx";
 | 
				
			||||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
 | 
					import { BaseTable } from "../../../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
import { FC } from "react";
 | 
					import { FC } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { useMemo } from "react";
 | 
					import { useMemo } from "react";
 | 
				
			||||||
import { MRT_ColumnDef } from "mantine-react-table";
 | 
					import { MRT_ColumnDef } from "mantine-react-table";
 | 
				
			||||||
import { CardStatusHistorySchema } from "../../../../client";
 | 
					import { CardStatusHistorySchema } from "../../../../../../client";
 | 
				
			||||||
import { Spoiler, Text } from "@mantine/core";
 | 
					import { Spoiler, Text } from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useDealStatusChangeTableColumns = () => {
 | 
					export const useDealStatusChangeTableColumns = () => {
 | 
				
			||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import { FC, useState } from "react";
 | 
					import { FC, useState } from "react";
 | 
				
			||||||
import { useCardPageContext } from "../../contexts/CardPageContext.tsx";
 | 
					import { useCardPageContext } from "../../../../contexts/CardPageContext.tsx";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    Button,
 | 
					    Button,
 | 
				
			||||||
    Checkbox,
 | 
					    Checkbox,
 | 
				
			||||||
@@ -14,31 +14,17 @@ import {
 | 
				
			|||||||
    TextInput,
 | 
					    TextInput,
 | 
				
			||||||
} from "@mantine/core";
 | 
					} from "@mantine/core";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import {
 | 
					import { CardSchema, CardService, ClientService, ProjectSchema, StatusSchema } from "../../../../../../client";
 | 
				
			||||||
    CardSchema,
 | 
					 | 
				
			||||||
    CardService,
 | 
					 | 
				
			||||||
    ClientService,
 | 
					 | 
				
			||||||
    ProjectSchema,
 | 
					 | 
				
			||||||
    ShippingWarehouseSchema,
 | 
					 | 
				
			||||||
    StatusSchema,
 | 
					 | 
				
			||||||
} from "../../../../client";
 | 
					 | 
				
			||||||
import { isEqual } from "lodash";
 | 
					import { isEqual } from "lodash";
 | 
				
			||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
					import { notifications } from "../../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
import { useQueryClient } from "@tanstack/react-query";
 | 
					import { useQueryClient } from "@tanstack/react-query";
 | 
				
			||||||
import ShippingWarehouseAutocomplete
 | 
					import { ButtonCopyControlled } from "../../../../../../components/ButtonCopyControlled/ButtonCopyControlled.tsx";
 | 
				
			||||||
    from "../../../../components/Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
					 | 
				
			||||||
import { ButtonCopyControlled } from "../../../../components/ButtonCopyControlled/ButtonCopyControlled.tsx";
 | 
					 | 
				
			||||||
import { useClipboard } from "@mantine/hooks";
 | 
					import { useClipboard } from "@mantine/hooks";
 | 
				
			||||||
import ManagerSelect from "../../../../components/ManagerSelect/ManagerSelect.tsx";
 | 
					import ProjectSelect from "../../../../../../components/ProjectSelect/ProjectSelect.tsx";
 | 
				
			||||||
import ProjectSelect from "../../../../components/ProjectSelect/ProjectSelect.tsx";
 | 
					import BoardSelect from "../../../../../../components/BoardSelect/BoardSelect.tsx";
 | 
				
			||||||
import BoardSelect from "../../../../components/BoardSelect/BoardSelect.tsx";
 | 
					import CardStatusSelect from "../../../../../../components/DealStatusSelect/CardStatusSelect.tsx";
 | 
				
			||||||
import DealStatusSelect from "../../../../components/DealStatusSelect/DealStatusSelect.tsx";
 | 
					import CardAttributeFields from "../../../../../../components/CardAttributeFields/CardAttributeFields.tsx";
 | 
				
			||||||
import CardAttributeFields from "../../../../components/CardAttributeFields/CardAttributeFields.tsx";
 | 
					import getAttributesFromCard from "../../../../../../components/CardAttributeFields/utils/getAttributesFromCard.ts";
 | 
				
			||||||
import getAttributesFromCard from "../../../../components/CardAttributeFields/utils/getAttributesFromCard.ts";
 | 
					 | 
				
			||||||
import isModuleInProject, { Modules } from "../../utils/isModuleInProject.ts";
 | 
					 | 
				
			||||||
import PaymentLinkButton from "./components/PaymentLinkButton.tsx";
 | 
					 | 
				
			||||||
import PrintDealBarcodesButton from "./components/PrintDealBarcodesButton.tsx";
 | 
					 | 
				
			||||||
import ClientSelect from "../../../../components/Selects/ClientSelect/ClientSelect.tsx";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    card: CardSchema;
 | 
					    card: CardSchema;
 | 
				
			||||||
@@ -56,10 +42,6 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
    const queryClient = useQueryClient();
 | 
					    const queryClient = useQueryClient();
 | 
				
			||||||
    const [project, setProject] = useState<ProjectSchema | null>(card.board.project);
 | 
					    const [project, setProject] = useState<ProjectSchema | null>(card.board.project);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isServicesAndProductsIncluded = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, card.board.project);
 | 
					 | 
				
			||||||
    const isManagerIncluded = isModuleInProject(Modules.MANAGERS, card.board.project);
 | 
					 | 
				
			||||||
    const isClientIncluded = isModuleInProject(Modules.CLIENTS, card.board.project);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const getInitialValues = (card: CardSchema): CardGeneralFormType => {
 | 
					    const getInitialValues = (card: CardSchema): CardGeneralFormType => {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...card,
 | 
					            ...card,
 | 
				
			||||||
@@ -99,7 +81,6 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
                    statusId: values.status.id,
 | 
					                    statusId: values.status.id,
 | 
				
			||||||
                    boardId: values.board.id,
 | 
					                    boardId: values.board.id,
 | 
				
			||||||
                    clientId: values.client?.id ?? null,
 | 
					                    clientId: values.client?.id ?? null,
 | 
				
			||||||
                    shippingWarehouse: values.shippingWarehouse?.toString(),
 | 
					 | 
				
			||||||
                    attributes,
 | 
					                    attributes,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@@ -107,7 +88,6 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
            notifications.guess(ok, { message });
 | 
					            notifications.guess(ok, { message });
 | 
				
			||||||
            if (!ok) return;
 | 
					            if (!ok) return;
 | 
				
			||||||
            CardService.getCardById({ cardId: card.id }).then(data => {
 | 
					            CardService.getCardById({ cardId: card.id }).then(data => {
 | 
				
			||||||
                console.log(data);
 | 
					 | 
				
			||||||
                setSelectedCard(data);
 | 
					                setSelectedCard(data);
 | 
				
			||||||
                initialValues = getInitialValues(data);
 | 
					                initialValues = getInitialValues(data);
 | 
				
			||||||
                form.setValues(initialValues);
 | 
					                form.setValues(initialValues);
 | 
				
			||||||
@@ -131,21 +111,7 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
            await updateClientInfo(values);
 | 
					            await updateClientInfo(values);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const shippingWarehouse = isShippingWarehouse(values.shippingWarehouse)
 | 
					        await updateCardInfo(values);
 | 
				
			||||||
            ? values.shippingWarehouse.name
 | 
					 | 
				
			||||||
            : values.shippingWarehouse;
 | 
					 | 
				
			||||||
        await updateCardInfo(
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                ...values,
 | 
					 | 
				
			||||||
                shippingWarehouse,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const isShippingWarehouse = (
 | 
					 | 
				
			||||||
        value: ShippingWarehouseSchema | string | null | undefined,
 | 
					 | 
				
			||||||
    ): value is ShippingWarehouseSchema => {
 | 
					 | 
				
			||||||
        return !!value && !["string"].includes(typeof value);
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const onCopyGuestUrlClick = () => {
 | 
					    const onCopyGuestUrlClick = () => {
 | 
				
			||||||
@@ -196,7 +162,7 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
                                    {...form.getInputProps("board")}
 | 
					                                    {...form.getInputProps("board")}
 | 
				
			||||||
                                    label={"Доска"}
 | 
					                                    label={"Доска"}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                <DealStatusSelect
 | 
					                                <CardStatusSelect
 | 
				
			||||||
                                    board={form.values.board}
 | 
					                                    board={form.values.board}
 | 
				
			||||||
                                    {...form.getInputProps("status")}
 | 
					                                    {...form.getInputProps("status")}
 | 
				
			||||||
                                    label={"Статус"}
 | 
					                                    label={"Статус"}
 | 
				
			||||||
@@ -211,49 +177,6 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
                                    placeholder={"Введите коментарий"}
 | 
					                                    placeholder={"Введите коментарий"}
 | 
				
			||||||
                                    {...form.getInputProps("comment")}
 | 
					                                    {...form.getInputProps("comment")}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                                {isClientIncluded && (
 | 
					 | 
				
			||||||
                                    <ClientSelect
 | 
					 | 
				
			||||||
                                        {...form.getInputProps("client")}
 | 
					 | 
				
			||||||
                                        withLabel
 | 
					 | 
				
			||||||
                                    />
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                                {isServicesAndProductsIncluded && (
 | 
					 | 
				
			||||||
                                    <ShippingWarehouseAutocomplete
 | 
					 | 
				
			||||||
                                        placeholder={"Введите склад отгрузки"}
 | 
					 | 
				
			||||||
                                        label={"Склад отгрузки"}
 | 
					 | 
				
			||||||
                                        value={
 | 
					 | 
				
			||||||
                                            isShippingWarehouse(
 | 
					 | 
				
			||||||
                                                form.values.shippingWarehouse,
 | 
					 | 
				
			||||||
                                            )
 | 
					 | 
				
			||||||
                                                ? form.values.shippingWarehouse
 | 
					 | 
				
			||||||
                                                : undefined
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                        onChange={event => {
 | 
					 | 
				
			||||||
                                            if (isShippingWarehouse(event)) {
 | 
					 | 
				
			||||||
                                                form.getInputProps(
 | 
					 | 
				
			||||||
                                                    "shippingWarehouse",
 | 
					 | 
				
			||||||
                                                ).onChange(event.name);
 | 
					 | 
				
			||||||
                                                return;
 | 
					 | 
				
			||||||
                                            }
 | 
					 | 
				
			||||||
                                            form.getInputProps(
 | 
					 | 
				
			||||||
                                                "shippingWarehouse",
 | 
					 | 
				
			||||||
                                            ).onChange(event);
 | 
					 | 
				
			||||||
                                        }}
 | 
					 | 
				
			||||||
                                    />
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                                {isManagerIncluded && (
 | 
					 | 
				
			||||||
                                    <ManagerSelect
 | 
					 | 
				
			||||||
                                        placeholder={"Укажите менеджера"}
 | 
					 | 
				
			||||||
                                        label={"Менеджер"}
 | 
					 | 
				
			||||||
                                        {...form.getInputProps("manager")}
 | 
					 | 
				
			||||||
                                    />
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                                {isServicesAndProductsIncluded && (
 | 
					 | 
				
			||||||
                                    <Checkbox
 | 
					 | 
				
			||||||
                                        label={"Учет выручки с услуг в статистике"}
 | 
					 | 
				
			||||||
                                        {...form.getInputProps("isServicesProfitAccounted", { type: "checkbox" })}
 | 
					 | 
				
			||||||
                                    />
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                                {project && (
 | 
					                                {project && (
 | 
				
			||||||
                                    <CardAttributeFields
 | 
					                                    <CardAttributeFields
 | 
				
			||||||
                                        project={project}
 | 
					                                        project={project}
 | 
				
			||||||
@@ -273,17 +196,6 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
                        align={"center"}
 | 
					                        align={"center"}
 | 
				
			||||||
                        gap={rem(10)}
 | 
					                        gap={rem(10)}
 | 
				
			||||||
                        justify={"center"}>
 | 
					                        justify={"center"}>
 | 
				
			||||||
                        <Flex
 | 
					 | 
				
			||||||
                            gap={rem(10)}
 | 
					 | 
				
			||||||
                            align={"center"}
 | 
					 | 
				
			||||||
                            justify={"space-between"}>
 | 
					 | 
				
			||||||
                            {isServicesAndProductsIncluded && (
 | 
					 | 
				
			||||||
                                <PrintDealBarcodesButton card={card} />
 | 
					 | 
				
			||||||
                            )}
 | 
					 | 
				
			||||||
                            <Flex gap={rem(10)}>
 | 
					 | 
				
			||||||
                                {isServicesAndProductsIncluded && (
 | 
					 | 
				
			||||||
                                    <PaymentLinkButton card={card} />
 | 
					 | 
				
			||||||
                                )}
 | 
					 | 
				
			||||||
                        <ButtonCopyControlled
 | 
					                        <ButtonCopyControlled
 | 
				
			||||||
                            onCopyClick={onCopyGuestUrlClick}
 | 
					                            onCopyClick={onCopyGuestUrlClick}
 | 
				
			||||||
                            onCopiedLabel={
 | 
					                            onCopiedLabel={
 | 
				
			||||||
@@ -293,16 +205,7 @@ const Content: FC<Props> = ({ card }) => {
 | 
				
			|||||||
                        >
 | 
					                        >
 | 
				
			||||||
                            Ссылка на редактирование
 | 
					                            Ссылка на редактирование
 | 
				
			||||||
                        </ButtonCopyControlled>
 | 
					                        </ButtonCopyControlled>
 | 
				
			||||||
                            </Flex>
 | 
					 | 
				
			||||||
                        </Flex>
 | 
					 | 
				
			||||||
                        <Flex gap={rem(10)}>
 | 
					                        <Flex gap={rem(10)}>
 | 
				
			||||||
                            {isServicesAndProductsIncluded && (
 | 
					 | 
				
			||||||
                                <Checkbox
 | 
					 | 
				
			||||||
                                    label={"Оплачен"}
 | 
					 | 
				
			||||||
                                    checked={card.billRequest?.paid || card.group?.billRequest?.paid || false}
 | 
					 | 
				
			||||||
                                    disabled
 | 
					 | 
				
			||||||
                                />
 | 
					 | 
				
			||||||
                            )}
 | 
					 | 
				
			||||||
                            <Checkbox
 | 
					                            <Checkbox
 | 
				
			||||||
                                label={"Завершена"}
 | 
					                                label={"Завершена"}
 | 
				
			||||||
                                {...form.getInputProps("isCompleted", { type: "checkbox" })}
 | 
					                                {...form.getInputProps("isCompleted", { type: "checkbox" })}
 | 
				
			||||||
@@ -2,7 +2,7 @@ import { FC } from "react";
 | 
				
			|||||||
import { CardProductSchema, ProductSchema } from "../../../../../../client";
 | 
					import { CardProductSchema, ProductSchema } from "../../../../../../client";
 | 
				
			||||||
import { Image, rem, Text, Title } from "@mantine/core";
 | 
					import { Image, rem, Text, Title } from "@mantine/core";
 | 
				
			||||||
import { isNil } from "lodash";
 | 
					import { isNil } from "lodash";
 | 
				
			||||||
import { ProductFieldNames } from "../../../../tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
					import { ProductFieldNames } from "../../../../../../modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
				
			||||||
import ProductServicesTable from "../tables/ProductServicesTable/ProductServicesTable.tsx";
 | 
					import ProductServicesTable from "../tables/ProductServicesTable/ProductServicesTable.tsx";
 | 
				
			||||||
import styles from "./ProductPreview.module.css";
 | 
					import styles from "./ProductPreview.module.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import { useForm } from "@mantine/form";
 | 
				
			|||||||
import { useEffect, useState } from "react";
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
import { BaseMarketplaceSchema } from "../../../../../client";
 | 
					import { BaseMarketplaceSchema } from "../../../../../client";
 | 
				
			||||||
import { useCardSummariesFull } from "../../../hooks/useCardSummaries.tsx";
 | 
					import { useCardSummariesFull } from "../../../hooks/useCardSummaries.tsx";
 | 
				
			||||||
import isModuleInProject, { Modules } from "../../../utils/isModuleInProject.ts";
 | 
					import isModuleInProject, { Modules } from "../../../../../modules/utils/isModuleInProject.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type State = {
 | 
					type State = {
 | 
				
			||||||
    idOrName: string | null;
 | 
					    idOrName: string | null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import { Flex, Modal, NumberInput, rem } from "@mantine/core";
 | 
				
			|||||||
import { UseFormReturnType } from "@mantine/form";
 | 
					import { UseFormReturnType } from "@mantine/form";
 | 
				
			||||||
import { CardsPageState } from "../hooks/useCardsPageState.tsx";
 | 
					import { CardsPageState } from "../hooks/useCardsPageState.tsx";
 | 
				
			||||||
import ObjectSelect from "../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
					import ObjectSelect from "../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
import DealStatusSelect from "../../../components/DealStatusSelect/DealStatusSelect.tsx";
 | 
					import CardStatusSelect from "../../../components/DealStatusSelect/CardStatusSelect.tsx";
 | 
				
			||||||
import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
					import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
 | 
				
			||||||
import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
 | 
					import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx";
 | 
				
			||||||
import { useDisclosure } from "@mantine/hooks";
 | 
					import { useDisclosure } from "@mantine/hooks";
 | 
				
			||||||
@@ -25,7 +25,7 @@ const CardsTableFiltersModal = ({ form, projects }: Props) => {
 | 
				
			|||||||
                <IconFilter />
 | 
					                <IconFilter />
 | 
				
			||||||
                Фильтры
 | 
					                Фильтры
 | 
				
			||||||
            </InlineButton>
 | 
					            </InlineButton>
 | 
				
			||||||
            <Modal title={"Фильтры для сделок"} opened={opened} onClose={close}>
 | 
					            <Modal title={"Фильтры"} opened={opened} onClose={close}>
 | 
				
			||||||
                <Flex
 | 
					                <Flex
 | 
				
			||||||
                    direction={"column"}
 | 
					                    direction={"column"}
 | 
				
			||||||
                    gap={rem(10)}
 | 
					                    gap={rem(10)}
 | 
				
			||||||
@@ -49,7 +49,7 @@ const CardsTableFiltersModal = ({ form, projects }: Props) => {
 | 
				
			|||||||
                        {...form.getInputProps("board")}
 | 
					                        {...form.getInputProps("board")}
 | 
				
			||||||
                        clearable
 | 
					                        clearable
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <DealStatusSelect
 | 
					                    <CardStatusSelect
 | 
				
			||||||
                        board={form.values.board}
 | 
					                        board={form.values.board}
 | 
				
			||||||
                        {...form.getInputProps("status")}
 | 
					                        {...form.getInputProps("status")}
 | 
				
			||||||
                        clearable
 | 
					                        clearable
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,103 +0,0 @@
 | 
				
			|||||||
import { Button, Fieldset, Flex, rem, Stack, Textarea, TextInput } from "@mantine/core";
 | 
					 | 
				
			||||||
import { useCardPageContext } from "../../contexts/CardPageContext.tsx";
 | 
					 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					 | 
				
			||||||
import { CardGeneralFormType } from "../GeneralTab/GeneralTab.tsx";
 | 
					 | 
				
			||||||
import { CardSchema, CardService, ClientService } from "../../../../client";
 | 
					 | 
				
			||||||
import { isEqual } from "lodash";
 | 
					 | 
				
			||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
					 | 
				
			||||||
import { useQueryClient } from "@tanstack/react-query";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ClientTab = () => {
 | 
					 | 
				
			||||||
    const { selectedCard: card, setSelectedCard } = useCardPageContext();
 | 
					 | 
				
			||||||
    const initialValues: CardGeneralFormType = card as CardSchema;
 | 
					 | 
				
			||||||
    const queryClient = useQueryClient();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!card?.client) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const form = useForm<CardGeneralFormType>(
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            initialValues: initialValues,
 | 
					 | 
				
			||||||
            validate: {
 | 
					 | 
				
			||||||
                name: (value: string) => value.length > 0 ? null : "Название сделки не может быть пустым",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const hasChanges = !isEqual(form.values, initialValues);
 | 
					 | 
				
			||||||
    const updateClientInfo = async (values: CardGeneralFormType) => {
 | 
					 | 
				
			||||||
        if (!values.client) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return ClientService.updateClient({
 | 
					 | 
				
			||||||
            requestBody: {
 | 
					 | 
				
			||||||
                data: values.client,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }).then(({ ok, message }) => notifications.guess(ok, { message }));
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const update = async () => {
 | 
					 | 
				
			||||||
        return CardService.getCardById({ cardId: form.values.id }).then(data => {
 | 
					 | 
				
			||||||
            setSelectedCard(data);
 | 
					 | 
				
			||||||
            form.setInitialValues(data);
 | 
					 | 
				
			||||||
            queryClient.invalidateQueries({
 | 
					 | 
				
			||||||
                queryKey: ["getCardSummaries"],
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const handleSave = () => {
 | 
					 | 
				
			||||||
        updateClientInfo(form.values).then(async () => {
 | 
					 | 
				
			||||||
            await update();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const handleCancel = () => {
 | 
					 | 
				
			||||||
        form.setInitialValues(initialValues);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
        <Flex direction={"column"} flex={1} gap={rem(10)}>
 | 
					 | 
				
			||||||
            <Flex flex={1}>
 | 
					 | 
				
			||||||
                <Fieldset legend={"Клиент"} flex={1}>
 | 
					 | 
				
			||||||
                    <Stack gap={rem(10)}>
 | 
					 | 
				
			||||||
                        <TextInput
 | 
					 | 
				
			||||||
                            disabled
 | 
					 | 
				
			||||||
                            placeholder={"Название"}
 | 
					 | 
				
			||||||
                            label={"Название"}
 | 
					 | 
				
			||||||
                            value={card?.client.name}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <TextInput
 | 
					 | 
				
			||||||
                            placeholder={"Введите телефон"}
 | 
					 | 
				
			||||||
                            label={"Телефон клиента"}
 | 
					 | 
				
			||||||
                            {...form.getInputProps("client.details.phoneNumber")}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <TextInput
 | 
					 | 
				
			||||||
                            placeholder={"Введите email"}
 | 
					 | 
				
			||||||
                            label={"Email"}
 | 
					 | 
				
			||||||
                            {...form.getInputProps("client.details.email")}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <TextInput
 | 
					 | 
				
			||||||
                            placeholder={"Введите телеграм"}
 | 
					 | 
				
			||||||
                            label={"Телеграм"}
 | 
					 | 
				
			||||||
                            {...form.getInputProps("client.details.telegram")}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <TextInput
 | 
					 | 
				
			||||||
                            placeholder={"Введите ИНН"}
 | 
					 | 
				
			||||||
                            label={"ИНН"}
 | 
					 | 
				
			||||||
                            {...form.getInputProps("client.details.inn")}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                        <Textarea
 | 
					 | 
				
			||||||
                            placeholder={"Введите комментарий"}
 | 
					 | 
				
			||||||
                            label={"Комментарий"}
 | 
					 | 
				
			||||||
                            {...form.getInputProps("client.comment")}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                    </Stack>
 | 
					 | 
				
			||||||
                </Fieldset>
 | 
					 | 
				
			||||||
            </Flex>
 | 
					 | 
				
			||||||
            <Flex
 | 
					 | 
				
			||||||
                gap={rem(10)}
 | 
					 | 
				
			||||||
                justify={"flex-end"}
 | 
					 | 
				
			||||||
                display={!hasChanges ? "none" : "flex"}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
                <Button onClick={handleCancel} variant={"default"}>Отмена</Button>
 | 
					 | 
				
			||||||
                <Button onClick={handleSave} variant={"default"}>Сохранить</Button>
 | 
					 | 
				
			||||||
            </Flex>
 | 
					 | 
				
			||||||
        </Flex>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
export default ClientTab;
 | 
					 | 
				
			||||||
@@ -13,7 +13,7 @@ import {
 | 
				
			|||||||
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";
 | 
				
			||||||
import DealStatusSelect from "../../../../../../components/DealStatusSelect/DealStatusSelect.tsx";
 | 
					import CardStatusSelect from "../../../../../../components/DealStatusSelect/CardStatusSelect.tsx";
 | 
				
			||||||
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 TransactionTagSelect from "../../../../components/ExpenseTagSelect/TransactionTagSelect.tsx";
 | 
					import TransactionTagSelect from "../../../../components/ExpenseTagSelect/TransactionTagSelect.tsx";
 | 
				
			||||||
@@ -107,7 +107,7 @@ export const Filters = (props: FiltersProps) => {
 | 
				
			|||||||
                />
 | 
					                />
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            {props.statusSelectProps &&
 | 
					            {props.statusSelectProps &&
 | 
				
			||||||
                <DealStatusSelect
 | 
					                <CardStatusSelect
 | 
				
			||||||
                    board={props.boardSelectProps?.value ?? null}
 | 
					                    board={props.boardSelectProps?.value ?? null}
 | 
				
			||||||
                    {...props.statusSelectProps}
 | 
					                    {...props.statusSelectProps}
 | 
				
			||||||
                    clearable
 | 
					                    clearable
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
/* prettier-ignore-start */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @ts-nocheck
 | 
					// @ts-nocheck
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// noinspection JSUnusedGlobalSymbols
 | 
					// noinspection JSUnusedGlobalSymbols
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This file is auto-generated by TanStack Router
 | 
					// This file was automatically generated by TanStack Router.
 | 
				
			||||||
 | 
					// You should NOT make any changes in this file as it will be overwritten.
 | 
				
			||||||
 | 
					// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { createFileRoute } from '@tanstack/react-router'
 | 
					import { createFileRoute } from '@tanstack/react-router'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,16 +36,19 @@ const IndexLazyImport = createFileRoute('/')()
 | 
				
			|||||||
// Create/Update Routes
 | 
					// Create/Update Routes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TestLazyRoute = TestLazyImport.update({
 | 
					const TestLazyRoute = TestLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/test',
 | 
				
			||||||
  path: '/test',
 | 
					  path: '/test',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/test.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/test.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StatisticsLazyRoute = StatisticsLazyImport.update({
 | 
					const StatisticsLazyRoute = StatisticsLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/statistics',
 | 
				
			||||||
  path: '/statistics',
 | 
					  path: '/statistics',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/statistics.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/statistics.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
 | 
					const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/shipping_warehouses',
 | 
				
			||||||
  path: '/shipping_warehouses',
 | 
					  path: '/shipping_warehouses',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() =>
 | 
					} as any).lazy(() =>
 | 
				
			||||||
@@ -53,66 +56,79 @@ const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ServicesLazyRoute = ServicesLazyImport.update({
 | 
					const ServicesLazyRoute = ServicesLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/services',
 | 
				
			||||||
  path: '/services',
 | 
					  path: '/services',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/services.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/services.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ResiduesLazyRoute = ResiduesLazyImport.update({
 | 
					const ResiduesLazyRoute = ResiduesLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/residues',
 | 
				
			||||||
  path: '/residues',
 | 
					  path: '/residues',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/residues.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/residues.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ReceiptLazyRoute = ReceiptLazyImport.update({
 | 
					const ReceiptLazyRoute = ReceiptLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/receipt',
 | 
				
			||||||
  path: '/receipt',
 | 
					  path: '/receipt',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/receipt.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/receipt.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProductsLazyRoute = ProductsLazyImport.update({
 | 
					const ProductsLazyRoute = ProductsLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/products',
 | 
				
			||||||
  path: '/products',
 | 
					  path: '/products',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MarketplacesLazyRoute = MarketplacesLazyImport.update({
 | 
					const MarketplacesLazyRoute = MarketplacesLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/marketplaces',
 | 
				
			||||||
  path: '/marketplaces',
 | 
					  path: '/marketplaces',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LoginLazyRoute = LoginLazyImport.update({
 | 
					const LoginLazyRoute = LoginLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/login',
 | 
				
			||||||
  path: '/login',
 | 
					  path: '/login',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LeadsLazyRoute = LeadsLazyImport.update({
 | 
					const LeadsLazyRoute = LeadsLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/leads',
 | 
				
			||||||
  path: '/leads',
 | 
					  path: '/leads',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/leads.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/leads.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ClientsLazyRoute = ClientsLazyImport.update({
 | 
					const ClientsLazyRoute = ClientsLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/clients',
 | 
				
			||||||
  path: '/clients',
 | 
					  path: '/clients',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/clients.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/clients.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const BarcodeLazyRoute = BarcodeLazyImport.update({
 | 
					const BarcodeLazyRoute = BarcodeLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/barcode',
 | 
				
			||||||
  path: '/barcode',
 | 
					  path: '/barcode',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/barcode.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/barcode.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AdminLazyRoute = AdminLazyImport.update({
 | 
					const AdminLazyRoute = AdminLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/admin',
 | 
				
			||||||
  path: '/admin',
 | 
					  path: '/admin',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const IndexLazyRoute = IndexLazyImport.update({
 | 
					const IndexLazyRoute = IndexLazyImport.update({
 | 
				
			||||||
 | 
					  id: '/',
 | 
				
			||||||
  path: '/',
 | 
					  path: '/',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route))
 | 
					} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LeadsDealIdRoute = LeadsDealIdImport.update({
 | 
					const LeadsDealIdRoute = LeadsDealIdImport.update({
 | 
				
			||||||
 | 
					  id: '/$dealId',
 | 
				
			||||||
  path: '/$dealId',
 | 
					  path: '/$dealId',
 | 
				
			||||||
  getParentRoute: () => LeadsLazyRoute,
 | 
					  getParentRoute: () => LeadsLazyRoute,
 | 
				
			||||||
} as any)
 | 
					} as any)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DealsDealIdRoute = DealsDealIdImport.update({
 | 
					const DealsDealIdRoute = DealsDealIdImport.update({
 | 
				
			||||||
 | 
					  id: '/deals/$dealId',
 | 
				
			||||||
  path: '/deals/$dealId',
 | 
					  path: '/deals/$dealId',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
} as any)
 | 
					} as any)
 | 
				
			||||||
@@ -406,8 +422,6 @@ export const routeTree = rootRoute
 | 
				
			|||||||
  ._addFileChildren(rootRouteChildren)
 | 
					  ._addFileChildren(rootRouteChildren)
 | 
				
			||||||
  ._addFileTypes<FileRouteTypes>()
 | 
					  ._addFileTypes<FileRouteTypes>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* prettier-ignore-end */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* ROUTE_MANIFEST_START
 | 
					/* ROUTE_MANIFEST_START
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "routes": {
 | 
					  "routes": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import { ProductSchema } from "../client";
 | 
					import { ProductSchema } from "../client";
 | 
				
			||||||
import { isNil } from "lodash";
 | 
					import { isNil } from "lodash";
 | 
				
			||||||
import { ProductFieldNames } from "../pages/CardsPage/tabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
					import { ProductFieldNames } from "../modules/cardModules/cardEditorTabs/ProductAndServiceTab/components/ProductView/ProductView.tsx";
 | 
				
			||||||
import UseObjectState from "./UseObjectState.ts";
 | 
					import UseObjectState from "./UseObjectState.ts";
 | 
				
			||||||
import { CRUDTableProps } from "./CRUDTable.tsx";
 | 
					import { CRUDTableProps } from "./CRUDTable.tsx";
 | 
				
			||||||
import { MRT_RowData } from "mantine-react-table";
 | 
					import { MRT_RowData } from "mantine-react-table";
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user