k
This commit is contained in:
		
							
								
								
									
										86
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								package.json
									
									
									
									
									
								
							@@ -11,54 +11,58 @@
 | 
				
			|||||||
    "generate-client": "openapi --input http://127.0.0.1:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
 | 
					    "generate-client": "openapi --input http://127.0.0.1:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@hello-pangea/dnd": "^16.5.0",
 | 
					    "@hello-pangea/dnd": "^16.6.0",
 | 
				
			||||||
    "@mantine/core": "^7.6.1",
 | 
					    "@mantine/core": "^7.11.2",
 | 
				
			||||||
    "@mantine/dates": "^7.6.1",
 | 
					    "@mantine/dates": "^7.11.2",
 | 
				
			||||||
    "@mantine/dropzone": "^7.9.2",
 | 
					    "@mantine/dropzone": "^7.11.2",
 | 
				
			||||||
    "@mantine/form": "^7.6.1",
 | 
					    "@mantine/form": "^7.11.2",
 | 
				
			||||||
    "@mantine/hooks": "^7.6.1",
 | 
					    "@mantine/hooks": "^7.11.2",
 | 
				
			||||||
    "@mantine/modals": "^7.6.1",
 | 
					    "@mantine/modals": "^7.11.2",
 | 
				
			||||||
    "@mantine/notifications": "^7.6.1",
 | 
					    "@mantine/notifications": "^7.11.2",
 | 
				
			||||||
    "@reduxjs/toolkit": "^2.2.1",
 | 
					    "@reduxjs/toolkit": "^2.2.6",
 | 
				
			||||||
    "@tabler/icons-react": "^2.47.0",
 | 
					    "@tabler/icons-react": "^3.11.0",
 | 
				
			||||||
    "@tanstack/react-query": "^5.22.2",
 | 
					    "@tanstack/react-query": "^5.51.9",
 | 
				
			||||||
    "@tanstack/react-router": "^1.16.6",
 | 
					    "@tanstack/react-router": "^1.45.6",
 | 
				
			||||||
    "@tanstack/router-devtools": "^1.16.6",
 | 
					    "@tanstack/router-devtools": "^1.45.6",
 | 
				
			||||||
    "@tanstack/router-vite-plugin": "^1.16.5",
 | 
					    "@tanstack/router-vite-plugin": "^1.45.3",
 | 
				
			||||||
    "axios": "^1.6.7",
 | 
					    "axios": "^1.7.2",
 | 
				
			||||||
    "classnames": "^2.5.1",
 | 
					    "classnames": "^2.5.1",
 | 
				
			||||||
    "clsx": "^2.1.0",
 | 
					    "clsx": "^2.1.1",
 | 
				
			||||||
    "dayjs": "^1.11.10",
 | 
					    "dayjs": "^1.11.12",
 | 
				
			||||||
    "dot-object": "^2.1.4",
 | 
					    "dot-object": "^2.1.5",
 | 
				
			||||||
 | 
					    "framer-motion": "^11.3.8",
 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "mantine-form-zod-resolver": "^1.1.0",
 | 
					    "mantine-form-zod-resolver": "^1.1.0",
 | 
				
			||||||
    "mantine-react-table": "^2.0.0-beta.0",
 | 
					    "mantine-react-table": "^2.0.0-beta.5",
 | 
				
			||||||
    "react": "^18.2.0",
 | 
					    "phone": "^3.1.49",
 | 
				
			||||||
    "react-barcode": "^1.5.1",
 | 
					    "react": "^18.3.1",
 | 
				
			||||||
    "react-dom": "^18.2.0",
 | 
					    "react-barcode": "^1.5.3",
 | 
				
			||||||
    "react-redux": "^9.1.0",
 | 
					    "react-dom": "^18.3.1",
 | 
				
			||||||
 | 
					    "react-imask": "^7.6.1",
 | 
				
			||||||
 | 
					    "react-redux": "^9.1.2",
 | 
				
			||||||
    "react-to-print": "^2.15.1",
 | 
					    "react-to-print": "^2.15.1",
 | 
				
			||||||
    "reactflow": "^11.10.4",
 | 
					    "reactflow": "^11.11.4",
 | 
				
			||||||
    "zod": "^3.22.4"
 | 
					    "zod": "^3.23.8"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/dot-object": "^2",
 | 
					    "@types/dot-object": "^2.1.6",
 | 
				
			||||||
    "@types/lodash": "^4",
 | 
					    "@types/lodash": "^4.17.7",
 | 
				
			||||||
    "@types/react": "^18.2.56",
 | 
					    "@types/react": "^18.3.3",
 | 
				
			||||||
    "@types/react-dom": "^18.2.19",
 | 
					    "@types/react-dom": "^18.3.0",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^7.0.2",
 | 
					    "@typescript-eslint/eslint-plugin": "^7.16.1",
 | 
				
			||||||
    "@typescript-eslint/parser": "^7.0.2",
 | 
					    "@typescript-eslint/parser": "^7.16.1",
 | 
				
			||||||
    "@vitejs/plugin-react-swc": "^3.5.0",
 | 
					    "@vitejs/plugin-react-swc": "^3.7.0",
 | 
				
			||||||
    "eslint": "^8.56.0",
 | 
					    "eslint": "^9.7.0",
 | 
				
			||||||
    "eslint-plugin-react-hooks": "^4.6.0",
 | 
					    "eslint-plugin-react-hooks": "^4.6.2",
 | 
				
			||||||
    "eslint-plugin-react-refresh": "^0.4.5",
 | 
					    "eslint-plugin-react-refresh": "^0.4.8",
 | 
				
			||||||
    "openapi-typescript-codegen": "^0.27.0",
 | 
					    "openapi-typescript-codegen": "^0.29.0",
 | 
				
			||||||
    "postcss": "^8.4.35",
 | 
					    "postcss": "^8.4.39",
 | 
				
			||||||
    "postcss-preset-mantine": "^1.13.0",
 | 
					    "postcss-preset-mantine": "^1.16.0",
 | 
				
			||||||
    "postcss-simple-vars": "^7.0.1",
 | 
					    "postcss-simple-vars": "^7.0.1",
 | 
				
			||||||
    "sass": "^1.71.1",
 | 
					    "sass": "^1.77.8",
 | 
				
			||||||
    "typescript": "^5.2.2",
 | 
					    "typescript": "^5.5.3",
 | 
				
			||||||
    "vite": "^5.1.4"
 | 
					    "vite": "^5.3.4",
 | 
				
			||||||
 | 
					    "yarn-upgrade-all": "^0.7.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "packageManager": "yarn@4.1.0"
 | 
					  "packageManager": "yarn@4.1.0"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,8 @@ export type { ClientUpdateRequest } from './models/ClientUpdateRequest';
 | 
				
			|||||||
export type { ClientUpdateResponse } from './models/ClientUpdateResponse';
 | 
					export type { ClientUpdateResponse } from './models/ClientUpdateResponse';
 | 
				
			||||||
export type { CreateBarcodeTemplateAttributeRequest } from './models/CreateBarcodeTemplateAttributeRequest';
 | 
					export type { CreateBarcodeTemplateAttributeRequest } from './models/CreateBarcodeTemplateAttributeRequest';
 | 
				
			||||||
export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse';
 | 
					export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse';
 | 
				
			||||||
 | 
					export type { CreatePositionRequest } from './models/CreatePositionRequest';
 | 
				
			||||||
 | 
					export type { CreatePositionResponse } from './models/CreatePositionResponse';
 | 
				
			||||||
export type { DealAddProductRequest } from './models/DealAddProductRequest';
 | 
					export type { DealAddProductRequest } from './models/DealAddProductRequest';
 | 
				
			||||||
export type { DealAddProductResponse } from './models/DealAddProductResponse';
 | 
					export type { DealAddProductResponse } from './models/DealAddProductResponse';
 | 
				
			||||||
export type { DealAddServiceRequest } from './models/DealAddServiceRequest';
 | 
					export type { DealAddServiceRequest } from './models/DealAddServiceRequest';
 | 
				
			||||||
@@ -80,7 +82,10 @@ export type { DealUpdateServiceResponse } from './models/DealUpdateServiceRespon
 | 
				
			|||||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
					export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
					export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
 | 
					export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
 | 
				
			||||||
 | 
					export type { GetAllPositionsResponse } from './models/GetAllPositionsResponse';
 | 
				
			||||||
 | 
					export type { GetAllRolesResponse } from './models/GetAllRolesResponse';
 | 
				
			||||||
export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWarehousesResponse';
 | 
					export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWarehousesResponse';
 | 
				
			||||||
 | 
					export type { GetAllUsersResponse } from './models/GetAllUsersResponse';
 | 
				
			||||||
export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest';
 | 
					export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest';
 | 
				
			||||||
export type { GetBarcodeTemplateByIdResponse } from './models/GetBarcodeTemplateByIdResponse';
 | 
					export type { GetBarcodeTemplateByIdResponse } from './models/GetBarcodeTemplateByIdResponse';
 | 
				
			||||||
export type { GetProductBarcodePdfRequest } from './models/GetProductBarcodePdfRequest';
 | 
					export type { GetProductBarcodePdfRequest } from './models/GetProductBarcodePdfRequest';
 | 
				
			||||||
@@ -89,6 +94,8 @@ export type { GetProductBarcodeRequest } from './models/GetProductBarcodeRequest
 | 
				
			|||||||
export type { GetProductBarcodeResponse } from './models/GetProductBarcodeResponse';
 | 
					export type { GetProductBarcodeResponse } from './models/GetProductBarcodeResponse';
 | 
				
			||||||
export type { HTTPValidationError } from './models/HTTPValidationError';
 | 
					export type { HTTPValidationError } from './models/HTTPValidationError';
 | 
				
			||||||
export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
 | 
					export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
 | 
				
			||||||
 | 
					export type { PermissionSchema } from './models/PermissionSchema';
 | 
				
			||||||
 | 
					export type { PositionSchema } from './models/PositionSchema';
 | 
				
			||||||
export type { ProductAddBarcodeRequest } from './models/ProductAddBarcodeRequest';
 | 
					export type { ProductAddBarcodeRequest } from './models/ProductAddBarcodeRequest';
 | 
				
			||||||
export type { ProductAddBarcodeResponse } from './models/ProductAddBarcodeResponse';
 | 
					export type { ProductAddBarcodeResponse } from './models/ProductAddBarcodeResponse';
 | 
				
			||||||
export type { ProductCreateRequest } from './models/ProductCreateRequest';
 | 
					export type { ProductCreateRequest } from './models/ProductCreateRequest';
 | 
				
			||||||
@@ -104,6 +111,7 @@ 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';
 | 
				
			||||||
export type { ProductUploadImageResponse } from './models/ProductUploadImageResponse';
 | 
					export type { ProductUploadImageResponse } from './models/ProductUploadImageResponse';
 | 
				
			||||||
 | 
					export type { RoleSchema } from './models/RoleSchema';
 | 
				
			||||||
export type { ServiceCategorySchema } from './models/ServiceCategorySchema';
 | 
					export type { ServiceCategorySchema } from './models/ServiceCategorySchema';
 | 
				
			||||||
export type { ServiceCreateCategoryRequest } from './models/ServiceCreateCategoryRequest';
 | 
					export type { ServiceCreateCategoryRequest } from './models/ServiceCreateCategoryRequest';
 | 
				
			||||||
export type { ServiceCreateCategoryResponse } from './models/ServiceCreateCategoryResponse';
 | 
					export type { ServiceCreateCategoryResponse } from './models/ServiceCreateCategoryResponse';
 | 
				
			||||||
@@ -118,13 +126,19 @@ export type { ServiceSchema } from './models/ServiceSchema';
 | 
				
			|||||||
export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
 | 
					export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
 | 
				
			||||||
export type { ServiceUpdateResponse } from './models/ServiceUpdateResponse';
 | 
					export type { ServiceUpdateResponse } from './models/ServiceUpdateResponse';
 | 
				
			||||||
export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema';
 | 
					export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema';
 | 
				
			||||||
 | 
					export type { UpdateUserRequest } from './models/UpdateUserRequest';
 | 
				
			||||||
 | 
					export type { UpdateUserResponse } from './models/UpdateUserResponse';
 | 
				
			||||||
export type { UserSchema } from './models/UserSchema';
 | 
					export type { UserSchema } from './models/UserSchema';
 | 
				
			||||||
 | 
					export type { UserUpdate } from './models/UserUpdate';
 | 
				
			||||||
export type { ValidationError } from './models/ValidationError';
 | 
					export type { ValidationError } from './models/ValidationError';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { AuthService } from './services/AuthService';
 | 
					export { AuthService } from './services/AuthService';
 | 
				
			||||||
export { BarcodeService } from './services/BarcodeService';
 | 
					export { BarcodeService } from './services/BarcodeService';
 | 
				
			||||||
export { ClientService } from './services/ClientService';
 | 
					export { ClientService } from './services/ClientService';
 | 
				
			||||||
export { DealService } from './services/DealService';
 | 
					export { DealService } from './services/DealService';
 | 
				
			||||||
 | 
					export { PositionService } from './services/PositionService';
 | 
				
			||||||
export { ProductService } from './services/ProductService';
 | 
					export { ProductService } from './services/ProductService';
 | 
				
			||||||
 | 
					export { RoleService } from './services/RoleService';
 | 
				
			||||||
export { ServiceService } from './services/ServiceService';
 | 
					export { ServiceService } from './services/ServiceService';
 | 
				
			||||||
export { ShippingWarehouseService } from './services/ShippingWarehouseService';
 | 
					export { ShippingWarehouseService } from './services/ShippingWarehouseService';
 | 
				
			||||||
 | 
					export { UserService } from './services/UserService';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/CreatePositionRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/CreatePositionRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PositionSchema } from './PositionSchema';
 | 
				
			||||||
 | 
					export type CreatePositionRequest = {
 | 
				
			||||||
 | 
					    data: PositionSchema;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/CreatePositionResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/CreatePositionResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type CreatePositionResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7,5 +7,6 @@ export type DealGeneralInfoSchema = {
 | 
				
			|||||||
    isDeleted: boolean;
 | 
					    isDeleted: boolean;
 | 
				
			||||||
    isCompleted: boolean;
 | 
					    isCompleted: boolean;
 | 
				
			||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
 | 
					    shippingWarehouse?: (string | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,6 @@ export type DealSchema = {
 | 
				
			|||||||
    isCompleted: boolean;
 | 
					    isCompleted: boolean;
 | 
				
			||||||
    client: ClientSchema;
 | 
					    client: ClientSchema;
 | 
				
			||||||
    comment: string;
 | 
					    comment: string;
 | 
				
			||||||
    shippingWarehouse?: (ShippingWarehouseSchema | null);
 | 
					    shippingWarehouse?: (ShippingWarehouseSchema | string | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/client/models/GetAllPositionsResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/GetAllPositionsResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PositionSchema } from './PositionSchema';
 | 
				
			||||||
 | 
					export type GetAllPositionsResponse = {
 | 
				
			||||||
 | 
					    positions: Array<PositionSchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/GetAllRolesResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/GetAllRolesResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { RoleSchema } from './RoleSchema';
 | 
				
			||||||
 | 
					export type GetAllRolesResponse = {
 | 
				
			||||||
 | 
					    roles: Array<RoleSchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/GetAllUsersResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/GetAllUsersResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { UserSchema } from './UserSchema';
 | 
				
			||||||
 | 
					export type GetAllUsersResponse = {
 | 
				
			||||||
 | 
					    users: Array<UserSchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/PermissionSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/PermissionSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type PermissionSchema = {
 | 
				
			||||||
 | 
					    key: string;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/PositionSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/PositionSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type PositionSchema = {
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    key: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/client/models/RoleSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/client/models/RoleSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PermissionSchema } from './PermissionSchema';
 | 
				
			||||||
 | 
					export type RoleSchema = {
 | 
				
			||||||
 | 
					    key: string;
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    permissions: Array<PermissionSchema>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateUserRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateUserRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { UserUpdate } from './UserUpdate';
 | 
				
			||||||
 | 
					export type UpdateUserRequest = {
 | 
				
			||||||
 | 
					    data: UserUpdate;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/client/models/UpdateUserResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/UpdateUserResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UpdateUserResponse = {
 | 
				
			||||||
 | 
					    ok: boolean;
 | 
				
			||||||
 | 
					    message: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2,10 +2,20 @@
 | 
				
			|||||||
/* istanbul ignore file */
 | 
					/* istanbul ignore file */
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { PositionSchema } from './PositionSchema';
 | 
				
			||||||
 | 
					import type { RoleSchema } from './RoleSchema';
 | 
				
			||||||
export type UserSchema = {
 | 
					export type UserSchema = {
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
    telegramId: number;
 | 
					    telegramId: number;
 | 
				
			||||||
    phoneNumber?: (string | null);
 | 
					    phoneNumber?: (string | null);
 | 
				
			||||||
 | 
					    firstName: string;
 | 
				
			||||||
 | 
					    secondName: string;
 | 
				
			||||||
 | 
					    comment: string;
 | 
				
			||||||
    isAdmin: boolean;
 | 
					    isAdmin: boolean;
 | 
				
			||||||
 | 
					    isBlocked: boolean;
 | 
				
			||||||
 | 
					    isDeleted: boolean;
 | 
				
			||||||
 | 
					    roleKey: string;
 | 
				
			||||||
 | 
					    role: RoleSchema;
 | 
				
			||||||
 | 
					    position?: (PositionSchema | null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								src/client/models/UserUpdate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/client/models/UserUpdate.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					export type UserUpdate = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    telegramId: number;
 | 
				
			||||||
 | 
					    phoneNumber?: (string | null);
 | 
				
			||||||
 | 
					    firstName: string;
 | 
				
			||||||
 | 
					    secondName: string;
 | 
				
			||||||
 | 
					    comment: string;
 | 
				
			||||||
 | 
					    isAdmin: boolean;
 | 
				
			||||||
 | 
					    isBlocked: boolean;
 | 
				
			||||||
 | 
					    isDeleted: boolean;
 | 
				
			||||||
 | 
					    positionKey?: (string | null);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/client/services/PositionService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/client/services/PositionService.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { CreatePositionRequest } from '../models/CreatePositionRequest';
 | 
				
			||||||
 | 
					import type { CreatePositionResponse } from '../models/CreatePositionResponse';
 | 
				
			||||||
 | 
					import type { GetAllPositionsResponse } from '../models/GetAllPositionsResponse';
 | 
				
			||||||
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
 | 
					export class PositionService {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All
 | 
				
			||||||
 | 
					     * @returns GetAllPositionsResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllPositions(): CancelablePromise<GetAllPositionsResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/position/get-all',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create
 | 
				
			||||||
 | 
					     * @returns CreatePositionResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static createPosition({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: CreatePositionRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<CreatePositionResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/position/create',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/client/services/RoleService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/client/services/RoleService.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { GetAllRolesResponse } from '../models/GetAllRolesResponse';
 | 
				
			||||||
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
 | 
					export class RoleService {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All
 | 
				
			||||||
 | 
					     * @returns GetAllRolesResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllRoles(): CancelablePromise<GetAllRolesResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/role/get-all',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/client/services/UserService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/client/services/UserService.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					/* generated using openapi-typescript-codegen -- do no edit */
 | 
				
			||||||
 | 
					/* istanbul ignore file */
 | 
				
			||||||
 | 
					/* tslint:disable */
 | 
				
			||||||
 | 
					/* eslint-disable */
 | 
				
			||||||
 | 
					import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
 | 
				
			||||||
 | 
					import type { UpdateUserRequest } from '../models/UpdateUserRequest';
 | 
				
			||||||
 | 
					import type { UpdateUserResponse } from '../models/UpdateUserResponse';
 | 
				
			||||||
 | 
					import type { CancelablePromise } from '../core/CancelablePromise';
 | 
				
			||||||
 | 
					import { OpenAPI } from '../core/OpenAPI';
 | 
				
			||||||
 | 
					import { request as __request } from '../core/request';
 | 
				
			||||||
 | 
					export class UserService {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get All
 | 
				
			||||||
 | 
					     * @returns GetAllUsersResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static getAllUsers(): CancelablePromise<GetAllUsersResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'GET',
 | 
				
			||||||
 | 
					            url: '/user/get-all',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update
 | 
				
			||||||
 | 
					     * @returns UpdateUserResponse Successful Response
 | 
				
			||||||
 | 
					     * @throws ApiError
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static updateUser({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: UpdateUserRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<UpdateUserResponse> {
 | 
				
			||||||
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
 | 
					            method: 'POST',
 | 
				
			||||||
 | 
					            url: '/user/update',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/components/AnimatedOutlet/au.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/components/AnimatedOutlet/au.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					import {forwardRef, RefObject, useContext, useRef} from "react";
 | 
				
			||||||
 | 
					import {getRouterContext, Outlet} from "@tanstack/react-router";
 | 
				
			||||||
 | 
					import {motion, useIsPresent} from "framer-motion";
 | 
				
			||||||
 | 
					import {cloneDeep} from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AnimatedOutlet = forwardRef<HTMLDivElement>((_, ref) => {
 | 
				
			||||||
 | 
					    const RouterContext = getRouterContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const routerContext = useContext(RouterContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const renderedContext = useRef(routerContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isPresent = useIsPresent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (isPresent) {
 | 
				
			||||||
 | 
					        renderedContext.current = cloneDeep(routerContext);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <motion.div ref={ref}
 | 
				
			||||||
 | 
					                    initial={{x: "-100%"}}
 | 
				
			||||||
 | 
					                    animate={{x: 0}}
 | 
				
			||||||
 | 
					                    transition={{duration: 0.3}}
 | 
				
			||||||
 | 
					                    onAnimationComplete={()=>{
 | 
				
			||||||
 | 
					                        (ref as RefObject<HTMLDivElement>).current?.style.removeProperty("transform")
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <RouterContext.Provider value={renderedContext.current}>
 | 
				
			||||||
 | 
					                <Outlet/>
 | 
				
			||||||
 | 
					            </RouterContext.Provider>
 | 
				
			||||||
 | 
					        </motion.div>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					export default AnimatedOutlet
 | 
				
			||||||
@@ -26,7 +26,7 @@ export type BaseTableRef<T extends MRT_RowData> = {
 | 
				
			|||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 | 
					// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 | 
				
			||||||
// @ts-expect-error
 | 
					// @ts-expect-error
 | 
				
			||||||
export const BaseTable = forwardRef<BaseTableRef<never>, Props<never>>((props, ref) => {
 | 
					export const BaseTable = forwardRef<BaseTableRef<never>, Props<never>>((props, ref) => {
 | 
				
			||||||
    const {data, columns, restProps, striped, onSelectionChange} = props;
 | 
					    const {data, columns, restProps, striped = true, onSelectionChange} = props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const table = useMantineReactTable({
 | 
					    const table = useMantineReactTable({
 | 
				
			||||||
        localization: MRT_Localization_RU,
 | 
					        localization: MRT_Localization_RU,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import {Center, Image, rem, Stack, Tooltip, UnstyledButton, useMantineColorSchem
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    IconBarcode,
 | 
					    IconBarcode,
 | 
				
			||||||
    IconBox,
 | 
					    IconBox,
 | 
				
			||||||
    IconCash,
 | 
					    IconCash, IconDashboard,
 | 
				
			||||||
    IconFileBarcode,
 | 
					    IconFileBarcode,
 | 
				
			||||||
    IconHome2,
 | 
					    IconHome2,
 | 
				
			||||||
    IconLogout,
 | 
					    IconLogout,
 | 
				
			||||||
@@ -76,7 +76,7 @@ export function Navbar() {
 | 
				
			|||||||
    const dispatch = useAppDispatch();
 | 
					    const dispatch = useAppDispatch();
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
    const router = useRouterState();
 | 
					    const router = useRouterState();
 | 
				
			||||||
    const {colorScheme, toggleColorScheme} = useMantineColorScheme({keepTransitions: false});
 | 
					    const {colorScheme, toggleColorScheme} = useMantineColorScheme({keepTransitions: true});
 | 
				
			||||||
    const onLogoutClick = () => {
 | 
					    const onLogoutClick = () => {
 | 
				
			||||||
        dispatch(logout());
 | 
					        dispatch(logout());
 | 
				
			||||||
        navigate({to: '/login'});
 | 
					        navigate({to: '/login'});
 | 
				
			||||||
@@ -110,6 +110,12 @@ export function Navbar() {
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <Stack w={"100%"} justify="center" gap={0}>
 | 
					            <Stack w={"100%"} justify="center" gap={0}>
 | 
				
			||||||
 | 
					                <NavbarLink icon={IconDashboard}
 | 
				
			||||||
 | 
					                            href={"/admin"}
 | 
				
			||||||
 | 
					                            index={-1}
 | 
				
			||||||
 | 
					                            label={"Панель администратора"}
 | 
				
			||||||
 | 
					                            onClick={() => onNavlinkClick({href: "/admin", index: -1, icon: IconDashboard})}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
                <NavbarLink label={"Сменить тему"} onClick={toggleColorScheme}
 | 
					                <NavbarLink label={"Сменить тему"} onClick={toggleColorScheme}
 | 
				
			||||||
                            icon={colorScheme == "dark" ? IconSun : IconMoon} href={"#"} index={-1}/>
 | 
					                            icon={colorScheme == "dark" ? IconSun : IconMoon} href={"#"} index={-1}/>
 | 
				
			||||||
                <NavbarLink index={-1} href={"#"} onClick={onLogoutClick} icon={IconLogout} label="Выйти"/>
 | 
					                <NavbarLink index={-1} href={"#"} onClick={onLogoutClick} icon={IconLogout} label="Выйти"/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,35 +1,55 @@
 | 
				
			|||||||
import {Select, SelectProps} from "@mantine/core";
 | 
					import {Select, SelectProps} from "@mantine/core";
 | 
				
			||||||
import {useEffect, useMemo, useState} from "react";
 | 
					import {useEffect, useMemo, useState} from "react";
 | 
				
			||||||
import {ObjectWithNameAndId} from "../../types/utils.ts";
 | 
					 | 
				
			||||||
import {groupBy, omit} from "lodash";
 | 
					import {groupBy, omit} from "lodash";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ObjectWithIdAndName {
 | 
				
			||||||
 | 
					    id: number,
 | 
				
			||||||
 | 
					    name: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type SelectObjectType<T extends ObjectWithNameAndId> = T;
 | 
					export type SelectObjectType<T> = T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ControlledValueProps<T extends ObjectWithNameAndId> = {
 | 
					type ControlledValueProps<T> = {
 | 
				
			||||||
    value: SelectObjectType<T>,
 | 
					    value: SelectObjectType<T>,
 | 
				
			||||||
    onChange: (value: SelectObjectType<T>) => void;
 | 
					    onChange: (value: SelectObjectType<T>) => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					type CustomLabelAndKeyProps<T> = {
 | 
				
			||||||
 | 
					    getLabelFn: (item: SelectObjectType<T>) => string;
 | 
				
			||||||
 | 
					    getValueFn: (item: SelectObjectType<T>) => string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RestProps<T extends ObjectWithNameAndId> = {
 | 
					type RestProps<T> = {
 | 
				
			||||||
    defaultValue?: SelectObjectType<T>
 | 
					    defaultValue?: SelectObjectType<T>
 | 
				
			||||||
    onChange: (value: SelectObjectType<T>) => void;
 | 
					    onChange: (value: SelectObjectType<T>) => void;
 | 
				
			||||||
    data: SelectObjectType<T>[];
 | 
					    data: SelectObjectType<T>[];
 | 
				
			||||||
    groupBy?: (item: SelectObjectType<T>) => string;
 | 
					    groupBy?: (item: SelectObjectType<T>) => string;
 | 
				
			||||||
    filterBy?: (item: SelectObjectType<T>) => boolean;
 | 
					    filterBy?: (item: SelectObjectType<T>) => boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const defaultGetLabelFn = <T extends { name: string }>(item: T): string => {
 | 
				
			||||||
 | 
					    return item.name;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type ObjectSelectProps<T extends ObjectWithNameAndId> =
 | 
					const defaultGetValueFn = <T extends { id: number }>(item: T): string => {
 | 
				
			||||||
 | 
					    return item.id.toString();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export type ObjectSelectProps<T> =
 | 
				
			||||||
    (RestProps<T> & Partial<ControlledValueProps<T>>)
 | 
					    (RestProps<T> & Partial<ControlledValueProps<T>>)
 | 
				
			||||||
    & Omit<SelectProps, 'value' | 'onChange' | 'data'>;
 | 
					    & Omit<SelectProps, 'value' | 'onChange' | 'data'>
 | 
				
			||||||
 | 
					    & (T extends ObjectWithIdAndName ? Partial<CustomLabelAndKeyProps<T>> : CustomLabelAndKeyProps<T>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<T>) => {
 | 
					const ObjectSelect = <T, >(props: ObjectSelectProps<T>) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isControlled = 'value' in props;
 | 
					    const isControlled = 'value' in props;
 | 
				
			||||||
 | 
					    const haveGetValueFn = 'getValueFn' in props;
 | 
				
			||||||
 | 
					    const haveGetLabelFn = 'getLabelFn' in props;
 | 
				
			||||||
    const [internalValue, setInternalValue] = useState<SelectObjectType<T> | undefined>(props.defaultValue);
 | 
					    const [internalValue, setInternalValue] = useState<SelectObjectType<T> | undefined>(props.defaultValue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const value = isControlled ? props.value : internalValue;
 | 
					    const value = isControlled ? props.value : internalValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const getValueFn = (haveGetValueFn && props.getValueFn) || defaultGetValueFn;
 | 
				
			||||||
 | 
					    const getLabelFn = (haveGetLabelFn && props.getLabelFn) || defaultGetLabelFn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const data = useMemo(() => {
 | 
					    const data = useMemo(() => {
 | 
				
			||||||
        const propsData = props.filterBy ? props.data.filter(props.filterBy) : props.data;
 | 
					        const propsData = props.filterBy ? props.data.filter(props.filterBy) : props.data;
 | 
				
			||||||
        if (props.groupBy) {
 | 
					        if (props.groupBy) {
 | 
				
			||||||
@@ -38,21 +58,21 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
 | 
				
			|||||||
            return Object.entries(groupedData).map(([group, items]) => ({
 | 
					            return Object.entries(groupedData).map(([group, items]) => ({
 | 
				
			||||||
                group,
 | 
					                group,
 | 
				
			||||||
                items: items.map(item => ({
 | 
					                items: items.map(item => ({
 | 
				
			||||||
                    label: item.name,
 | 
					                    label: getLabelFn(item),
 | 
				
			||||||
                    value: item.id.toString()
 | 
					                    value: getValueFn(item)
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
            }));
 | 
					            }));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return propsData.map(item => ({
 | 
					            return propsData.map(item => ({
 | 
				
			||||||
                label: item.name,
 | 
					                label: getLabelFn(item),
 | 
				
			||||||
                value: item.id.toString()
 | 
					                value: getValueFn(item)
 | 
				
			||||||
            }));
 | 
					            }));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }, [props.data, props.groupBy]);
 | 
					    }, [props.data, props.groupBy]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handleOnChange = (event: string | null) => {
 | 
					    const handleOnChange = (event: string | null) => {
 | 
				
			||||||
        if (!event) return;
 | 
					        if (!event) return;
 | 
				
			||||||
        const object = props.data.find(item => parseInt(event) == item.id);
 | 
					        const object = props.data.find(item => event == getValueFn(item));
 | 
				
			||||||
        if (!object) return;
 | 
					        if (!object) return;
 | 
				
			||||||
        if (isControlled) {
 | 
					        if (isControlled) {
 | 
				
			||||||
            props.onChange(object);
 | 
					            props.onChange(object);
 | 
				
			||||||
@@ -65,11 +85,11 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
 | 
				
			|||||||
        if (isControlled || !internalValue) return;
 | 
					        if (isControlled || !internalValue) return;
 | 
				
			||||||
        props.onChange(internalValue);
 | 
					        props.onChange(internalValue);
 | 
				
			||||||
    }, [internalValue]);
 | 
					    }, [internalValue]);
 | 
				
			||||||
    const restProps = omit(props, ['filterBy', 'groupBy']);
 | 
					    const restProps = omit(props, ['filterBy', 'groupBy', 'getValueFn', 'getLabelFn']);
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Select
 | 
					        <Select
 | 
				
			||||||
            {...restProps}
 | 
					            {...restProps}
 | 
				
			||||||
            value={value?.id.toString()}
 | 
					            value={value && getValueFn(value)}
 | 
				
			||||||
            onChange={handleOnChange}
 | 
					            onChange={handleOnChange}
 | 
				
			||||||
            data={data}
 | 
					            data={data}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								src/hooks/objectList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/hooks/objectList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import {QueryObserverResult, RefetchOptions, useQuery} from "@tanstack/react-query";
 | 
				
			||||||
 | 
					import {CancelablePromise} from "../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props<T, K> = {
 | 
				
			||||||
 | 
					    queryFn: () => CancelablePromise<T>,
 | 
				
			||||||
 | 
					    getObjectsFn: (response: T) => K[],
 | 
				
			||||||
 | 
					    queryKey: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					type Response<T, K> = {
 | 
				
			||||||
 | 
					    objects: K[],
 | 
				
			||||||
 | 
					    refetch: (options?: RefetchOptions) => Promise<QueryObserverResult<T, Error>>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const ObjectList = <T, K, >(props: Props<T, K>): Response<T, K> => {
 | 
				
			||||||
 | 
					    const {isPending, error, data, refetch} = useQuery({
 | 
				
			||||||
 | 
					        queryKey: [props.queryKey],
 | 
				
			||||||
 | 
					        queryFn: props.queryFn
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const objects = isPending || error || !data ? ([] as K[]) : props.getObjectsFn(data);
 | 
				
			||||||
 | 
					    return {objects, refetch}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default ObjectList
 | 
				
			||||||
@@ -10,6 +10,7 @@ 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/LeadsPage/modals/ProductServiceFormModal.tsx";
 | 
					import ProductServiceFormModal from "../pages/LeadsPage/modals/ProductServiceFormModal.tsx";
 | 
				
			||||||
 | 
					import UserFormModal from "../pages/AdminPage/modals/UserFormModal/UserFormModal.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const modals = {
 | 
					export const modals = {
 | 
				
			||||||
    enterDeadline: EnterDeadlineModal,
 | 
					    enterDeadline: EnterDeadlineModal,
 | 
				
			||||||
@@ -22,5 +23,6 @@ export const modals = {
 | 
				
			|||||||
    productServiceForm: ProductServiceFormModal,
 | 
					    productServiceForm: ProductServiceFormModal,
 | 
				
			||||||
    printBarcode: PrintBarcodeModal,
 | 
					    printBarcode: PrintBarcodeModal,
 | 
				
			||||||
    addBarcode: AddBarcodeModal,
 | 
					    addBarcode: AddBarcodeModal,
 | 
				
			||||||
    barcodeTemplateFormModal: BarcodeTemplateFormModal
 | 
					    barcodeTemplateFormModal: BarcodeTemplateFormModal,
 | 
				
			||||||
 | 
					    userFormModal: UserFormModal
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								src/pages/AdminPage/AdminPage.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/pages/AdminPage/AdminPage.module.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					.container {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/pages/AdminPage/AdminPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/pages/AdminPage/AdminPage.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import styles from './AdminPage.module.css';
 | 
				
			||||||
 | 
					import {Tabs} from "@mantine/core";
 | 
				
			||||||
 | 
					import PageBlock from "../../components/PageBlock/PageBlock.tsx";
 | 
				
			||||||
 | 
					import {IconBriefcase, IconUser, IconUsersGroup} from "@tabler/icons-react";
 | 
				
			||||||
 | 
					import RolesAndPositionsTab from "./tabs/RolesAndPositions/RolesAndPositionsTab.tsx";
 | 
				
			||||||
 | 
					import UsersTab from "./tabs/Users/UsersTab.tsx";
 | 
				
			||||||
 | 
					import {motion} from "framer-motion";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AdminPage = () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <div className={styles['container']}>
 | 
				
			||||||
 | 
					            <PageBlock fullHeight>
 | 
				
			||||||
 | 
					                <Tabs variant={"outline"} keepMounted={false} defaultValue={"users"}>
 | 
				
			||||||
 | 
					                    <Tabs.List>
 | 
				
			||||||
 | 
					                        <Tabs.Tab value={"users"} leftSection={<IconUser/>}>
 | 
				
			||||||
 | 
					                            Пользователи
 | 
				
			||||||
 | 
					                        </Tabs.Tab>
 | 
				
			||||||
 | 
					                        <Tabs.Tab value={"rolesAndPositions"} leftSection={<IconBriefcase/>}>
 | 
				
			||||||
 | 
					                            Роли и должности
 | 
				
			||||||
 | 
					                        </Tabs.Tab>
 | 
				
			||||||
 | 
					                        <Tabs.Tab value={"employees"} leftSection={<IconUsersGroup/>}>
 | 
				
			||||||
 | 
					                            Сотрудники
 | 
				
			||||||
 | 
					                        </Tabs.Tab>
 | 
				
			||||||
 | 
					                    </Tabs.List>
 | 
				
			||||||
 | 
					                    <Tabs.Panel value={"users"}>
 | 
				
			||||||
 | 
					                        <motion.div
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            initial={{scaleY: 0}}
 | 
				
			||||||
 | 
					                            animate={{scaleY: 1}}
 | 
				
			||||||
 | 
					                            transition={{duration: 0.1}}>
 | 
				
			||||||
 | 
					                            <UsersTab/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        </motion.div>
 | 
				
			||||||
 | 
					                    </Tabs.Panel>
 | 
				
			||||||
 | 
					                    <Tabs.Panel value={"rolesAndPositions"}>
 | 
				
			||||||
 | 
					                        <motion.div
 | 
				
			||||||
 | 
					                            initial={{scaleY: 0}}
 | 
				
			||||||
 | 
					                            animate={{scaleY: 1}}
 | 
				
			||||||
 | 
					                            transition={{duration: 0.1}}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            <RolesAndPositionsTab/>
 | 
				
			||||||
 | 
					                        </motion.div>
 | 
				
			||||||
 | 
					                    </Tabs.Panel>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					            </PageBlock>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AdminPage;
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import ObjectSelect, {ObjectSelectProps} from "../../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
 | 
					import {PositionSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					import usePositionsList from "../../hooks/usePositionsList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<ObjectSelectProps<PositionSchema>, 'data' | 'getLabelFn' | 'getValueFn'>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PositionSelect: FC<Props> = (props) => {
 | 
				
			||||||
 | 
					    const {objects: positions} = usePositionsList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ObjectSelect
 | 
				
			||||||
 | 
					            getLabelFn={(position) => position.name}
 | 
				
			||||||
 | 
					            getValueFn={(position) => position.key}
 | 
				
			||||||
 | 
					            data={positions}
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default PositionSelect;
 | 
				
			||||||
@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
				
			||||||
 | 
					import {PositionSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
 | 
					import {usePositionsTableColumns} from "./columns.tsx";
 | 
				
			||||||
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					import {Button, Flex, rem} from "@mantine/core";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CRUDTableProps<PositionSchema>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PositionsTable: FC<Props> = ({items}) => {
 | 
				
			||||||
 | 
					    const columns = usePositionsTableColumns();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <BaseTable
 | 
				
			||||||
 | 
					            restProps={{
 | 
				
			||||||
 | 
					                enableTopToolbar: true,
 | 
				
			||||||
 | 
					                enableSorting: false,
 | 
				
			||||||
 | 
					                enableColumnActions: false,
 | 
				
			||||||
 | 
					                renderTopToolbar: () => (
 | 
				
			||||||
 | 
					                    <Flex p={rem(10)}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        <Button
 | 
				
			||||||
 | 
					                            variant={"default"}
 | 
				
			||||||
 | 
					                            onClick={() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            }}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            Создать должность
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                    </Flex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            data={items}
 | 
				
			||||||
 | 
					            columns={columns}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default PositionsTable;
 | 
				
			||||||
							
								
								
									
										16
									
								
								src/pages/AdminPage/components/PositionsTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/pages/AdminPage/components/PositionsTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					import {useMemo} from "react";
 | 
				
			||||||
 | 
					import {MRT_ColumnDef} from "mantine-react-table";
 | 
				
			||||||
 | 
					import {PositionSchema} from "../../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const usePositionsTableColumns = () => {
 | 
				
			||||||
 | 
					    return useMemo<MRT_ColumnDef<PositionSchema>[]>(() => [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "key",
 | 
				
			||||||
 | 
					            header: "Ключ"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "name",
 | 
				
			||||||
 | 
					            header: "Название должности"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ], []);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/pages/AdminPage/components/RoleSelect/RoleSelect.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/pages/AdminPage/components/RoleSelect/RoleSelect.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import ObjectSelect, {ObjectSelectProps} from "../../../../components/ObjectSelect/ObjectSelect.tsx";
 | 
				
			||||||
 | 
					import {RoleSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					import useRolesList from "../../hooks/useRolesList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = Omit<ObjectSelectProps<RoleSchema>, 'data' | 'getLabelFn' | 'getValueFn'>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RolesSelect: FC<Props> = (props) => {
 | 
				
			||||||
 | 
					    const {objects: roles} = useRolesList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <ObjectSelect
 | 
				
			||||||
 | 
					            getLabelFn={(position) => position.name}
 | 
				
			||||||
 | 
					            getValueFn={(position) => position.key}
 | 
				
			||||||
 | 
					            data={roles}
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default RolesSelect;
 | 
				
			||||||
							
								
								
									
										81
									
								
								src/pages/AdminPage/components/UsersTable/UsersTable.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/pages/AdminPage/components/UsersTable/UsersTable.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
				
			||||||
 | 
					import {UserSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					import {ActionIcon, Flex, Text, Tooltip} from "@mantine/core";
 | 
				
			||||||
 | 
					import {useUsersTableColumns} from "./columns.tsx";
 | 
				
			||||||
 | 
					import {IconEdit, IconTrash} from "@tabler/icons-react";
 | 
				
			||||||
 | 
					import {modals} from "@mantine/modals";
 | 
				
			||||||
 | 
					import {MRT_TableOptions} from "mantine-react-table";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = CRUDTableProps<UserSchema>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const UsersTable: FC<Props> = ({items, onChange, onDelete}) => {
 | 
				
			||||||
 | 
					    const columns = useUsersTableColumns();
 | 
				
			||||||
 | 
					    const onEditClick = (user: UserSchema) => {
 | 
				
			||||||
 | 
					        if (!onChange) return;
 | 
				
			||||||
 | 
					        modals.openContextModal({
 | 
				
			||||||
 | 
					            modal: "userFormModal",
 | 
				
			||||||
 | 
					            title: 'Редактирование пользователя',
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            innerProps: {
 | 
				
			||||||
 | 
					                onChange: onChange,
 | 
				
			||||||
 | 
					                element: user,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            size: "md"
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const onDeleteClick = (user: UserSchema) => {
 | 
				
			||||||
 | 
					        if (!onDelete) return;
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            title: 'Удаление пользователя',
 | 
				
			||||||
 | 
					            centered: true,
 | 
				
			||||||
 | 
					            children: (
 | 
				
			||||||
 | 
					                <Text size="sm">
 | 
				
			||||||
 | 
					                    Вы уверены что хотите удалить пользователя {user.firstName} {user.secondName}
 | 
				
			||||||
 | 
					                </Text>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            labels: {confirm: 'Да', cancel: "Нет"},
 | 
				
			||||||
 | 
					            confirmProps: {color: 'red'},
 | 
				
			||||||
 | 
					            onConfirm: () => onDelete(user)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <BaseTable
 | 
				
			||||||
 | 
					            data={items}
 | 
				
			||||||
 | 
					            columns={columns}
 | 
				
			||||||
 | 
					            restProps={{
 | 
				
			||||||
 | 
					                enableTopToolbar: false,
 | 
				
			||||||
 | 
					                enableSorting: false,
 | 
				
			||||||
 | 
					                enableColumnActions: false,
 | 
				
			||||||
 | 
					                enableRowActions: true,
 | 
				
			||||||
 | 
					                renderRowActions: ({row}) => (
 | 
				
			||||||
 | 
					                    <Flex gap="md">
 | 
				
			||||||
 | 
					                        <Tooltip onClick={() => {
 | 
				
			||||||
 | 
					                            onDeleteClick(row.original);
 | 
				
			||||||
 | 
					                        }} label="Удалить">
 | 
				
			||||||
 | 
					                            <ActionIcon variant={"default"}>
 | 
				
			||||||
 | 
					                                <IconTrash/>
 | 
				
			||||||
 | 
					                            </ActionIcon>
 | 
				
			||||||
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					                        <Tooltip
 | 
				
			||||||
 | 
					                            onClick={() => {
 | 
				
			||||||
 | 
					                                onEditClick(row.original)
 | 
				
			||||||
 | 
					                            }}
 | 
				
			||||||
 | 
					                            label="Редактировать">
 | 
				
			||||||
 | 
					                            <ActionIcon
 | 
				
			||||||
 | 
					                                variant={"default"}>
 | 
				
			||||||
 | 
					                                <IconEdit/>
 | 
				
			||||||
 | 
					                            </ActionIcon>
 | 
				
			||||||
 | 
					                        </Tooltip>
 | 
				
			||||||
 | 
					                    </Flex>
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            } as MRT_TableOptions<UserSchema>}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UsersTable;
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/pages/AdminPage/components/UsersTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/pages/AdminPage/components/UsersTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					import {useMemo} from "react";
 | 
				
			||||||
 | 
					import {MRT_ColumnDef} from "mantine-react-table";
 | 
				
			||||||
 | 
					import {UserSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {IconCheck, IconX} from "@tabler/icons-react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUsersTableColumns = () => {
 | 
				
			||||||
 | 
					    return useMemo<MRT_ColumnDef<UserSchema>[]>(() => [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "id",
 | 
				
			||||||
 | 
					            header: "ID"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "telegramId",
 | 
				
			||||||
 | 
					            header: "ID Телеграм"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "phoneNumber",
 | 
				
			||||||
 | 
					            header: "Номер телефона"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "role.name",
 | 
				
			||||||
 | 
					            header: "Роль"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "comment",
 | 
				
			||||||
 | 
					            header: "Дополнительная информация"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "isAdmin",
 | 
				
			||||||
 | 
					            header: "Администратор",
 | 
				
			||||||
 | 
					            Cell: ({row}) => row.original.isAdmin ? <IconCheck/> : <IconX/>
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accessorKey: "isBlocked",
 | 
				
			||||||
 | 
					            header: "Заблокирован",
 | 
				
			||||||
 | 
					            Cell: ({row}) => row.original.isBlocked ? <IconCheck/> : <IconX/>
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ], []);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/pages/AdminPage/hooks/usePositionsList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/pages/AdminPage/hooks/usePositionsList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import {PositionService} from "../../../client";
 | 
				
			||||||
 | 
					import ObjectList from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const usePositionsList = () => ObjectList({
 | 
				
			||||||
 | 
					    queryFn: PositionService.getAllPositions,
 | 
				
			||||||
 | 
					    getObjectsFn: response => response.positions,
 | 
				
			||||||
 | 
					    queryKey: "getAllPositions"
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export default usePositionsList;
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/pages/AdminPage/hooks/useRolesList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/pages/AdminPage/hooks/useRolesList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import ObjectList from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					import {RoleService} from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useRolesList = () => ObjectList({
 | 
				
			||||||
 | 
					    queryFn: RoleService.getAllRoles,
 | 
				
			||||||
 | 
					    getObjectsFn: response => response.roles,
 | 
				
			||||||
 | 
					    queryKey: "getAllRoles"
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export default useRolesList;
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/pages/AdminPage/hooks/useUsersList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/pages/AdminPage/hooks/useUsersList.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					import ObjectList from "../../../hooks/objectList.tsx";
 | 
				
			||||||
 | 
					import {UserService} from "../../../client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useUsersList = () => ObjectList({
 | 
				
			||||||
 | 
					    queryFn: UserService.getAllUsers,
 | 
				
			||||||
 | 
					    getObjectsFn: (response) => response.users,
 | 
				
			||||||
 | 
					    queryKey: "getAllUsers"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default useUsersList;
 | 
				
			||||||
							
								
								
									
										108
									
								
								src/pages/AdminPage/modals/UserFormModal/UserFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/pages/AdminPage/modals/UserFormModal/UserFormModal.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					import {ContextModalProps} from "@mantine/modals";
 | 
				
			||||||
 | 
					import BaseFormModal, {EditProps} from "../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
 | 
					import {UserSchema} from "../../../../client";
 | 
				
			||||||
 | 
					import {useForm} from "@mantine/form";
 | 
				
			||||||
 | 
					import {Checkbox, Fieldset, Input, Stack, Textarea, TextInput} from "@mantine/core";
 | 
				
			||||||
 | 
					import RoleSelect from "../../components/RoleSelect/RoleSelect.tsx";
 | 
				
			||||||
 | 
					import PositionSelect from "../../components/PositionSelect/PositionSelect.tsx";
 | 
				
			||||||
 | 
					import {UserRoleEnum} from "../../../../shared/enums/UserRole.ts";
 | 
				
			||||||
 | 
					import {capitalize} from "lodash";
 | 
				
			||||||
 | 
					import {IMaskInput} from "react-imask";
 | 
				
			||||||
 | 
					import phone from "phone";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Props = EditProps<UserSchema>;
 | 
				
			||||||
 | 
					const UserFormModal = ({context, id, innerProps}: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					    const initialValues = innerProps.element;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const form = useForm<UserSchema>({
 | 
				
			||||||
 | 
					        initialValues: initialValues,
 | 
				
			||||||
 | 
					        validate: {
 | 
				
			||||||
 | 
					            firstName: value => !value.trim() && "Укажите имя пользователя",
 | 
				
			||||||
 | 
					            secondName: value => !value.trim() && "Укажите фамилию",
 | 
				
			||||||
 | 
					            position: (value, values) => ((values.role.key === UserRoleEnum.EMPLOYEE) && (!value)) && 'Необходимо указать должность сотрудника',
 | 
				
			||||||
 | 
					            phoneNumber: value => !phone(value || '', {
 | 
				
			||||||
 | 
					                country: "",
 | 
				
			||||||
 | 
					                strictDetection: false,
 | 
				
			||||||
 | 
					                validateMobilePrefix: false
 | 
				
			||||||
 | 
					            }).isValid && 'Неверно указан номер телефона',
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    console.log(form.getInputProps('isAdmin'))
 | 
				
			||||||
 | 
					    return (<BaseFormModal
 | 
				
			||||||
 | 
					            form={form}
 | 
				
			||||||
 | 
					            closeOnSubmit
 | 
				
			||||||
 | 
					            onClose={() => context.closeContextModal(id)}
 | 
				
			||||||
 | 
					            {...innerProps}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <BaseFormModal.Body>
 | 
				
			||||||
 | 
					                <>
 | 
				
			||||||
 | 
					                    <Fieldset legend={"Общая информация"}>
 | 
				
			||||||
 | 
					                        <Stack>
 | 
				
			||||||
 | 
					                            <TextInput
 | 
				
			||||||
 | 
					                                label={"Имя"}
 | 
				
			||||||
 | 
					                                placeholder={"Введите имя пользователя"}
 | 
				
			||||||
 | 
					                                {...form.getInputProps("firstName")}
 | 
				
			||||||
 | 
					                                onChange={event => form.getInputProps('firstName').onChange(capitalize(event.target.value).trim())}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <TextInput
 | 
				
			||||||
 | 
					                                {...form.getInputProps("secondName")}
 | 
				
			||||||
 | 
					                                label={"Фамилия"}
 | 
				
			||||||
 | 
					                                placeholder={"Введите фамилию пользователя"}
 | 
				
			||||||
 | 
					                                onChange={event => form.getInputProps('secondName').onChange(capitalize(event.target.value).trim())}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <Input.Wrapper
 | 
				
			||||||
 | 
					                                label={"Номер телефона"}
 | 
				
			||||||
 | 
					                                error={form.getInputProps("phoneNumber").error}
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                                <Input
 | 
				
			||||||
 | 
					                                    component={IMaskInput}
 | 
				
			||||||
 | 
					                                    mask="+7 000 000-00-00"
 | 
				
			||||||
 | 
					                                    placeholder={"Введите номер телефона"}
 | 
				
			||||||
 | 
					                                    {...form.getInputProps("phoneNumber")}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            </Input.Wrapper>
 | 
				
			||||||
 | 
					                        </Stack>
 | 
				
			||||||
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					                    <Fieldset legend={"Роль и должность"}>
 | 
				
			||||||
 | 
					                        <Stack>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <RoleSelect
 | 
				
			||||||
 | 
					                                label={"Роль пользователя"}
 | 
				
			||||||
 | 
					                                placeholder={"Выберите роль пользователя"}
 | 
				
			||||||
 | 
					                                {...form.getInputProps('role')}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            {form.values.role.key === UserRoleEnum.EMPLOYEE &&
 | 
				
			||||||
 | 
					                                <PositionSelect
 | 
				
			||||||
 | 
					                                    label={"Должность сотрудника"}
 | 
				
			||||||
 | 
					                                    placeholder={"Выберите должность сотрудника"}
 | 
				
			||||||
 | 
					                                    {...form.getInputProps('position')}
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        </Stack>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					                    <Fieldset legend={"Дополнительные параметры"}>
 | 
				
			||||||
 | 
					                        <Stack>
 | 
				
			||||||
 | 
					                            <Checkbox
 | 
				
			||||||
 | 
					                                label={"Права администратора"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                {...form.getInputProps('isAdmin', {type: "checkbox"})}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <Checkbox
 | 
				
			||||||
 | 
					                                label={"Заблокирован"}
 | 
				
			||||||
 | 
					                                {...form.getInputProps('isBlocked', {type: "checkbox"})}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <Textarea
 | 
				
			||||||
 | 
					                                label={"Дополнительная информация"}
 | 
				
			||||||
 | 
					                                {...form.getInputProps('comment')}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        </Stack>
 | 
				
			||||||
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					                </>
 | 
				
			||||||
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
 | 
					        </BaseFormModal>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UserFormModal;
 | 
				
			||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import {Tabs} from "@mantine/core";
 | 
				
			||||||
 | 
					import PositionsTable from "../../components/PositionsTable/PositionsTable.tsx";
 | 
				
			||||||
 | 
					import usePositionsList from "../../hooks/usePositionsList.tsx";
 | 
				
			||||||
 | 
					import {motion} from "framer-motion";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RolesAndPositionsTab = () => {
 | 
				
			||||||
 | 
					    const {objects: positions} = usePositionsList();
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Tabs w={"100%"}
 | 
				
			||||||
 | 
					              variant={"default"}
 | 
				
			||||||
 | 
					              keepMounted={false}
 | 
				
			||||||
 | 
					              defaultValue={"roles"}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <Tabs.List grow>
 | 
				
			||||||
 | 
					                <Tabs.Tab value={"roles"}>Роли</Tabs.Tab>
 | 
				
			||||||
 | 
					                <Tabs.Tab value={"positions"}>Должности</Tabs.Tab>
 | 
				
			||||||
 | 
					            </Tabs.List>
 | 
				
			||||||
 | 
					            <Tabs.Panel value={"roles"}>
 | 
				
			||||||
 | 
					                <motion.div
 | 
				
			||||||
 | 
					                    initial={{scaleY: 0}}
 | 
				
			||||||
 | 
					                    animate={{scaleY: 1}}
 | 
				
			||||||
 | 
					                    transition={{duration: 0.1}}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                    <PositionsTable items={positions}/>
 | 
				
			||||||
 | 
					                </motion.div>
 | 
				
			||||||
 | 
					            </Tabs.Panel>
 | 
				
			||||||
 | 
					            <Tabs.Panel value={"positions"}>
 | 
				
			||||||
 | 
					                <motion.div
 | 
				
			||||||
 | 
					                    initial={{scaleY: 0}}
 | 
				
			||||||
 | 
					                    animate={{scaleY: 1}}
 | 
				
			||||||
 | 
					                    transition={{duration: 0.1}}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                    <PositionsTable items={positions}/>
 | 
				
			||||||
 | 
					                </motion.div>
 | 
				
			||||||
 | 
					            </Tabs.Panel>
 | 
				
			||||||
 | 
					        </Tabs>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export default RolesAndPositionsTab;
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/pages/AdminPage/tabs/Users/UsersTab.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/pages/AdminPage/tabs/Users/UsersTab.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import useUsersList from "../../hooks/useUsersList.tsx";
 | 
				
			||||||
 | 
					import UsersTable from "../../components/UsersTable/UsersTable.tsx";
 | 
				
			||||||
 | 
					import {UserSchema, UserService} from "../../../../client";
 | 
				
			||||||
 | 
					import {notifications} from "../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const UsersTab = () => {
 | 
				
			||||||
 | 
					    const {objects: users, refetch} = useUsersList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const onChange = (user: UserSchema) => {
 | 
				
			||||||
 | 
					        UserService.updateUser({
 | 
				
			||||||
 | 
					            requestBody: {
 | 
				
			||||||
 | 
					                data: {
 | 
				
			||||||
 | 
					                    ...user,
 | 
				
			||||||
 | 
					                    positionKey: user.position?.key,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }).then(async ({ok, message}) => {
 | 
				
			||||||
 | 
					            notifications.guess(ok, {message});
 | 
				
			||||||
 | 
					            if (!ok) return;
 | 
				
			||||||
 | 
					            await refetch();
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const onDelete = async (user: UserSchema) => {
 | 
				
			||||||
 | 
					        onChange({...user, isDeleted: true});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <UsersTable
 | 
				
			||||||
 | 
					            items={users}
 | 
				
			||||||
 | 
					            onChange={onChange}
 | 
				
			||||||
 | 
					            onDelete={onDelete}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UsersTab;
 | 
				
			||||||
@@ -2,23 +2,22 @@ import {UseFormReturnType} from "@mantine/form";
 | 
				
			|||||||
import {Button, Flex, rem} from "@mantine/core";
 | 
					import {Button, Flex, rem} from "@mantine/core";
 | 
				
			||||||
import {FC} from "react";
 | 
					import {FC} from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CreateProps<T> = {
 | 
					export type CreateProps<T> = {
 | 
				
			||||||
    onCreate(values: T): void;
 | 
					    onCreate(values: T): void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type EditProps<T> = {
 | 
					export type EditProps<T> = {
 | 
				
			||||||
    onChange(values: T): void;
 | 
					    onChange(values: T): void;
 | 
				
			||||||
    element: T;
 | 
					    element: T;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type CreateEditFormProps<T> = CreateProps<T> | EditProps<T>;
 | 
					export type CreateEditFormProps<T> = CreateProps<T> | EditProps<T>;
 | 
				
			||||||
 | 
					export type BaseFormProps<T> = {
 | 
				
			||||||
type BaseProps<T> = {
 | 
					 | 
				
			||||||
    form: UseFormReturnType<T>
 | 
					    form: UseFormReturnType<T>
 | 
				
			||||||
    onClose: () => void;
 | 
					    onClose: () => void;
 | 
				
			||||||
    closeOnSubmit?: boolean;
 | 
					    closeOnSubmit?: boolean;
 | 
				
			||||||
    children: React.JSX.Element;
 | 
					    children: React.JSX.Element;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type Props<T> = BaseProps<T> & (CreateProps<T> | EditProps<T>);
 | 
					type Props<T> = BaseFormProps<T> & (CreateProps<T> | EditProps<T>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const BaseFormModal = <T, >(props: Props<T>) => {
 | 
					const BaseFormModal = <T, >(props: Props<T>) => {
 | 
				
			||||||
    const {closeOnSubmit = false} = props;
 | 
					    const {closeOnSubmit = false} = props;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,15 +2,18 @@ import {FC} from "react";
 | 
				
			|||||||
import {useDealPageContext} from "../../../contexts/DealPageContext.tsx";
 | 
					import {useDealPageContext} from "../../../contexts/DealPageContext.tsx";
 | 
				
			||||||
import {Button, Checkbox, Divider, Fieldset, Flex, Group, rem, Textarea, TextInput} from "@mantine/core";
 | 
					import {Button, Checkbox, Divider, Fieldset, Flex, Group, rem, Textarea, TextInput} from "@mantine/core";
 | 
				
			||||||
import {useForm} from "@mantine/form";
 | 
					import {useForm} from "@mantine/form";
 | 
				
			||||||
import {ClientService, DealSchema, DealService} from "../../../../../client";
 | 
					import {ClientService, DealSchema, DealService, ShippingWarehouseSchema} from "../../../../../client";
 | 
				
			||||||
import {DealStatus, DealStatusDictionary} from "../../../../../shared/enums/DealStatus.ts";
 | 
					import {DealStatus, DealStatusDictionary} from "../../../../../shared/enums/DealStatus.ts";
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					    from "../../../../../components/Selects/ShippingWarehouseAutocomplete/ShippingWarehouseAutocomplete.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
    deal: DealSchema
 | 
					    deal: DealSchema
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FormType = Omit<DealSchema, 'statusHistory' | 'services' | 'products'>
 | 
					type FormType = Omit<DealSchema, 'statusHistory' | 'services' | 'products'>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Content: FC<Props> = ({deal}) => {
 | 
					const Content: FC<Props> = ({deal}) => {
 | 
				
			||||||
@@ -30,7 +33,7 @@ const Content: FC<Props> = ({deal}) => {
 | 
				
			|||||||
        return DealService.updateDealGeneralInfo({
 | 
					        return DealService.updateDealGeneralInfo({
 | 
				
			||||||
            requestBody: {
 | 
					            requestBody: {
 | 
				
			||||||
                dealId: deal.id,
 | 
					                dealId: deal.id,
 | 
				
			||||||
                data: values
 | 
					                data: {...values, shippingWarehouse: values.shippingWarehouse?.toString()}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }).then(({ok, message}) => {
 | 
					        }).then(({ok, message}) => {
 | 
				
			||||||
            notifications.guess(ok, {message});
 | 
					            notifications.guess(ok, {message});
 | 
				
			||||||
@@ -61,6 +64,10 @@ const Content: FC<Props> = ({deal}) => {
 | 
				
			|||||||
        // updating deal info
 | 
					        // updating deal info
 | 
				
			||||||
        await updateDealInfo(values);
 | 
					        await updateDealInfo(values);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const isShippingWarehouse = (value: (ShippingWarehouseSchema | string | null | undefined)): value is ShippingWarehouseSchema => {
 | 
				
			||||||
 | 
					        return !["string", "null", "undefined"].includes((typeof value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
 | 
					        <form onSubmit={form.onSubmit((values) => handleSubmit(values))}>
 | 
				
			||||||
            <Flex direction={'column'}>
 | 
					            <Flex direction={'column'}>
 | 
				
			||||||
@@ -87,11 +94,17 @@ const Content: FC<Props> = ({deal}) => {
 | 
				
			|||||||
                            placeholder={'Введите коментарий к сделке'}
 | 
					                            placeholder={'Введите коментарий к сделке'}
 | 
				
			||||||
                            {...form.getInputProps('comment')}
 | 
					                            {...form.getInputProps('comment')}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <TextInput
 | 
					                        <ShippingWarehouseAutocomplete
 | 
				
			||||||
                            disabled
 | 
					 | 
				
			||||||
                            placeholder={"Введите склад отгрузки"}
 | 
					                            placeholder={"Введите склад отгрузки"}
 | 
				
			||||||
                            label={"Склад отгрузки"}
 | 
					                            label={"Склад отгрузки"}
 | 
				
			||||||
                            value={form.values.shippingWarehouse?.name}
 | 
					                            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)
 | 
				
			||||||
 | 
					                            }}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                    </Flex>
 | 
					                    </Flex>
 | 
				
			||||||
                </Fieldset>
 | 
					                </Fieldset>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,17 +5,27 @@ import {AuthService} from "../../client";
 | 
				
			|||||||
import TelegramLoginButton, {TelegramUser} from "../../components/TelegramAuthButton/TelegramAuthButton.tsx";
 | 
					import TelegramLoginButton, {TelegramUser} from "../../components/TelegramAuthButton/TelegramAuthButton.tsx";
 | 
				
			||||||
import {notifications} from "../../shared/lib/notifications.ts";
 | 
					import {notifications} from "../../shared/lib/notifications.ts";
 | 
				
			||||||
import {login} from "../../features/authSlice.ts";
 | 
					import {login} from "../../features/authSlice.ts";
 | 
				
			||||||
import {useNavigate} from "@tanstack/react-router";
 | 
					import {Navigate, useNavigate} from "@tanstack/react-router";
 | 
				
			||||||
import {useSelector} from "react-redux";
 | 
					import {useSelector} from "react-redux";
 | 
				
			||||||
 | 
					import {useEffect} from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LoginPage = () => {
 | 
					const LoginPage = () => {
 | 
				
			||||||
    const dispatch = useAppDispatch();
 | 
					    const dispatch = useAppDispatch();
 | 
				
			||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        if (authState.isAuthorized)
 | 
				
			||||||
 | 
					            // ???????????
 | 
				
			||||||
 | 
					            navigate({to: "/leads"}).then(() => {
 | 
				
			||||||
 | 
					                navigate({to: "/leads"}).then(() => {
 | 
				
			||||||
 | 
					                    notifications.success({message: "Вы успешно вошли!"})
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    }, [authState.isAuthorized])
 | 
				
			||||||
    if (authState.isAuthorized) {
 | 
					    if (authState.isAuthorized) {
 | 
				
			||||||
        navigate({to: "/leads"})
 | 
					        return (<Navigate to={"/leads"}/>)
 | 
				
			||||||
        return (<></>)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Container size={420} my={40}>
 | 
					        <Container size={420} my={40}>
 | 
				
			||||||
@@ -41,9 +51,6 @@ const LoginPage = () => {
 | 
				
			|||||||
                            AuthService.loginAuthLoginPost({requestBody: data})
 | 
					                            AuthService.loginAuthLoginPost({requestBody: data})
 | 
				
			||||||
                                .then(({accessToken}) => {
 | 
					                                .then(({accessToken}) => {
 | 
				
			||||||
                                    dispatch(login({accessToken: accessToken}));
 | 
					                                    dispatch(login({accessToken: accessToken}));
 | 
				
			||||||
                                    navigate({to: "/"}).then(() => {
 | 
					 | 
				
			||||||
                                        notifications.success({message: "Вы успешно вошли!"})
 | 
					 | 
				
			||||||
                                    })
 | 
					 | 
				
			||||||
                                }).catch(() => {
 | 
					                                }).catch(() => {
 | 
				
			||||||
                                notifications.error({message: "Неудалось войти!"})
 | 
					                                notifications.error({message: "Неудалось войти!"})
 | 
				
			||||||
                            })
 | 
					                            })
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,19 @@
 | 
				
			|||||||
import {Outlet} from "@tanstack/react-router";
 | 
					import {useMatch, useMatches} from "@tanstack/react-router";
 | 
				
			||||||
import {useEffect} from "react";
 | 
					import {useEffect} from "react";
 | 
				
			||||||
import {useSelector} from "react-redux";
 | 
					import {useSelector} from "react-redux";
 | 
				
			||||||
import {RootState} from "../../redux/store.ts";
 | 
					import {RootState} from "../../redux/store.ts";
 | 
				
			||||||
import {OpenAPI} from "../../client";
 | 
					import {OpenAPI} from "../../client";
 | 
				
			||||||
import PageWrapper from "../PageWrapper/PageWrapper.tsx";
 | 
					import PageWrapper from "../PageWrapper/PageWrapper.tsx";
 | 
				
			||||||
import {LoadingOverlay} from "@mantine/core";
 | 
					import {LoadingOverlay} from "@mantine/core";
 | 
				
			||||||
 | 
					import {AnimatePresence} from "framer-motion";
 | 
				
			||||||
 | 
					import AnimatedOutlet from "../../components/AnimatedOutlet/au.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const RootPage = () => {
 | 
					const RootPage = () => {
 | 
				
			||||||
 | 
					    const matches = useMatches();
 | 
				
			||||||
 | 
					    const match = useMatch({strict: false});
 | 
				
			||||||
 | 
					    const nextMatchIndex = matches.findIndex((d) => d.id === match.id) + 1;
 | 
				
			||||||
 | 
					    const nextMatch = matches[nextMatchIndex];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const authState = useSelector((state: RootState) => state.auth);
 | 
					    const authState = useSelector((state: RootState) => state.auth);
 | 
				
			||||||
    const uiState = useSelector((state: RootState) => state.ui);
 | 
					    const uiState = useSelector((state: RootState) => state.ui);
 | 
				
			||||||
    const rewriteLocalStorage = () => {
 | 
					    const rewriteLocalStorage = () => {
 | 
				
			||||||
@@ -20,12 +27,13 @@ const RootPage = () => {
 | 
				
			|||||||
        rewriteLocalStorage();
 | 
					        rewriteLocalStorage();
 | 
				
			||||||
        setOpenApiToken();
 | 
					        setOpenApiToken();
 | 
				
			||||||
    }, [authState]);
 | 
					    }, [authState]);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            <LoadingOverlay visible={uiState.isLoading}/>
 | 
					            <LoadingOverlay visible={uiState.isLoading}/>
 | 
				
			||||||
            <PageWrapper>
 | 
					            <PageWrapper>
 | 
				
			||||||
                <Outlet/>
 | 
					                <AnimatePresence mode="popLayout">
 | 
				
			||||||
 | 
					                    <AnimatedOutlet key={nextMatch.id}/>
 | 
				
			||||||
 | 
					                </AnimatePresence>
 | 
				
			||||||
            </PageWrapper>
 | 
					            </PageWrapper>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,6 +86,9 @@ export const ServicesPage: FC = () => {
 | 
				
			|||||||
                await refetch();
 | 
					                await refetch();
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <div className={styles['container']}>
 | 
					        <div className={styles['container']}>
 | 
				
			||||||
            <PageBlock>
 | 
					            <PageBlock>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ const LoginLazyImport = createFileRoute('/login')()
 | 
				
			|||||||
const LeadsLazyImport = createFileRoute('/leads')()
 | 
					const LeadsLazyImport = createFileRoute('/leads')()
 | 
				
			||||||
const ClientsLazyImport = createFileRoute('/clients')()
 | 
					const ClientsLazyImport = createFileRoute('/clients')()
 | 
				
			||||||
const BarcodeLazyImport = createFileRoute('/barcode')()
 | 
					const BarcodeLazyImport = createFileRoute('/barcode')()
 | 
				
			||||||
 | 
					const AdminLazyImport = createFileRoute('/admin')()
 | 
				
			||||||
const IndexLazyImport = createFileRoute('/')()
 | 
					const IndexLazyImport = createFileRoute('/')()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Create/Update Routes
 | 
					// Create/Update Routes
 | 
				
			||||||
@@ -62,6 +63,11 @@ const BarcodeLazyRoute = BarcodeLazyImport.update({
 | 
				
			|||||||
  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({
 | 
				
			||||||
 | 
					  path: '/admin',
 | 
				
			||||||
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
 | 
					} as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const IndexLazyRoute = IndexLazyImport.update({
 | 
					const IndexLazyRoute = IndexLazyImport.update({
 | 
				
			||||||
  path: '/',
 | 
					  path: '/',
 | 
				
			||||||
  getParentRoute: () => rootRoute,
 | 
					  getParentRoute: () => rootRoute,
 | 
				
			||||||
@@ -72,34 +78,65 @@ const IndexLazyRoute = IndexLazyImport.update({
 | 
				
			|||||||
declare module '@tanstack/react-router' {
 | 
					declare module '@tanstack/react-router' {
 | 
				
			||||||
  interface FileRoutesByPath {
 | 
					  interface FileRoutesByPath {
 | 
				
			||||||
    '/': {
 | 
					    '/': {
 | 
				
			||||||
 | 
					      id: '/'
 | 
				
			||||||
 | 
					      path: '/'
 | 
				
			||||||
 | 
					      fullPath: '/'
 | 
				
			||||||
      preLoaderRoute: typeof IndexLazyImport
 | 
					      preLoaderRoute: typeof IndexLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    '/admin': {
 | 
				
			||||||
 | 
					      id: '/admin'
 | 
				
			||||||
 | 
					      path: '/admin'
 | 
				
			||||||
 | 
					      fullPath: '/admin'
 | 
				
			||||||
 | 
					      preLoaderRoute: typeof AdminLazyImport
 | 
				
			||||||
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    '/barcode': {
 | 
					    '/barcode': {
 | 
				
			||||||
 | 
					      id: '/barcode'
 | 
				
			||||||
 | 
					      path: '/barcode'
 | 
				
			||||||
 | 
					      fullPath: '/barcode'
 | 
				
			||||||
      preLoaderRoute: typeof BarcodeLazyImport
 | 
					      preLoaderRoute: typeof BarcodeLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/clients': {
 | 
					    '/clients': {
 | 
				
			||||||
 | 
					      id: '/clients'
 | 
				
			||||||
 | 
					      path: '/clients'
 | 
				
			||||||
 | 
					      fullPath: '/clients'
 | 
				
			||||||
      preLoaderRoute: typeof ClientsLazyImport
 | 
					      preLoaderRoute: typeof ClientsLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/leads': {
 | 
					    '/leads': {
 | 
				
			||||||
 | 
					      id: '/leads'
 | 
				
			||||||
 | 
					      path: '/leads'
 | 
				
			||||||
 | 
					      fullPath: '/leads'
 | 
				
			||||||
      preLoaderRoute: typeof LeadsLazyImport
 | 
					      preLoaderRoute: typeof LeadsLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/login': {
 | 
					    '/login': {
 | 
				
			||||||
 | 
					      id: '/login'
 | 
				
			||||||
 | 
					      path: '/login'
 | 
				
			||||||
 | 
					      fullPath: '/login'
 | 
				
			||||||
      preLoaderRoute: typeof LoginLazyImport
 | 
					      preLoaderRoute: typeof LoginLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/products': {
 | 
					    '/products': {
 | 
				
			||||||
 | 
					      id: '/products'
 | 
				
			||||||
 | 
					      path: '/products'
 | 
				
			||||||
 | 
					      fullPath: '/products'
 | 
				
			||||||
      preLoaderRoute: typeof ProductsLazyImport
 | 
					      preLoaderRoute: typeof ProductsLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/services': {
 | 
					    '/services': {
 | 
				
			||||||
 | 
					      id: '/services'
 | 
				
			||||||
 | 
					      path: '/services'
 | 
				
			||||||
 | 
					      fullPath: '/services'
 | 
				
			||||||
      preLoaderRoute: typeof ServicesLazyImport
 | 
					      preLoaderRoute: typeof ServicesLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    '/test': {
 | 
					    '/test': {
 | 
				
			||||||
 | 
					      id: '/test'
 | 
				
			||||||
 | 
					      path: '/test'
 | 
				
			||||||
 | 
					      fullPath: '/test'
 | 
				
			||||||
      preLoaderRoute: typeof TestLazyImport
 | 
					      preLoaderRoute: typeof TestLazyImport
 | 
				
			||||||
      parentRoute: typeof rootRoute
 | 
					      parentRoute: typeof rootRoute
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -108,8 +145,9 @@ declare module '@tanstack/react-router' {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Create and export the route tree
 | 
					// Create and export the route tree
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const routeTree = rootRoute.addChildren([
 | 
					export const routeTree = rootRoute.addChildren({
 | 
				
			||||||
  IndexLazyRoute,
 | 
					  IndexLazyRoute,
 | 
				
			||||||
 | 
					  AdminLazyRoute,
 | 
				
			||||||
  BarcodeLazyRoute,
 | 
					  BarcodeLazyRoute,
 | 
				
			||||||
  ClientsLazyRoute,
 | 
					  ClientsLazyRoute,
 | 
				
			||||||
  LeadsLazyRoute,
 | 
					  LeadsLazyRoute,
 | 
				
			||||||
@@ -117,6 +155,54 @@ export const routeTree = rootRoute.addChildren([
 | 
				
			|||||||
  ProductsLazyRoute,
 | 
					  ProductsLazyRoute,
 | 
				
			||||||
  ServicesLazyRoute,
 | 
					  ServicesLazyRoute,
 | 
				
			||||||
  TestLazyRoute,
 | 
					  TestLazyRoute,
 | 
				
			||||||
])
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* prettier-ignore-end */
 | 
					/* prettier-ignore-end */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ROUTE_MANIFEST_START
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "routes": {
 | 
				
			||||||
 | 
					    "__root__": {
 | 
				
			||||||
 | 
					      "filePath": "__root.tsx",
 | 
				
			||||||
 | 
					      "children": [
 | 
				
			||||||
 | 
					        "/",
 | 
				
			||||||
 | 
					        "/admin",
 | 
				
			||||||
 | 
					        "/barcode",
 | 
				
			||||||
 | 
					        "/clients",
 | 
				
			||||||
 | 
					        "/leads",
 | 
				
			||||||
 | 
					        "/login",
 | 
				
			||||||
 | 
					        "/products",
 | 
				
			||||||
 | 
					        "/services",
 | 
				
			||||||
 | 
					        "/test"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/": {
 | 
				
			||||||
 | 
					      "filePath": "index.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/admin": {
 | 
				
			||||||
 | 
					      "filePath": "admin.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/barcode": {
 | 
				
			||||||
 | 
					      "filePath": "barcode.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/clients": {
 | 
				
			||||||
 | 
					      "filePath": "clients.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/leads": {
 | 
				
			||||||
 | 
					      "filePath": "leads.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/login": {
 | 
				
			||||||
 | 
					      "filePath": "login.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/products": {
 | 
				
			||||||
 | 
					      "filePath": "products.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/services": {
 | 
				
			||||||
 | 
					      "filePath": "services.lazy.tsx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/test": {
 | 
				
			||||||
 | 
					      "filePath": "test.lazy.tsx"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ROUTE_MANIFEST_END */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								src/routes/admin.lazy.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/routes/admin.lazy.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import {createLazyFileRoute} from "@tanstack/react-router";
 | 
				
			||||||
 | 
					import AdminPage from "../pages/AdminPage/AdminPage.tsx";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const Route = createLazyFileRoute('/admin')({
 | 
				
			||||||
 | 
					    component: AdminPage
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
@@ -1,14 +1,43 @@
 | 
				
			|||||||
import {createLazyFileRoute} from "@tanstack/react-router";
 | 
					import {createLazyFileRoute} from "@tanstack/react-router";
 | 
				
			||||||
 | 
					import {Flex, Tabs} from '@mantine/core';
 | 
				
			||||||
 | 
					import {motion} from 'framer-motion';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Route = createLazyFileRoute('/test')({
 | 
					export const Route = createLazyFileRoute('/test')({
 | 
				
			||||||
    component: TestPage
 | 
					    component: TestPage
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tabs = [
 | 
				
			||||||
 | 
					    ['tab111', 'content111'],
 | 
				
			||||||
 | 
					    ['tab222', 'content222'],
 | 
				
			||||||
 | 
					    ['tab333', 'content333'],
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Demo() {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Tabs>
 | 
				
			||||||
 | 
					            {tabs.map((el, i) => (
 | 
				
			||||||
 | 
					                <Tabs.Tab key={i} value={el[0]}>
 | 
				
			||||||
 | 
					                    <motion.div
 | 
				
			||||||
 | 
					                        initial={{opacity: 0}}
 | 
				
			||||||
 | 
					                        animate={{opacity: 1}}
 | 
				
			||||||
 | 
					                        transition={{duration: 0.5}}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <div>{el[1]}</div>
 | 
				
			||||||
 | 
					                    </motion.div>
 | 
				
			||||||
 | 
					                </Tabs.Tab>
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					        </Tabs>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function TestPage() {
 | 
					function TestPage() {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
            {/*<ShippingWarehouseAutocomplete/>*/}
 | 
					            <Flex w={"80vw"}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <Demo/>
 | 
				
			||||||
 | 
					            </Flex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/shared/enums/UserRole.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/shared/enums/UserRole.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					export enum UserRoleEnum {
 | 
				
			||||||
 | 
					    USER = 'user',
 | 
				
			||||||
 | 
					    EMPLOYEE = 'employee',
 | 
				
			||||||
 | 
					    MANAGER = 'manager',
 | 
				
			||||||
 | 
					    ADMIN = 'admin'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user