crap
This commit is contained in:
		@@ -27,8 +27,12 @@ export type { HTTPValidationError } from './models/HTTPValidationError';
 | 
			
		||||
export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
 | 
			
		||||
export type { ProductCreateRequest } from './models/ProductCreateRequest';
 | 
			
		||||
export type { ProductCreateResponse } from './models/ProductCreateResponse';
 | 
			
		||||
export type { ProductDeleteRequest } from './models/ProductDeleteRequest';
 | 
			
		||||
export type { ProductDeleteResponse } from './models/ProductDeleteResponse';
 | 
			
		||||
export type { ProductGetResponse } from './models/ProductGetResponse';
 | 
			
		||||
export type { ProductSchema } from './models/ProductSchema';
 | 
			
		||||
export type { ProductUpdateRequest } from './models/ProductUpdateRequest';
 | 
			
		||||
export type { ProductUpdateResponse } from './models/ProductUpdateResponse';
 | 
			
		||||
export type { ServiceCategorySchema } from './models/ServiceCategorySchema';
 | 
			
		||||
export type { ServiceCreateCategoryRequest } from './models/ServiceCreateCategoryRequest';
 | 
			
		||||
export type { ServiceCreateCategoryResponse } from './models/ServiceCreateCategoryResponse';
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type AuthLoginResponse = {
 | 
			
		||||
    access_token: string;
 | 
			
		||||
    accessToken: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ClientDetailsSchema = {
 | 
			
		||||
    address?: (string | null);
 | 
			
		||||
    phone_number?: (string | null);
 | 
			
		||||
    phoneNumber?: (string | null);
 | 
			
		||||
    inn?: (number | null);
 | 
			
		||||
    email?: (string | null);
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ClientDetailsSchema } from './ClientDetailsSchema';
 | 
			
		||||
export type ClientUpdateDetailsRequest = {
 | 
			
		||||
    client_id: number;
 | 
			
		||||
    clientId: number;
 | 
			
		||||
    details: ClientDetailsSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { DealServiceSchema } from './DealServiceSchema';
 | 
			
		||||
export type DealAddServicesRequest = {
 | 
			
		||||
    deal_id: number;
 | 
			
		||||
    dealId: number;
 | 
			
		||||
    services: Array<DealServiceSchema>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type DealChangeStatusRequest = {
 | 
			
		||||
    deal_id: number;
 | 
			
		||||
    new_status: number;
 | 
			
		||||
    dealId: number;
 | 
			
		||||
    newStatus: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,9 @@
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type DealQuickCreateRequest = {
 | 
			
		||||
    name: string;
 | 
			
		||||
    client_name: string;
 | 
			
		||||
    client_address: string;
 | 
			
		||||
    clientName: string;
 | 
			
		||||
    clientAddress: string;
 | 
			
		||||
    comment: string;
 | 
			
		||||
    acceptance_date: string;
 | 
			
		||||
    acceptanceDate: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type DealQuickCreateResponse = {
 | 
			
		||||
    deal_id: number;
 | 
			
		||||
    dealId: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,9 @@
 | 
			
		||||
export type DealSummary = {
 | 
			
		||||
    id: number;
 | 
			
		||||
    name: string;
 | 
			
		||||
    client_name: string;
 | 
			
		||||
    changed_at: string;
 | 
			
		||||
    clientName: string;
 | 
			
		||||
    changedAt: string;
 | 
			
		||||
    status: number;
 | 
			
		||||
    total_price: number;
 | 
			
		||||
    totalPrice: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type PaginationInfoSchema = {
 | 
			
		||||
    total_pages: number;
 | 
			
		||||
    total_items: number;
 | 
			
		||||
    totalPages: number;
 | 
			
		||||
    totalItems: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
export type ProductCreateRequest = {
 | 
			
		||||
    name: string;
 | 
			
		||||
    article: string;
 | 
			
		||||
    client_id: number;
 | 
			
		||||
    clientId: number;
 | 
			
		||||
    barcodes: Array<string>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ProductCreateResponse = {
 | 
			
		||||
    product_id: number;
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
    productId?: (number | null);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								src/client/models/ProductDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/models/ProductDeleteRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ProductDeleteRequest = {
 | 
			
		||||
    productId: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ProductDeleteResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ProductDeleteResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ProductDeleteResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -6,6 +6,6 @@ import type { PaginationInfoSchema } from './PaginationInfoSchema';
 | 
			
		||||
import type { ProductSchema } from './ProductSchema';
 | 
			
		||||
export type ProductGetResponse = {
 | 
			
		||||
    products: Array<ProductSchema>;
 | 
			
		||||
    pagination_info: PaginationInfoSchema;
 | 
			
		||||
    paginationInfo: PaginationInfoSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ export type ProductSchema = {
 | 
			
		||||
    id: number;
 | 
			
		||||
    name: string;
 | 
			
		||||
    article: string;
 | 
			
		||||
    client_id: number;
 | 
			
		||||
    clientId: number;
 | 
			
		||||
    barcodes: Array<string>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ProductUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ProductUpdateRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ProductSchema } from './ProductSchema';
 | 
			
		||||
export type ProductUpdateRequest = {
 | 
			
		||||
    product: ProductSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/ProductUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/ProductUpdateResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ProductUpdateResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -4,7 +4,11 @@
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ProductCreateRequest } from '../models/ProductCreateRequest';
 | 
			
		||||
import type { ProductCreateResponse } from '../models/ProductCreateResponse';
 | 
			
		||||
import type { ProductDeleteRequest } from '../models/ProductDeleteRequest';
 | 
			
		||||
import type { ProductDeleteResponse } from '../models/ProductDeleteResponse';
 | 
			
		||||
import type { ProductGetResponse } from '../models/ProductGetResponse';
 | 
			
		||||
import type { ProductUpdateRequest } from '../models/ProductUpdateRequest';
 | 
			
		||||
import type { ProductUpdateResponse } from '../models/ProductUpdateResponse';
 | 
			
		||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
			
		||||
import { OpenAPI } from '../core/OpenAPI';
 | 
			
		||||
import { request as __request } from '../core/request';
 | 
			
		||||
@@ -14,7 +18,7 @@ export class ProductService {
 | 
			
		||||
     * @returns ProductCreateResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static createProductProductCreatePost({
 | 
			
		||||
    public static createProduct({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ProductCreateRequest,
 | 
			
		||||
@@ -29,6 +33,46 @@ export class ProductService {
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete Product
 | 
			
		||||
     * @returns ProductDeleteResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static deleteProduct({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ProductDeleteRequest,
 | 
			
		||||
    }): CancelablePromise<ProductDeleteResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/product/delete',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete Product
 | 
			
		||||
     * @returns ProductUpdateResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static updateProduct({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: ProductUpdateRequest,
 | 
			
		||||
    }): CancelablePromise<ProductUpdateResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/product/update',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Get Product
 | 
			
		||||
     * @returns ProductGetResponse Successful Response
 | 
			
		||||
 
 | 
			
		||||
@@ -2,13 +2,12 @@ import {
 | 
			
		||||
    MantineReactTable,
 | 
			
		||||
    MRT_ColumnDef,
 | 
			
		||||
    MRT_RowData,
 | 
			
		||||
    MRT_Table,
 | 
			
		||||
    MRT_TableInstance,
 | 
			
		||||
    MRT_TableOptions,
 | 
			
		||||
    useMantineReactTable
 | 
			
		||||
} from "mantine-react-table";
 | 
			
		||||
import {MRT_Localization_RU} from "mantine-react-table/locales/ru/index.cjs";
 | 
			
		||||
import {forwardRef, useEffect, useImperativeHandle} from 'react';
 | 
			
		||||
import {forwardRef, useImperativeHandle} from 'react';
 | 
			
		||||
 | 
			
		||||
type Props<T extends Record<string, any>, K extends keyof T> = {
 | 
			
		||||
    data: T[],
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ const CreateDealButton: FC<Props> = () => {
 | 
			
		||||
                                DealService.quickCreateDealQuickCreatePost({
 | 
			
		||||
                                    requestBody: {
 | 
			
		||||
                                        ...quickDeal,
 | 
			
		||||
                                        acceptance_date: dateWithoutTimezone(quickDeal.acceptance_date)
 | 
			
		||||
                                        acceptanceDate: dateWithoutTimezone(quickDeal.acceptanceDate)
 | 
			
		||||
                                    }
 | 
			
		||||
                                })
 | 
			
		||||
                            }}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
 | 
			
		||||
    const form = useForm({
 | 
			
		||||
        initialValues: {
 | 
			
		||||
            name: '',
 | 
			
		||||
            client_name: '',
 | 
			
		||||
            client_address: '',
 | 
			
		||||
            clientName: '',
 | 
			
		||||
            clientAddress: '',
 | 
			
		||||
            comment: '',
 | 
			
		||||
            acceptance_date: new Date()
 | 
			
		||||
            acceptanceDate: new Date()
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    return (
 | 
			
		||||
@@ -43,8 +43,8 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
 | 
			
		||||
                <div className={styles['inputs']}>
 | 
			
		||||
                    <ClientAutocomplete
 | 
			
		||||
                        withAddress
 | 
			
		||||
                        nameRestProps={form.getInputProps('client_name')}
 | 
			
		||||
                        addressRestProps={form.getInputProps('client_address')}
 | 
			
		||||
                        nameRestProps={form.getInputProps('clientName')}
 | 
			
		||||
                        addressRestProps={form.getInputProps('clientAddress')}
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
@@ -60,7 +60,7 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
 | 
			
		||||
                <div className={styles['inputs']}>
 | 
			
		||||
                    <DateTimePicker
 | 
			
		||||
                        placeholder={'Дата приемки'}
 | 
			
		||||
                        {...form.getInputProps('acceptance_date')}
 | 
			
		||||
                        {...form.getInputProps('acceptanceDate')}
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ const DealSummaryCard: FC<Props> = ({dealSummary}) => {
 | 
			
		||||
            <div className={styles['flex-row']}>
 | 
			
		||||
                <div className={styles['flex-item']}>
 | 
			
		||||
                    <Text size={"sm"} c={"gray.6"}>
 | 
			
		||||
                        {dealSummary.client_name}
 | 
			
		||||
                        {dealSummary.clientName}
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className={styles['flex-item']}>
 | 
			
		||||
@@ -23,14 +23,14 @@ const DealSummaryCard: FC<Props> = ({dealSummary}) => {
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className={styles['flex-item']}>
 | 
			
		||||
                    <Text size={"sm"} c={"gray.6"}>
 | 
			
		||||
                        {dealSummary.total_price.toLocaleString('ru-RU')} руб
 | 
			
		||||
                        {dealSummary.totalPrice.toLocaleString('ru-RU')} руб
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div className={classNames(styles['flex-row'], styles['flex-row-right'])}>
 | 
			
		||||
                <div className={styles['flex-item']}>
 | 
			
		||||
                    <Text size={"sm"} c={"gray.6"}>
 | 
			
		||||
                        {new Date(dealSummary.changed_at).toLocaleString('ru-RU')}
 | 
			
		||||
                        {new Date(dealSummary.changedAt).toLocaleString('ru-RU')}
 | 
			
		||||
                    </Text>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div className={styles['flex-item']}>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
import {ContextModalProps} from "@mantine/modals";
 | 
			
		||||
import {Button, Text} from "@mantine/core";
 | 
			
		||||
import {useForm} from "@mantine/form";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const CreateProductModal = ({
 | 
			
		||||
                                context,
 | 
			
		||||
                                id,
 | 
			
		||||
                                innerProps,
 | 
			
		||||
                            }: ContextModalProps<{ clientId: number }>) => {
 | 
			
		||||
    const form = useForm({
 | 
			
		||||
        initialValues: {
 | 
			
		||||
            name: '',
 | 
			
		||||
            article: '',
 | 
			
		||||
            barcode: ''
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <Button fullWidth mt="md" onClick={() => context.closeModal(id)}>
 | 
			
		||||
                Close modal
 | 
			
		||||
            </Button>
 | 
			
		||||
        </>
 | 
			
		||||
    )
 | 
			
		||||
};
 | 
			
		||||
export default CreateProductModal;
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import EnterDeadlineModal from "./EnterDeadlineModal/EnterDeadlineModal.tsx";
 | 
			
		||||
import CreateServiceCategoryModal from "../pages/ServicesPage/modals/CreateServiceCategoryModal.tsx";
 | 
			
		||||
import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.tsx";
 | 
			
		||||
import createProductModal from "./CreateProductModal/CreateProductModal.tsx";
 | 
			
		||||
import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx";
 | 
			
		||||
 | 
			
		||||
export const modals = {
 | 
			
		||||
    enterDeadline: EnterDeadlineModal,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import React, {FC, useEffect, useState} from "react";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import styles from './LeadsPage.module.css';
 | 
			
		||||
import Board from "../../../components/Dnd/Board/Board.tsx";
 | 
			
		||||
import {DragDropContext} from "@hello-pangea/dnd";
 | 
			
		||||
 
 | 
			
		||||
@@ -39,8 +39,8 @@ const LoginPage = () => {
 | 
			
		||||
                        },
 | 
			
		||||
                        (data: TelegramUser) => {
 | 
			
		||||
                            AuthService.loginAuthLoginPost({requestBody: data})
 | 
			
		||||
                                .then(({access_token}) => {
 | 
			
		||||
                                    dispatch(login({accessToken: access_token}));
 | 
			
		||||
                                .then(({accessToken}) => {
 | 
			
		||||
                                    dispatch(login({accessToken: accessToken}));
 | 
			
		||||
                                    navigate({to: "/"}).then(() => {
 | 
			
		||||
                                        notifications.success({message: "Вы успешно вошли!"})
 | 
			
		||||
                                    })
 | 
			
		||||
 
 | 
			
		||||
@@ -10,5 +10,4 @@
 | 
			
		||||
.container {
 | 
			
		||||
    padding: rem(20);
 | 
			
		||||
    display: flex;
 | 
			
		||||
    //min-height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,20 +14,17 @@ const PageWrapper: FC<Props> = ({children}) => {
 | 
			
		||||
        <AppShell
 | 
			
		||||
            layout={"alt"}
 | 
			
		||||
            navbar={{width: rem('80px'), breakpoint: "sm"}}
 | 
			
		||||
            // header={{height:rem(60)}}
 | 
			
		||||
        >
 | 
			
		||||
            {/*<AppShell.Header>*/}
 | 
			
		||||
            {/*    <Header/>*/}
 | 
			
		||||
            {/*</AppShell.Header>*/}
 | 
			
		||||
 | 
			
		||||
            <AppShell.Navbar>
 | 
			
		||||
                {authState.isAuthorized &&
 | 
			
		||||
                    <Navbar/>
 | 
			
		||||
                }
 | 
			
		||||
            </AppShell.Navbar>
 | 
			
		||||
            <AppShell.Main className={styles['main-container']}>
 | 
			
		||||
                <div className={styles['container']}>
 | 
			
		||||
                    {children}
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            </AppShell.Main>
 | 
			
		||||
        </AppShell>
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,54 @@
 | 
			
		||||
import {ProductSchema} from "../../../../client";
 | 
			
		||||
import {FC, RefObject} from "react";
 | 
			
		||||
import {BaseTable, BaseTableRef} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import {MRT_TableOptions} from "mantine-react-table";
 | 
			
		||||
import {useProductsTableColumns} from "./columns.tsx";
 | 
			
		||||
import {ActionIcon, Flex, Tooltip} from "@mantine/core";
 | 
			
		||||
import {IconEdit, IconTrash} from "@tabler/icons-react";
 | 
			
		||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    products: ProductSchema[];
 | 
			
		||||
    tableRef?: RefObject<BaseTableRef<ProductSchema>>
 | 
			
		||||
}
 | 
			
		||||
const ProductsTable: FC<Props> = ({products, tableRef}) => {
 | 
			
		||||
 | 
			
		||||
const ProductsTable: FC<CRUDTableProps<ProductSchema>> = ({items, onDelete, onChange, tableRef}) => {
 | 
			
		||||
    const columns = useProductsTableColumns();
 | 
			
		||||
    const onEditClick = (product: ProductSchema) => {
 | 
			
		||||
        if (!onChange) return;
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: "createProduct",
 | 
			
		||||
            title: 'Создание товара',
 | 
			
		||||
            withCloseButton: false,
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                onChange: (newProduct) => onChange(newProduct),
 | 
			
		||||
                product: product,
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseTable
 | 
			
		||||
            ref={tableRef}
 | 
			
		||||
                data={products}
 | 
			
		||||
            data={items}
 | 
			
		||||
            columns={columns}
 | 
			
		||||
            restProps={{
 | 
			
		||||
                enableColumnActions: false,
 | 
			
		||||
                enableRowActions: true,
 | 
			
		||||
                renderRowActions: ({row}) => (
 | 
			
		||||
                    <Flex gap="md">
 | 
			
		||||
                        <Tooltip label="Редактировать">
 | 
			
		||||
                            <ActionIcon
 | 
			
		||||
                                onClick={() => onEditClick(row.original)}
 | 
			
		||||
                                variant={"default"}>
 | 
			
		||||
                                <IconEdit/>
 | 
			
		||||
                            </ActionIcon>
 | 
			
		||||
                        </Tooltip>
 | 
			
		||||
                        <Tooltip label="Удалить">
 | 
			
		||||
                            <ActionIcon onClick={() => {
 | 
			
		||||
                                if (onDelete) onDelete(row.original);
 | 
			
		||||
                            }} variant={"default"}>
 | 
			
		||||
                                <IconTrash/>
 | 
			
		||||
                            </ActionIcon>
 | 
			
		||||
                        </Tooltip>
 | 
			
		||||
                    </Flex>
 | 
			
		||||
                )
 | 
			
		||||
            } as MRT_TableOptions<ProductSchema>}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import {useMemo} from "react";
 | 
			
		||||
import {MRT_ColumnDef} from "mantine-react-table";
 | 
			
		||||
import {ProductSchema} from "../../../../client";
 | 
			
		||||
import {List, Spoiler, useMantineTheme} from "@mantine/core";
 | 
			
		||||
 | 
			
		||||
export const useProductsTableColumns = () => {
 | 
			
		||||
    const theme = useMantineTheme();
 | 
			
		||||
    return useMemo<MRT_ColumnDef<ProductSchema>[]>(() => [
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "article",
 | 
			
		||||
@@ -13,8 +15,27 @@ export const useProductsTableColumns = () => {
 | 
			
		||||
            accessorKey: "name",
 | 
			
		||||
            header: "Название",
 | 
			
		||||
            enableSorting: false,
 | 
			
		||||
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "barcodes",
 | 
			
		||||
            header: "Штрихкоды",
 | 
			
		||||
            Cell: ({cell}) => {
 | 
			
		||||
                return (
 | 
			
		||||
                    <List size={"sm"}>
 | 
			
		||||
                        <Spoiler maxHeight={parseFloat(theme.lineHeights.sm) * 25}
 | 
			
		||||
                                 showLabel={"Показать все"}
 | 
			
		||||
                                 hideLabel={"Скрыть"}>
 | 
			
		||||
                            {cell.getValue<string[]>().map(barcode => (
 | 
			
		||||
                                <List.Item key={barcode}>
 | 
			
		||||
                                    {barcode}
 | 
			
		||||
                                </List.Item>
 | 
			
		||||
                            ))}
 | 
			
		||||
                        </Spoiler>
 | 
			
		||||
 | 
			
		||||
                    </List>
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ], []);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -8,12 +8,12 @@ type Props = {
 | 
			
		||||
}
 | 
			
		||||
const useServicesList = (props: Props) => {
 | 
			
		||||
    const {clientId, page, itemsPerPage} = props;
 | 
			
		||||
    const {isPending, error, data, refetch} = useQuery({
 | 
			
		||||
    const {data, refetch} = useQuery({
 | 
			
		||||
        queryKey: ['getAllServices', clientId, page, itemsPerPage],
 | 
			
		||||
        queryFn: () => ProductService.getProductsByClientId({clientId, page, itemsPerPage})
 | 
			
		||||
    });
 | 
			
		||||
    const products = isPending || error || !data ? [] : data.products;
 | 
			
		||||
    const paginationInfo = data?.pagination_info;
 | 
			
		||||
    const products = !data ? [] : data.products;
 | 
			
		||||
    const paginationInfo = data?.paginationInfo;
 | 
			
		||||
    return {products, paginationInfo, refetch}
 | 
			
		||||
}
 | 
			
		||||
export default useServicesList;
 | 
			
		||||
@@ -0,0 +1,97 @@
 | 
			
		||||
import {ContextModalProps} from "@mantine/modals";
 | 
			
		||||
import {Button, Flex, rem, TagsInput, TextInput} from "@mantine/core";
 | 
			
		||||
import {useForm} from "@mantine/form";
 | 
			
		||||
import {BaseProduct, CreateProductRequest} from "../../types.ts";
 | 
			
		||||
import {ProductSchema} from "../../../../client";
 | 
			
		||||
 | 
			
		||||
type CreateProps = {
 | 
			
		||||
    clientId: number;
 | 
			
		||||
    onCreate: (values: CreateProductRequest) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EditProps = {
 | 
			
		||||
    product: ProductSchema,
 | 
			
		||||
    onChange: (values: ProductSchema) => void
 | 
			
		||||
}
 | 
			
		||||
type Props = CreateProps | EditProps;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const CreateProductModal = ({
 | 
			
		||||
                                context,
 | 
			
		||||
                                id,
 | 
			
		||||
                                innerProps,
 | 
			
		||||
                            }: ContextModalProps<Props>) => {
 | 
			
		||||
    const isEditProps = 'product' in innerProps;
 | 
			
		||||
    const isCreatingProps = 'clientId' in innerProps;
 | 
			
		||||
    const initialValues = isEditProps ? {
 | 
			
		||||
        name: innerProps.product.name,
 | 
			
		||||
        article: innerProps.product.article,
 | 
			
		||||
        barcodes: innerProps.product.barcodes
 | 
			
		||||
    } : {
 | 
			
		||||
        name: '',
 | 
			
		||||
        article: '',
 | 
			
		||||
        barcodes: []
 | 
			
		||||
    };
 | 
			
		||||
    const form = useForm({
 | 
			
		||||
        initialValues: initialValues,
 | 
			
		||||
        validate: {
 | 
			
		||||
            name: (name) => name.trim() !== '' ? null : "Необходимо ввести название товара",
 | 
			
		||||
            article: (article) => article.trim() !== '' ? null : "Необходимо ввести артикул",
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    const onCancelClick = () => {
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const onSubmit = (values: BaseProduct) => {
 | 
			
		||||
        if (isEditProps) innerProps.onChange({...innerProps.product, ...values})
 | 
			
		||||
        if (isCreatingProps) {
 | 
			
		||||
            innerProps.onCreate({...values, clientId: innerProps.clientId});
 | 
			
		||||
            form.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <form onSubmit={form.onSubmit((values) => onSubmit(values))}>
 | 
			
		||||
                <Flex gap={rem(10)} direction={"column"}>
 | 
			
		||||
                    <TextInput
 | 
			
		||||
                        placeholder={"Введите название товара"}
 | 
			
		||||
                        label={"Название товара"}
 | 
			
		||||
                        {...form.getInputProps('name')}
 | 
			
		||||
                    />
 | 
			
		||||
                    <TextInput
 | 
			
		||||
                        placeholder={"Введите артикул"}
 | 
			
		||||
                        label={"Артикул"}
 | 
			
		||||
                        {...form.getInputProps('article')}
 | 
			
		||||
                    />
 | 
			
		||||
                    <TagsInput
 | 
			
		||||
                        placeholder={!form.values.barcodes.length ? "Добавьте штрихкоды к товару" : ""}
 | 
			
		||||
                        label={"Штрихкоды"}
 | 
			
		||||
                        {...form.getInputProps('barcodes')}
 | 
			
		||||
                    />
 | 
			
		||||
                    <Flex justify={"flex-end"} mt={rem(5)} gap={rem(10)}>
 | 
			
		||||
                        <Button onClick={() => onCancelClick()} variant={"subtle"}>Отменить</Button>
 | 
			
		||||
                        {isEditProps ?
 | 
			
		||||
                            <Button
 | 
			
		||||
                                onClick={() => context.closeContextModal(id)}
 | 
			
		||||
                                type={"submit"}
 | 
			
		||||
                                variant={"default"}
 | 
			
		||||
                            >Сохранить и закрыть</Button> :
 | 
			
		||||
                            <>
 | 
			
		||||
                                <Button
 | 
			
		||||
                                    onClick={() => context.closeContextModal(id)}
 | 
			
		||||
                                    type={"submit"}
 | 
			
		||||
                                    variant={"default"}
 | 
			
		||||
                                >Создать и закрыть</Button>
 | 
			
		||||
                                <Button
 | 
			
		||||
                                    type={"submit"}
 | 
			
		||||
                                    variant={"default"}
 | 
			
		||||
                                >Создать</Button>
 | 
			
		||||
                            </>}
 | 
			
		||||
                    </Flex>
 | 
			
		||||
                </Flex>
 | 
			
		||||
            </form>
 | 
			
		||||
        </>
 | 
			
		||||
    )
 | 
			
		||||
};
 | 
			
		||||
export default CreateProductModal;
 | 
			
		||||
							
								
								
									
										6
									
								
								src/pages/ProductsPage/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/pages/ProductsPage/types.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
export type BaseProduct = {
 | 
			
		||||
    name: string;
 | 
			
		||||
    article: string;
 | 
			
		||||
    barcodes: string[];
 | 
			
		||||
}
 | 
			
		||||
export type CreateProductRequest = BaseProduct & { clientId: number }
 | 
			
		||||
@@ -1,37 +1,83 @@
 | 
			
		||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import styles from './ProductsPage.module.css';
 | 
			
		||||
import {Button, Drawer, Pagination} from "@mantine/core";
 | 
			
		||||
import {useDisclosure, usePagination} from "@mantine/hooks";
 | 
			
		||||
import {Button, Text, Pagination} from "@mantine/core";
 | 
			
		||||
import ClientSelect from "../../../components/Selects/ClientSelect/ClientSelect.tsx";
 | 
			
		||||
import ProductsTable from "../components/ProductsTable/ProductsTable.tsx";
 | 
			
		||||
import useProductsList from "../hooks/useProductsList.tsx";
 | 
			
		||||
import {notifications} from "../../../shared/lib/notifications.ts";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
import {notifications} from "../../../shared/lib/notifications.ts";
 | 
			
		||||
import {CreateProductRequest} from "../types.ts";
 | 
			
		||||
import {ProductSchema, ProductService} from "../../../client";
 | 
			
		||||
 | 
			
		||||
export const ProductsPage: FC = () => {
 | 
			
		||||
    // const [opened, {open, close}] = useDisclosure(false);
 | 
			
		||||
    const [clientId, setClientId] = useState(-1);
 | 
			
		||||
    const [totalPages, setTotalPages] = useState(1);
 | 
			
		||||
    const pagination = usePagination({total: totalPages});
 | 
			
		||||
    const {products, paginationInfo} = useProductsList({
 | 
			
		||||
    const [currentPage, setCurrentPage] = useState(1);
 | 
			
		||||
 | 
			
		||||
    const {products, paginationInfo, refetch} = useProductsList({
 | 
			
		||||
        clientId,
 | 
			
		||||
        page: pagination.active - 1,
 | 
			
		||||
        page: currentPage - 1,
 | 
			
		||||
        itemsPerPage: 10
 | 
			
		||||
    });
 | 
			
		||||
    const onProductCreate = (request: CreateProductRequest) => {
 | 
			
		||||
        ProductService.createProduct({requestBody: request})
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message: message});
 | 
			
		||||
                if (!ok) return;
 | 
			
		||||
                await refetch();
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const onProductChange = (product: ProductSchema) => {
 | 
			
		||||
        ProductService.updateProduct({requestBody: {product}})
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message});
 | 
			
		||||
                if (!ok) return;
 | 
			
		||||
                await refetch();
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const onCreateProductClick = () => {
 | 
			
		||||
        if (clientId < 0) {
 | 
			
		||||
            notifications.error({message: "Необходимо выбрать клиента"});
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: "createProduct",
 | 
			
		||||
            title: 'Создание категории',
 | 
			
		||||
            title: 'Создание товара',
 | 
			
		||||
            withCloseButton: false,
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                clientId
 | 
			
		||||
                clientId,
 | 
			
		||||
                onCreate: onProductCreate
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const onDeleteClick = (product: ProductSchema) => {
 | 
			
		||||
        modals.openConfirmModal({
 | 
			
		||||
            title: 'Удаление товара',
 | 
			
		||||
            centered: true,
 | 
			
		||||
            children: (
 | 
			
		||||
                <Text size="sm">
 | 
			
		||||
                    Вы уверены что хотите удалить товар {product.name}
 | 
			
		||||
                </Text>
 | 
			
		||||
            ),
 | 
			
		||||
            labels: {confirm: 'Да', cancel: "Нет"},
 | 
			
		||||
            confirmProps: {color: 'red'},
 | 
			
		||||
            onConfirm: () =>
 | 
			
		||||
                ProductService.deleteProduct({requestBody: {productId: product.id}})
 | 
			
		||||
                    .then(async ({ok, message}) => {
 | 
			
		||||
                        notifications.guess(ok, {message: message});
 | 
			
		||||
                        if (!ok) return;
 | 
			
		||||
                        await refetch();
 | 
			
		||||
                    })
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!paginationInfo) return;
 | 
			
		||||
        setTotalPages(paginationInfo.total_pages);
 | 
			
		||||
        setTotalPages(paginationInfo.totalPages);
 | 
			
		||||
    }, [paginationInfo]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -50,8 +96,18 @@ export const ProductsPage: FC = () => {
 | 
			
		||||
                <PageBlock>
 | 
			
		||||
                    <div className={styles['body-container']}>
 | 
			
		||||
                        <div className={styles['table-container']}>
 | 
			
		||||
                            <ProductsTable products={products}/>
 | 
			
		||||
                            <Pagination className={styles['table-pagination']} total={100}/>
 | 
			
		||||
                            <ProductsTable
 | 
			
		||||
                                onChange={onProductChange}
 | 
			
		||||
                                onDelete={onDeleteClick}
 | 
			
		||||
                                items={products}
 | 
			
		||||
                            />
 | 
			
		||||
                            <Pagination
 | 
			
		||||
                                className={styles['table-pagination']}
 | 
			
		||||
                                withEdges
 | 
			
		||||
                                onChange={event => setCurrentPage(event)}
 | 
			
		||||
                                total={totalPages}
 | 
			
		||||
                                value={currentPage}
 | 
			
		||||
                            />
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </PageBlock>
 | 
			
		||||
 
 | 
			
		||||
@@ -26,10 +26,10 @@ export const ServicesPage: FC = () => {
 | 
			
		||||
    }
 | 
			
		||||
    const onCreate = (values: ServiceSchema) => {
 | 
			
		||||
        ServiceService.createService({requestBody: {service: values}})
 | 
			
		||||
            .then(({ok, message}) => {
 | 
			
		||||
            .then(async ({ok, message}) => {
 | 
			
		||||
                notifications.guess(ok, {message: message});
 | 
			
		||||
                if (!ok) return;
 | 
			
		||||
                refetch();
 | 
			
		||||
                await refetch();
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
    const onCreateCategoryClick = () => {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/types/CRUDTable.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/types/CRUDTable.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
import {RefObject} from "react";
 | 
			
		||||
import {BaseTableRef} from "../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import {MRT_RowData} from "mantine-react-table";
 | 
			
		||||
 | 
			
		||||
export interface CRUDTableProps<T extends MRT_RowData> {
 | 
			
		||||
    items: T[];
 | 
			
		||||
    onCreate?: (item: T) => void;
 | 
			
		||||
    onDelete?: (item: T) => void;
 | 
			
		||||
    onChange?: (item: T) => void;
 | 
			
		||||
    tableRef?: RefObject<BaseTableRef<T>>
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
export type QuickDeal = {
 | 
			
		||||
    name: string
 | 
			
		||||
    client_name: string
 | 
			
		||||
    client_address: string
 | 
			
		||||
    clientName: string
 | 
			
		||||
    clientAddress: string
 | 
			
		||||
    comment:string
 | 
			
		||||
    acceptance_date: Date
 | 
			
		||||
    acceptanceDate: Date
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user