othr
This commit is contained in:
		@@ -31,6 +31,7 @@ export type { DealDeleteServiceResponse } from './models/DealDeleteServiceRespon
 | 
			
		||||
export type { DealDeleteServicesRequest } from './models/DealDeleteServicesRequest';
 | 
			
		||||
export type { DealDeleteServicesResponse } from './models/DealDeleteServicesResponse';
 | 
			
		||||
export type { DealGetAllResponse } from './models/DealGetAllResponse';
 | 
			
		||||
export type { DealProductSchema } from './models/DealProductSchema';
 | 
			
		||||
export type { DealQuickCreateRequest } from './models/DealQuickCreateRequest';
 | 
			
		||||
export type { DealQuickCreateResponse } from './models/DealQuickCreateResponse';
 | 
			
		||||
export type { DealSchema } from './models/DealSchema';
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/client/models/DealProductSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/DealProductSchema.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ProductSchema } from './ProductSchema';
 | 
			
		||||
export type DealProductSchema = {
 | 
			
		||||
    product: ProductSchema;
 | 
			
		||||
    quantity: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { DealProductSchema } from './DealProductSchema';
 | 
			
		||||
import type { DealServiceSchema } from './DealServiceSchema';
 | 
			
		||||
export type DealSchema = {
 | 
			
		||||
    id: number;
 | 
			
		||||
@@ -10,5 +11,6 @@ export type DealSchema = {
 | 
			
		||||
    createdAt: string;
 | 
			
		||||
    currentStatus: number;
 | 
			
		||||
    services: Array<DealServiceSchema>;
 | 
			
		||||
    products: Array<DealProductSchema>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -84,8 +84,8 @@ export class ProductService {
 | 
			
		||||
        itemsPerPage,
 | 
			
		||||
    }: {
 | 
			
		||||
        clientId: number,
 | 
			
		||||
        page: number,
 | 
			
		||||
        itemsPerPage: number,
 | 
			
		||||
        page?: (number | null),
 | 
			
		||||
        itemsPerPage?: (number | null),
 | 
			
		||||
    }): CancelablePromise<ProductGetResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								src/components/ProductSelect/ProductSelect.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/components/ProductSelect/ProductSelect.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
import {ProductSchema} from "../../client";
 | 
			
		||||
import {Select, SelectProps} from "@mantine/core";
 | 
			
		||||
import {FC, useEffect, useMemo, useState} from "react";
 | 
			
		||||
import useProductsList from "../../pages/ProductsPage/hooks/useProductsList.tsx";
 | 
			
		||||
 | 
			
		||||
type ControlledValueProps = {
 | 
			
		||||
    value: ProductSchema;
 | 
			
		||||
    onChange: (value: ProductSchema) => void;
 | 
			
		||||
}
 | 
			
		||||
type RestProps = {
 | 
			
		||||
    defaultValue?: ProductSchema;
 | 
			
		||||
    onChange: (value: ProductSchema) => void;
 | 
			
		||||
    clientId: number;
 | 
			
		||||
}
 | 
			
		||||
type Props = (RestProps & Partial<ControlledValueProps>) & Omit<SelectProps, 'value' | 'onChange'>;
 | 
			
		||||
 | 
			
		||||
const ProductSelect: FC<Props> = (props) => {
 | 
			
		||||
    const isControlled = 'value' in props;
 | 
			
		||||
    const [intertalValue, setInternalValue] = useState<ProductSchema | undefined>(props.defaultValue);
 | 
			
		||||
    const value = isControlled ? props.value : intertalValue
 | 
			
		||||
 | 
			
		||||
    const {products} = useProductsList({clientId: props.clientId});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    const data = useMemo(() => products.reduce((acc, product) => {
 | 
			
		||||
        acc.push({
 | 
			
		||||
            label: product.name,
 | 
			
		||||
            value: product.id.toString()
 | 
			
		||||
        });
 | 
			
		||||
        return acc;
 | 
			
		||||
    }, [] as { label: string, value: string }[]), [products]);
 | 
			
		||||
 | 
			
		||||
    const handleOnChange = (event: string | null) => {
 | 
			
		||||
        if (!event) return;
 | 
			
		||||
        const product = products.find(product => parseInt(event) == product.id);
 | 
			
		||||
        if (!product) return;
 | 
			
		||||
        if (isControlled) {
 | 
			
		||||
            props.onChange(product);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        setInternalValue(product);
 | 
			
		||||
    }
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (isControlled || !intertalValue) return;
 | 
			
		||||
        props.onChange(intertalValue);
 | 
			
		||||
    }, [intertalValue]);
 | 
			
		||||
    return (
 | 
			
		||||
        <Select
 | 
			
		||||
            {...props}
 | 
			
		||||
            withCheckIcon={false}
 | 
			
		||||
            searchable
 | 
			
		||||
            value={value?.id.toString()}
 | 
			
		||||
            onChange={handleOnChange}
 | 
			
		||||
            data={data}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
export default ProductSelect;
 | 
			
		||||
@@ -4,6 +4,7 @@ import CreateServiceModal from "../pages/ServicesPage/modals/CreateServiceModal.
 | 
			
		||||
import createProductModal from "../pages/ProductsPage/modals/CreateProductModal/CreateProductModal.tsx";
 | 
			
		||||
import ProductFormModal from "../pages/ClientsPage/modals/ClientFormModal/ClientFormModal.tsx";
 | 
			
		||||
import AddDealServiceModal from "../pages/LeadsPage/modals/AddDealServiceModal.tsx";
 | 
			
		||||
import AddDealProductModal from "../pages/LeadsPage/modals/AddDealProductModal.tsx";
 | 
			
		||||
 | 
			
		||||
export const modals = {
 | 
			
		||||
    enterDeadline: EnterDeadlineModal,
 | 
			
		||||
@@ -11,5 +12,6 @@ export const modals = {
 | 
			
		||||
    createService: CreateServiceModal,
 | 
			
		||||
    createProduct: createProductModal,
 | 
			
		||||
    productFormModal: ProductFormModal,
 | 
			
		||||
    addDealService: AddDealServiceModal
 | 
			
		||||
    addDealService: AddDealServiceModal,
 | 
			
		||||
    addDealProduct: AddDealProductModal
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import useDealProductsTableColumns from "./columns.tsx";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
			
		||||
import {DealProductSchema} from "../../../../client";
 | 
			
		||||
import {Button, Flex, rem} from "@mantine/core";
 | 
			
		||||
import {MRT_TableOptions} from "mantine-react-table";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
 | 
			
		||||
type RestProps = {
 | 
			
		||||
    clientId: number;
 | 
			
		||||
}
 | 
			
		||||
type Props = CRUDTableProps<DealProductSchema> & RestProps;
 | 
			
		||||
const DealProductsTable: FC<Props> = ({items, clientId}) => {
 | 
			
		||||
    const columns = useDealProductsTableColumns();
 | 
			
		||||
    const onCreateClick = () => {
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: "addDealProduct",
 | 
			
		||||
            title: "Добавление товара",
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                onCreate: event => console.log(event),
 | 
			
		||||
                clientId
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseTable
 | 
			
		||||
            data={items}
 | 
			
		||||
            columns={columns}
 | 
			
		||||
            restProps={{
 | 
			
		||||
                renderBottomToolbar: ({}) => (
 | 
			
		||||
                    <Flex justify={"flex-end"} gap={rem(10)} p={rem(10)}>
 | 
			
		||||
                        {/*{(onMultipleDelete && table.getSelectedRowModel().rows.length > 0) && (*/}
 | 
			
		||||
                        {/*    <Button*/}
 | 
			
		||||
                        {/*        onClick={() => {*/}
 | 
			
		||||
                        {/*            onMultipleDelete(table.getSelectedRowModel().rows.map(row => row.original))*/}
 | 
			
		||||
                        {/*        }}*/}
 | 
			
		||||
                        {/*        variant={"filled"}*/}
 | 
			
		||||
                        {/*        color={"red"}*/}
 | 
			
		||||
                        {/*    >*/}
 | 
			
		||||
                        {/*        Удалить выбранные*/}
 | 
			
		||||
                        {/*    </Button>*/}
 | 
			
		||||
                        {/*)}*/}
 | 
			
		||||
                        <Button onClick={onCreateClick} variant={"default"}>
 | 
			
		||||
                            Добавить услугу
 | 
			
		||||
                        </Button>
 | 
			
		||||
 | 
			
		||||
                    </Flex>
 | 
			
		||||
                ),
 | 
			
		||||
            } as MRT_TableOptions<DealProductSchema>}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default DealProductsTable;
 | 
			
		||||
							
								
								
									
										22
									
								
								src/pages/LeadsPage/components/DealProductsTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/pages/LeadsPage/components/DealProductsTable/columns.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
import {useMemo} from "react";
 | 
			
		||||
import {MRT_ColumnDef} from "mantine-react-table";
 | 
			
		||||
import {DealProductSchema} from "../../../../client";
 | 
			
		||||
 | 
			
		||||
const useDealProductsTableColumns = () => {
 | 
			
		||||
    return useMemo<MRT_ColumnDef<DealProductSchema>[]>(() => [
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "products.name",
 | 
			
		||||
            header: "Название"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "products.article",
 | 
			
		||||
            header: "Артикул"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "quantity",
 | 
			
		||||
            header: "Количество"
 | 
			
		||||
        }
 | 
			
		||||
    ], [])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default useDealProductsTableColumns;
 | 
			
		||||
@@ -4,7 +4,7 @@ import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import {DealServiceSchema} from "../../../../client";
 | 
			
		||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
			
		||||
import {MRT_TableOptions} from "mantine-react-table";
 | 
			
		||||
import {ActionIcon, Box, Button, Flex, rem, Tooltip} from "@mantine/core";
 | 
			
		||||
import {ActionIcon, Button, Flex, rem, Tooltip} from "@mantine/core";
 | 
			
		||||
import {openContextModal} from "@mantine/modals";
 | 
			
		||||
import {IconTrash} from "@tabler/icons-react";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import {DealService, DealServiceSchema} from "../../../../client";
 | 
			
		||||
import {notifications} from "../../../../shared/lib/notifications.ts";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
import {BaseTableRef} from "../../../../components/BaseTable/BaseTable.tsx";
 | 
			
		||||
import DealProductsTable from "../../components/DealProductsTable/DealProductsTable.tsx";
 | 
			
		||||
 | 
			
		||||
const useDealServicesTableState = () => {
 | 
			
		||||
    const {selectedDeal, setSelectedDeal} = useDealPageContext();
 | 
			
		||||
@@ -130,7 +131,6 @@ const useDealServicesTableState = () => {
 | 
			
		||||
        services: selectedDeal?.services || []
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DealEditDrawerServicesTable = () => {
 | 
			
		||||
    const {
 | 
			
		||||
        services,
 | 
			
		||||
@@ -150,6 +150,29 @@ const DealEditDrawerServicesTable = () => {
 | 
			
		||||
        onMultipleDelete={onsServiceMultipleDelete}
 | 
			
		||||
    />)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const useDealProductTableState = () => {
 | 
			
		||||
    const {selectedDeal} = useDealPageContext();
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        clientId: selectedDeal?.clientId || -1,
 | 
			
		||||
        products: selectedDeal?.products || []
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DealEditDrawerProductsTable = () => {
 | 
			
		||||
    const {
 | 
			
		||||
        products,
 | 
			
		||||
        clientId
 | 
			
		||||
    } = useDealProductTableState();
 | 
			
		||||
    return (
 | 
			
		||||
        <DealProductsTable
 | 
			
		||||
            clientId={clientId}
 | 
			
		||||
            items={products}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const useDealEditDrawerState = () => {
 | 
			
		||||
    const {selectedDeal, setSelectedDeal} = useDealPageContext();
 | 
			
		||||
    return {
 | 
			
		||||
@@ -168,6 +191,7 @@ const DealEditDrawer: FC = () => {
 | 
			
		||||
            onClose={onClose}
 | 
			
		||||
            opened={isVisible}>
 | 
			
		||||
            <DealEditDrawerServicesTable/>
 | 
			
		||||
            <DealEditDrawerProductsTable/>
 | 
			
		||||
        </Drawer>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								src/pages/LeadsPage/modals/AddDealProductModal.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/pages/LeadsPage/modals/AddDealProductModal.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
import {ContextModalProps} from "@mantine/modals";
 | 
			
		||||
import BaseFormModal, {CreateEditFormProps} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
			
		||||
import {DealProductSchema} from "../../../client";
 | 
			
		||||
import {useForm} from "@mantine/form";
 | 
			
		||||
import {NumberInput} from "@mantine/core";
 | 
			
		||||
import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
 | 
			
		||||
 | 
			
		||||
type RestProps = {
 | 
			
		||||
    clientId: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Props = CreateEditFormProps<Partial<DealProductSchema>> & RestProps;
 | 
			
		||||
const AddDealProductModal = ({
 | 
			
		||||
                                 context,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 innerProps
 | 
			
		||||
                             }: ContextModalProps<Props>) => {
 | 
			
		||||
    const form = useForm<Partial<DealProductSchema>>({
 | 
			
		||||
        initialValues: {
 | 
			
		||||
            product: undefined,
 | 
			
		||||
            quantity: 0
 | 
			
		||||
        },
 | 
			
		||||
        validate: {
 | 
			
		||||
            product: (product?: DealProductSchema['product']) => product !== undefined ? null : "Необходимо выбрать товар",
 | 
			
		||||
            quantity: (quantity?: number) => (quantity && quantity > 0) ? null : "Количество должно быть больше 0"
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    const onClose = () => {
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseFormModal
 | 
			
		||||
            {...innerProps}
 | 
			
		||||
            form={form}
 | 
			
		||||
            closeOnSubmit
 | 
			
		||||
            onClose={onClose}>
 | 
			
		||||
            <BaseFormModal.Body>
 | 
			
		||||
                <>
 | 
			
		||||
                    <ProductSelect
 | 
			
		||||
                        placeholder={"Выберите услугу"}
 | 
			
		||||
                        label={"Услуга"}
 | 
			
		||||
                        clientId={innerProps.clientId}
 | 
			
		||||
                        {...form.getInputProps('service')}
 | 
			
		||||
                    />
 | 
			
		||||
                    <NumberInput
 | 
			
		||||
                        placeholder={"Введите количество"}
 | 
			
		||||
                        label={"Количество"}
 | 
			
		||||
                        min={1}
 | 
			
		||||
                        {...form.getInputProps('quantity')}
 | 
			
		||||
                    />
 | 
			
		||||
                </>
 | 
			
		||||
 | 
			
		||||
            </BaseFormModal.Body>
 | 
			
		||||
        </BaseFormModal>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default AddDealProductModal;
 | 
			
		||||
@@ -13,7 +13,10 @@ const PageWrapper: FC<Props> = ({children}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <AppShell
 | 
			
		||||
            layout={"alt"}
 | 
			
		||||
            navbar={{width: '5%', breakpoint: "sm"}}
 | 
			
		||||
            navbar={{
 | 
			
		||||
                width: '5%',
 | 
			
		||||
                breakpoint: "sm"
 | 
			
		||||
            }}
 | 
			
		||||
        >
 | 
			
		||||
 | 
			
		||||
            <AppShell.Navbar>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,8 @@ import {ProductService} from "../../../client";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    clientId: number,
 | 
			
		||||
    page: number,
 | 
			
		||||
    itemsPerPage: number,
 | 
			
		||||
    page?: number,
 | 
			
		||||
    itemsPerPage?: number,
 | 
			
		||||
}
 | 
			
		||||
const useProductsList = (props: Props) => {
 | 
			
		||||
    const {clientId, page, itemsPerPage} = props;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,15 @@
 | 
			
		||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import styles from './ProductsPage.module.css';
 | 
			
		||||
import {Button, Text, Pagination} from "@mantine/core";
 | 
			
		||||
import {Button, Pagination, Text} from "@mantine/core";
 | 
			
		||||
import ClientSelect from "../../../components/Selects/ClientSelect/ClientSelect.tsx";
 | 
			
		||||
import ProductsTable from "../components/ProductsTable/ProductsTable.tsx";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
import {notifications} from "../../../shared/lib/notifications.ts";
 | 
			
		||||
import {CreateProductRequest} from "../types.ts";
 | 
			
		||||
import {ProductSchema, ProductService} from "../../../client";
 | 
			
		||||
import ServiceSelect from "../../../components/ServiceSelect/ServiceSelect.tsx";
 | 
			
		||||
import useProductsList from "../hooks/useProductsList.tsx";
 | 
			
		||||
import useServicesList from "../../ServicesPage/hooks/useServicesList.tsx";
 | 
			
		||||
import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
 | 
			
		||||
 | 
			
		||||
export const ProductsPage: FC = () => {
 | 
			
		||||
    const [clientId, setClientId] = useState(-1);
 | 
			
		||||
@@ -91,9 +90,11 @@ export const ProductsPage: FC = () => {
 | 
			
		||||
                            onClick={() => onCreateProductClick()}
 | 
			
		||||
                            variant={"default"}
 | 
			
		||||
                        >Создать</Button>
 | 
			
		||||
                        {/*<ServiceSelect*/}
 | 
			
		||||
                        {/*    value={selectedService}*/}
 | 
			
		||||
                        {/*    onChange={setSelectedService}/>*/}
 | 
			
		||||
                        <ProductSelect
 | 
			
		||||
                            onChange={event => console.log(event)}
 | 
			
		||||
                            clientId={8}
 | 
			
		||||
                            limit={10}
 | 
			
		||||
                        />
 | 
			
		||||
                    </div>
 | 
			
		||||
                </PageBlock>
 | 
			
		||||
                <PageBlock>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user