feat: deal product services
This commit is contained in:
		@@ -70,8 +70,12 @@ export type { DealUpdateGeneralInfoRequest } from './models/DealUpdateGeneralInf
 | 
			
		||||
export type { DealUpdateGeneralInfoResponse } from './models/DealUpdateGeneralInfoResponse';
 | 
			
		||||
export type { DealUpdateProductQuantityRequest } from './models/DealUpdateProductQuantityRequest';
 | 
			
		||||
export type { DealUpdateProductQuantityResponse } from './models/DealUpdateProductQuantityResponse';
 | 
			
		||||
export type { DealUpdateProductRequest } from './models/DealUpdateProductRequest';
 | 
			
		||||
export type { DealUpdateProductResponse } from './models/DealUpdateProductResponse';
 | 
			
		||||
export type { DealUpdateServiceQuantityRequest } from './models/DealUpdateServiceQuantityRequest';
 | 
			
		||||
export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse';
 | 
			
		||||
export type { DealUpdateServiceRequest } from './models/DealUpdateServiceRequest';
 | 
			
		||||
export type { DealUpdateServiceResponse } from './models/DealUpdateServiceResponse';
 | 
			
		||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
			
		||||
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
			
		||||
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
 | 
			
		||||
 
 | 
			
		||||
@@ -6,5 +6,6 @@ export type DealAddServiceRequest = {
 | 
			
		||||
    dealId: number;
 | 
			
		||||
    serviceId: number;
 | 
			
		||||
    quantity: number;
 | 
			
		||||
    price: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/client/models/DealUpdateProductRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/DealUpdateProductRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { DealProductSchema } from './DealProductSchema';
 | 
			
		||||
export type DealUpdateProductRequest = {
 | 
			
		||||
    dealId: number;
 | 
			
		||||
    product: DealProductSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/DealUpdateProductResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealUpdateProductResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type DealUpdateProductResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								src/client/models/DealUpdateServiceRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/client/models/DealUpdateServiceRequest.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { DealServiceSchema } from './DealServiceSchema';
 | 
			
		||||
export type DealUpdateServiceRequest = {
 | 
			
		||||
    dealId: number;
 | 
			
		||||
    service: DealServiceSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/client/models/DealUpdateServiceResponse.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/client/models/DealUpdateServiceResponse.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
/* generated using openapi-typescript-codegen -- do no edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type DealUpdateServiceResponse = {
 | 
			
		||||
    ok: boolean;
 | 
			
		||||
    message: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -31,8 +31,12 @@ import type { DealUpdateGeneralInfoRequest } from '../models/DealUpdateGeneralIn
 | 
			
		||||
import type { DealUpdateGeneralInfoResponse } from '../models/DealUpdateGeneralInfoResponse';
 | 
			
		||||
import type { DealUpdateProductQuantityRequest } from '../models/DealUpdateProductQuantityRequest';
 | 
			
		||||
import type { DealUpdateProductQuantityResponse } from '../models/DealUpdateProductQuantityResponse';
 | 
			
		||||
import type { DealUpdateProductRequest } from '../models/DealUpdateProductRequest';
 | 
			
		||||
import type { DealUpdateProductResponse } from '../models/DealUpdateProductResponse';
 | 
			
		||||
import type { DealUpdateServiceQuantityRequest } from '../models/DealUpdateServiceQuantityRequest';
 | 
			
		||||
import type { DealUpdateServiceQuantityResponse } from '../models/DealUpdateServiceQuantityResponse';
 | 
			
		||||
import type { DealUpdateServiceRequest } from '../models/DealUpdateServiceRequest';
 | 
			
		||||
import type { DealUpdateServiceResponse } from '../models/DealUpdateServiceResponse';
 | 
			
		||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
			
		||||
import { OpenAPI } from '../core/OpenAPI';
 | 
			
		||||
import { request as __request } from '../core/request';
 | 
			
		||||
@@ -241,7 +245,7 @@ export class DealService {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Services Update
 | 
			
		||||
     * Services Update Quantity
 | 
			
		||||
     * @returns DealUpdateServiceQuantityResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
@@ -260,6 +264,26 @@ export class DealService {
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Services Update
 | 
			
		||||
     * @returns DealUpdateServiceResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static updateDealService({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: DealUpdateServiceRequest,
 | 
			
		||||
    }): CancelablePromise<DealUpdateServiceResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/deal/services/update',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Services Delete
 | 
			
		||||
     * @returns DealDeleteServiceResponse Successful Response
 | 
			
		||||
@@ -380,4 +404,24 @@ export class DealService {
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Products Update
 | 
			
		||||
     * @returns DealUpdateProductResponse Successful Response
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public static updateDealProduct({
 | 
			
		||||
        requestBody,
 | 
			
		||||
    }: {
 | 
			
		||||
        requestBody: DealUpdateProductRequest,
 | 
			
		||||
    }): CancelablePromise<DealUpdateProductResponse> {
 | 
			
		||||
        return __request(OpenAPI, {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/deal/product/update',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Validation Error`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,8 @@ const DealSummaryCard: FC<Props> = ({dealSummary}) => {
 | 
			
		||||
        const currentDate = new Date();
 | 
			
		||||
        const diff = deadlineDate.getTime() - currentDate.getTime();
 | 
			
		||||
        const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
 | 
			
		||||
        if (diffDays < 0)
 | 
			
		||||
            return 'grey.8'; // for past deadlines
 | 
			
		||||
        if (diffDays === 1) {
 | 
			
		||||
            return 'yellow.8';
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import {Select, SelectProps} from "@mantine/core";
 | 
			
		||||
import {useEffect, useMemo, useState} from "react";
 | 
			
		||||
import {ObjectWithNameAndId} from "../../types/utils.ts";
 | 
			
		||||
import {groupBy} from "lodash";
 | 
			
		||||
import {groupBy, omit} from "lodash";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export type SelectObjectType<T extends ObjectWithNameAndId> = T;
 | 
			
		||||
@@ -16,6 +16,7 @@ type RestProps<T extends ObjectWithNameAndId> = {
 | 
			
		||||
    onChange: (value: SelectObjectType<T>) => void;
 | 
			
		||||
    data: SelectObjectType<T>[];
 | 
			
		||||
    groupBy?: (item: SelectObjectType<T>) => string;
 | 
			
		||||
    filterBy?: (item: SelectObjectType<T>) => boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ObjectSelectProps<T extends ObjectWithNameAndId> =
 | 
			
		||||
@@ -30,8 +31,10 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
 | 
			
		||||
    const value = isControlled ? props.value : internalValue;
 | 
			
		||||
 | 
			
		||||
    const data = useMemo(() => {
 | 
			
		||||
        const propsData = props.filterBy ? props.data.filter(props.filterBy) : props.data;
 | 
			
		||||
        if (props.groupBy) {
 | 
			
		||||
            const groupedData = groupBy(props.data, props.groupBy);
 | 
			
		||||
 | 
			
		||||
            const groupedData = groupBy(propsData, props.groupBy);
 | 
			
		||||
            return Object.entries(groupedData).map(([group, items]) => ({
 | 
			
		||||
                group,
 | 
			
		||||
                items: items.map(item => ({
 | 
			
		||||
@@ -40,7 +43,7 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
 | 
			
		||||
                }))
 | 
			
		||||
            }));
 | 
			
		||||
        } else {
 | 
			
		||||
            return props.data.map(item => ({
 | 
			
		||||
            return propsData.map(item => ({
 | 
			
		||||
                label: item.name,
 | 
			
		||||
                value: item.id.toString()
 | 
			
		||||
            }));
 | 
			
		||||
@@ -62,10 +65,10 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
 | 
			
		||||
        if (isControlled || !internalValue) return;
 | 
			
		||||
        props.onChange(internalValue);
 | 
			
		||||
    }, [internalValue]);
 | 
			
		||||
 | 
			
		||||
    const restProps = omit(props, ['filterBy', 'groupBy']);
 | 
			
		||||
    return (
 | 
			
		||||
        <Select
 | 
			
		||||
            {...props}
 | 
			
		||||
            {...restProps}
 | 
			
		||||
            value={value?.id.toString()}
 | 
			
		||||
            onChange={handleOnChange}
 | 
			
		||||
            data={data}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
import {ProductSchema} from "../../client";
 | 
			
		||||
import {Select, SelectProps} from "@mantine/core";
 | 
			
		||||
import {FC, useEffect, useMemo, useState} from "react";
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import useProductsList from "../../pages/ProductsPage/hooks/useProductsList.tsx";
 | 
			
		||||
import {omit} from "lodash";
 | 
			
		||||
import ObjectSelect, {ObjectSelectProps} from "../ObjectSelect/ObjectSelect.tsx";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +1,37 @@
 | 
			
		||||
import {ObjectSelectProps} from "../ObjectSelect/ObjectSelect.tsx";
 | 
			
		||||
import {ServiceSchema} from "../../client";
 | 
			
		||||
import {Flex, FlexProps, NumberInput, NumberInputProps, rem} from "@mantine/core";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
import {ActionIcon, Flex, FlexProps, NumberInput, NumberInputProps, rem} from "@mantine/core";
 | 
			
		||||
import {FC, useEffect, useRef, useState} from "react";
 | 
			
		||||
import ServiceSelectNew from "../Selects/ServiceSelectNew/ServiceSelectNew.tsx";
 | 
			
		||||
import {ServiceType} from "../../shared/enums/ServiceType.ts";
 | 
			
		||||
import {IconReload, IconTrash, IconUpload} from "@tabler/icons-react";
 | 
			
		||||
 | 
			
		||||
type ServiceProps = Omit<ObjectSelectProps<ServiceSchema>, 'data'>;
 | 
			
		||||
type PriceProps = NumberInputProps;
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    serviceProps: ServiceProps,
 | 
			
		||||
    priceProps: PriceProps
 | 
			
		||||
    quantity: number;
 | 
			
		||||
    containerProps: FlexProps
 | 
			
		||||
    priceProps: PriceProps,
 | 
			
		||||
    quantity: number,
 | 
			
		||||
    containerProps: FlexProps,
 | 
			
		||||
    filterType?: ServiceType
 | 
			
		||||
}
 | 
			
		||||
const ServiceWithPriceInput: FC<Props> = ({serviceProps, priceProps, quantity, containerProps}) => {
 | 
			
		||||
const ServiceWithPriceInput: FC<Props> = ({
 | 
			
		||||
                                              serviceProps,
 | 
			
		||||
                                              priceProps,
 | 
			
		||||
                                              quantity,
 | 
			
		||||
                                              containerProps,
 | 
			
		||||
                                              filterType = ServiceType.PRODUCT_SERVICE
 | 
			
		||||
                                          }) => {
 | 
			
		||||
    const [price, setPrice] = useState<number | undefined>(
 | 
			
		||||
        typeof priceProps.value === 'number' ? priceProps.value : undefined);
 | 
			
		||||
    const [service, setService] = useState<ServiceSchema | undefined>(serviceProps.value);
 | 
			
		||||
 | 
			
		||||
    const isFirstRender = useRef(true);
 | 
			
		||||
    const setPriceBasedOnQuantity = (): boolean => {
 | 
			
		||||
        if (!service || !service.priceRanges.length) return false;
 | 
			
		||||
        const range = service.priceRanges.find(priceRange =>
 | 
			
		||||
            quantity >= priceRange.fromQuantity && quantity <= priceRange.toQuantity) || service.priceRanges[0];
 | 
			
		||||
 | 
			
		||||
        setPrice(range.price);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
@@ -38,34 +48,56 @@ const ServiceWithPriceInput: FC<Props> = ({serviceProps, priceProps, quantity, c
 | 
			
		||||
        setPrice(value);
 | 
			
		||||
    }
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (isFirstRender.current) return;
 | 
			
		||||
 | 
			
		||||
        setPriceBasedOnQuantity();
 | 
			
		||||
    }, [quantity]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!priceProps.onChange || !price) return;
 | 
			
		||||
        if (isFirstRender.current) return;
 | 
			
		||||
 | 
			
		||||
        if (!priceProps.onChange || typeof price === 'undefined') return;
 | 
			
		||||
        priceProps.onChange(price);
 | 
			
		||||
    }, [price]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        // if (!isFirstRender) setPrice(0);
 | 
			
		||||
        // if (isFirstRender.current && price) return;
 | 
			
		||||
        if (!serviceProps.onChange || !service) return;
 | 
			
		||||
        if (price && isFirstRender.current) return;
 | 
			
		||||
        setPriceBasedOnService();
 | 
			
		||||
        serviceProps.onChange(service);
 | 
			
		||||
    }, [service]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        console.log('first render')
 | 
			
		||||
        isFirstRender.current = false;
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    const onReload = () => {
 | 
			
		||||
        setPriceBasedOnService();
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <Flex
 | 
			
		||||
            {...containerProps}
 | 
			
		||||
            align={"center"}
 | 
			
		||||
            gap={rem(10)}
 | 
			
		||||
            {...containerProps}
 | 
			
		||||
        >
 | 
			
		||||
 | 
			
		||||
            <ActionIcon variant={"default"}>
 | 
			
		||||
                <IconReload onClick={() => onReload()}/>
 | 
			
		||||
            </ActionIcon>
 | 
			
		||||
            <ServiceSelectNew
 | 
			
		||||
                {...serviceProps}
 | 
			
		||||
                value={service}
 | 
			
		||||
                onChange={onServiceManualChange}
 | 
			
		||||
                filterType={filterType}
 | 
			
		||||
            />
 | 
			
		||||
            <NumberInput
 | 
			
		||||
                {...priceProps}
 | 
			
		||||
                onChange={onPriceManualChange}
 | 
			
		||||
                value={price}
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
        </Flex>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,6 @@ type Props = {
 | 
			
		||||
const BarcodeTemplateAdditionalFieldTable: FC<Props> = (props: Props) => {
 | 
			
		||||
    const {value, onChange} = props;
 | 
			
		||||
    const [innerValue, setInnerValue] = useState<FieldType[]>(props.value || []);
 | 
			
		||||
    console.log(innerValue);
 | 
			
		||||
    const onNameChange = (field: FieldType, newName: string) => {
 | 
			
		||||
        const newField = {...field, name: newName};
 | 
			
		||||
        const newFields = innerValue.map(f => f === field ? newField : f);
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,6 @@ const BarcodeTemplateFormModal = ({
 | 
			
		||||
            name: (name: string | undefined) => name && name.trim() !== '' ? null : "Необходимо ввести название шаблона",
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
    console.log(form.values.additionalAttributes);
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseFormModal
 | 
			
		||||
            {...innerProps}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import {ActionIcon, Button, Flex, Input, rem} from "@mantine/core";
 | 
			
		||||
import {ActionIcon, Button, ComboboxItem, ComboboxItemGroup, Flex, Input, OptionsFilter, rem} from "@mantine/core";
 | 
			
		||||
import {BaseFormInputProps} from "../../../../types/utils.ts";
 | 
			
		||||
import {DealProductServiceSchema, ServiceSchema} from "../../../../client";
 | 
			
		||||
import {FC, useEffect, useState} from "react";
 | 
			
		||||
@@ -32,6 +32,16 @@ const DealProductServiceTable: FC<Props> = (props: Props) => {
 | 
			
		||||
        setInnerValue(oldValue => oldValue.filter((_, i) => i !== idx));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const serviceOptionsFilter = ({options}: { options: ComboboxItemGroup[] }) => {
 | 
			
		||||
        const productServiceIds = innerValue.map(service => service.service?.id);
 | 
			
		||||
        return (options as ComboboxItemGroup[]).map(({items, group}) => {
 | 
			
		||||
            return {
 | 
			
		||||
                group,
 | 
			
		||||
                items: items.filter(item => !productServiceIds.includes(parseInt((item as ComboboxItem).value)))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        onChange(innerValue as DealProductServiceSchema[]);
 | 
			
		||||
    }, [innerValue]);
 | 
			
		||||
@@ -39,7 +49,8 @@ const DealProductServiceTable: FC<Props> = (props: Props) => {
 | 
			
		||||
        <Input.Wrapper error={error}>
 | 
			
		||||
            <Flex direction={"column"} gap={rem(10)}>
 | 
			
		||||
                {innerValue.map((service, idx) => (
 | 
			
		||||
                    <Flex key={idx} direction={"row"} gap={rem(10)} align={"center"} justify={"stretch"}>
 | 
			
		||||
                    <Flex key={service.service?.name || idx} direction={"row"} gap={rem(10)} align={"center"}
 | 
			
		||||
                          justify={"stretch"}>
 | 
			
		||||
                        <ActionIcon onClick={() => onDelete(idx)} variant={"default"}>
 | 
			
		||||
                            <IconTrash/>
 | 
			
		||||
                        </ActionIcon>
 | 
			
		||||
@@ -48,7 +59,8 @@ const DealProductServiceTable: FC<Props> = (props: Props) => {
 | 
			
		||||
                                onChange: (event) => onServiceChange(idx, event),
 | 
			
		||||
                                value: service.service,
 | 
			
		||||
                                placeholder: "Выберите услугу",
 | 
			
		||||
                                style: {width: "100%"}
 | 
			
		||||
                                style: {width: "100%"},
 | 
			
		||||
                                filter: serviceOptionsFilter as OptionsFilter
 | 
			
		||||
                            }}
 | 
			
		||||
                            priceProps={{
 | 
			
		||||
                                onChange: (event) => onQuantityChange(idx, event),
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ const DealProductsTable: FC<Props> = (props: Props) => {
 | 
			
		||||
                onCreate: (product) => onCreate(product as DealProductSchema),
 | 
			
		||||
                clientId
 | 
			
		||||
            },
 | 
			
		||||
            size:"lg"
 | 
			
		||||
            size: "lg"
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    const onPrintBarcodeClick = (product: DealProductSchema) => {
 | 
			
		||||
@@ -73,6 +73,7 @@ const DealProductsTable: FC<Props> = (props: Props) => {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    const onEditClick = (product: DealProductSchema) => {
 | 
			
		||||
        if (!onChange) return;
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
            modal: "addDealProduct",
 | 
			
		||||
            title: 'Создание товара',
 | 
			
		||||
@@ -80,10 +81,9 @@ const DealProductsTable: FC<Props> = (props: Props) => {
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                clientId: clientId,
 | 
			
		||||
                element: product,
 | 
			
		||||
                onChange: () => {
 | 
			
		||||
                }
 | 
			
		||||
                onChange: onChange
 | 
			
		||||
            },
 | 
			
		||||
            size:"lg"
 | 
			
		||||
            size: "lg"
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import {useMemo} from "react";
 | 
			
		||||
import {MRT_ColumnDef} from "mantine-react-table";
 | 
			
		||||
import {DealProductSchema} from "../../../../client";
 | 
			
		||||
import PlusMinusInput from "../../../../components/PlusMinusInput/PlusMinusInput.tsx";
 | 
			
		||||
import {List} from "@mantine/core";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
@@ -11,7 +10,7 @@ type Props = {
 | 
			
		||||
const useDealProductsTableColumns = (props: Props) => {
 | 
			
		||||
    const {onChange, data} = props;
 | 
			
		||||
    const totalQuantity = useMemo(() => data.reduce((acc, row) => acc + row.quantity, 0), [data]);
 | 
			
		||||
 | 
			
		||||
    const totalPrice = useMemo(() => data.reduce((totalAcc, row) => totalAcc + row.services.reduce((singleAcc, service) => singleAcc + service.price * row.quantity, 0), 0), [data]);
 | 
			
		||||
    return useMemo<MRT_ColumnDef<DealProductSchema>[]>(() => [
 | 
			
		||||
        {
 | 
			
		||||
            accessorKey: "product.article",
 | 
			
		||||
@@ -50,14 +49,24 @@ const useDealProductsTableColumns = (props: Props) => {
 | 
			
		||||
            enableSorting: false,
 | 
			
		||||
            enableColumnActions: false,
 | 
			
		||||
            Footer: <>Всего товаров: {totalQuantity} </>,
 | 
			
		||||
            Cell: ({row}) => {
 | 
			
		||||
                return (
 | 
			
		||||
                    <PlusMinusInput
 | 
			
		||||
                        value={row.original.quantity}
 | 
			
		||||
                        onChange={(value) => onChange(row.original, value)}
 | 
			
		||||
                    />
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            header: "Услуги",
 | 
			
		||||
            Cell: ({row}) => <List size={"sm"}>{
 | 
			
		||||
                row.original.services.map(service => `${service.service.name} (${service.price}₽ за шт)`)
 | 
			
		||||
                    .map(serviceText => <List.Item key={serviceText}>
 | 
			
		||||
                            {serviceText}
 | 
			
		||||
                        </List.Item>
 | 
			
		||||
                    )}
 | 
			
		||||
            </List>,
 | 
			
		||||
            enableColumnActions: false,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            header: "Итоговая стоимость услуг",
 | 
			
		||||
            Cell: ({row}) => <>
 | 
			
		||||
                {row.original.services.reduce((acc, service) => acc + row.original.quantity * service.price, 0)}</>,
 | 
			
		||||
            enableColumnActions: false,
 | 
			
		||||
            Footer: <>Всего стоимость услуг: {totalPrice}</>
 | 
			
		||||
        }
 | 
			
		||||
    ], [onChange, data])
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
 | 
			
		||||
import {MRT_TableOptions} from "mantine-react-table";
 | 
			
		||||
import {ActionIcon, Button, Flex, rem, Tooltip} from "@mantine/core";
 | 
			
		||||
import {openContextModal} from "@mantine/modals";
 | 
			
		||||
import {IconTrash} from "@tabler/icons-react";
 | 
			
		||||
import {IconEdit, IconTrash} from "@tabler/icons-react";
 | 
			
		||||
 | 
			
		||||
type RestProps = {
 | 
			
		||||
    onMultipleDelete?: (items: DealServiceSchema[]) => void;
 | 
			
		||||
@@ -22,13 +22,15 @@ const DealServicesTable: FC<Props> = (
 | 
			
		||||
        onMultipleDelete,
 | 
			
		||||
        tableRef
 | 
			
		||||
    }) => {
 | 
			
		||||
    const serviceIds = items.map(item => item.service.id);
 | 
			
		||||
    const onQuantityChange = (service: DealServiceSchema, quantity: number) => {
 | 
			
		||||
        if (!onChange) return;
 | 
			
		||||
        if (quantity <= 0 && onDelete) {
 | 
			
		||||
            onDelete(service);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        onChange({...service, quantity});
 | 
			
		||||
        return;
 | 
			
		||||
        // if (!onChange) return;
 | 
			
		||||
        // if (quantity <= 0 && onDelete) {
 | 
			
		||||
        //     onDelete(service);
 | 
			
		||||
        //     return;
 | 
			
		||||
        // }
 | 
			
		||||
        // onChange({...service, quantity});
 | 
			
		||||
    }
 | 
			
		||||
    const columns = useDealServicesTableColumns({
 | 
			
		||||
        onChange: onQuantityChange,
 | 
			
		||||
@@ -40,11 +42,24 @@ const DealServicesTable: FC<Props> = (
 | 
			
		||||
            title: "Добавление услуги",
 | 
			
		||||
            modal: "addDealService",
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                onCreate: (event) => onCreate(event as DealServiceSchema)
 | 
			
		||||
                onCreate: (event) => onCreate(event as DealServiceSchema),
 | 
			
		||||
                serviceIds
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    const onEditClick = (service: DealServiceSchema) => {
 | 
			
		||||
        if (!onChange) return;
 | 
			
		||||
        openContextModal({
 | 
			
		||||
            title: "Добавление услуги",
 | 
			
		||||
            modal: "addDealService",
 | 
			
		||||
            innerProps: {
 | 
			
		||||
                element: service,
 | 
			
		||||
                onChange,
 | 
			
		||||
                serviceIds
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseTable
 | 
			
		||||
            ref={tableRef}
 | 
			
		||||
@@ -80,7 +95,6 @@ const DealServicesTable: FC<Props> = (
 | 
			
		||||
                ),
 | 
			
		||||
                renderRowActions: ({row}) => (
 | 
			
		||||
                    <Flex gap="md">
 | 
			
		||||
 | 
			
		||||
                        <Tooltip label="Удалить">
 | 
			
		||||
                            <ActionIcon onClick={() => {
 | 
			
		||||
                                if (onDelete) onDelete(row.original);
 | 
			
		||||
@@ -88,6 +102,13 @@ const DealServicesTable: FC<Props> = (
 | 
			
		||||
                                <IconTrash/>
 | 
			
		||||
                            </ActionIcon>
 | 
			
		||||
                        </Tooltip>
 | 
			
		||||
                        <Tooltip label="Редактировать">
 | 
			
		||||
                            <ActionIcon onClick={() => {
 | 
			
		||||
                                onEditClick(row.original);
 | 
			
		||||
                            }} variant={"default"}>
 | 
			
		||||
                                <IconEdit/>
 | 
			
		||||
                            </ActionIcon>
 | 
			
		||||
                        </Tooltip>
 | 
			
		||||
                    </Flex>
 | 
			
		||||
                )
 | 
			
		||||
            } as MRT_TableOptions<DealServiceSchema>}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import {MRT_ColumnDef} from "mantine-react-table";
 | 
			
		||||
import {useMemo} from "react";
 | 
			
		||||
import {DealServiceSchema} from "../../../../client";
 | 
			
		||||
import PlusMinusInput from "../../../../components/PlusMinusInput/PlusMinusInput.tsx";
 | 
			
		||||
 | 
			
		||||
type Props = {
 | 
			
		||||
    onChange: (service: DealServiceSchema, quantity: number) => void;
 | 
			
		||||
@@ -11,7 +10,7 @@ type Props = {
 | 
			
		||||
export const useDealServicesTableColumns = (props: Props) => {
 | 
			
		||||
    const {onChange, data} = props;
 | 
			
		||||
    const totalPrice = useMemo(() =>
 | 
			
		||||
            data.reduce((acc, row) => acc + row.quantity * row.service.price, 0)
 | 
			
		||||
            data.reduce((acc, row) => acc + row.quantity * row.price, 0)
 | 
			
		||||
        ,
 | 
			
		||||
        [data]);
 | 
			
		||||
 | 
			
		||||
@@ -28,34 +27,34 @@ export const useDealServicesTableColumns = (props: Props) => {
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            enableGrouping: false,
 | 
			
		||||
            accessorKey: "service.price",
 | 
			
		||||
            accessorKey: "price",
 | 
			
		||||
            header: "Цена",
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            enableGrouping: false,
 | 
			
		||||
            accessorKey: "quantity",
 | 
			
		||||
            header: "Количество",
 | 
			
		||||
            Cell: ({row}) => {
 | 
			
		||||
                return (
 | 
			
		||||
                    <PlusMinusInput
 | 
			
		||||
                        value={row.original.quantity}
 | 
			
		||||
                        onChange={(value) => onChange(row.original, value)}
 | 
			
		||||
                    />
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            // Cell: ({row}) => {
 | 
			
		||||
            //     return (
 | 
			
		||||
            //         <PlusMinusInput
 | 
			
		||||
            //             value={row.original.quantity}
 | 
			
		||||
            //             onChange={(value) => onChange(row.original, value)}
 | 
			
		||||
            //         />
 | 
			
		||||
            //     )
 | 
			
		||||
            // }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            enableGrouping: false,
 | 
			
		||||
            header: "Сумма",
 | 
			
		||||
            Cell: ({row}) => {
 | 
			
		||||
                return row.original.quantity * row.original.service.price;
 | 
			
		||||
                return row.original.quantity * row.original.price;
 | 
			
		||||
            },
 | 
			
		||||
            aggregationFn: "sum",
 | 
			
		||||
            AggregatedCell: ({cell}) => {
 | 
			
		||||
                return <>Итоговая сумма по категории: {" "}
 | 
			
		||||
                    {
 | 
			
		||||
                        cell.row.subRows?.reduce((acc, row) =>
 | 
			
		||||
                            acc + row.original.quantity * row.original.service.price, 0)
 | 
			
		||||
                            acc + row.original.quantity * row.original.price, 0)
 | 
			
		||||
                    }
 | 
			
		||||
                </>;
 | 
			
		||||
            },
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ export const useDealStatusChangeTableColumns = () => {
 | 
			
		||||
            accessorKey: "comment",
 | 
			
		||||
            header: "Комментарий",
 | 
			
		||||
            Cell: ({row}) =>
 | 
			
		||||
            <Spoiler onDoubleClick={()=>{console.log("double click")}} maxHeight={80} showLabel={"Показать весь"} hideLabel={"Скрыть"}>
 | 
			
		||||
            <Spoiler  maxHeight={80} showLabel={"Показать весь"} hideLabel={"Скрыть"}>
 | 
			
		||||
                <Text style={{wordWrap: "break-word", wordBreak: "break-all", whiteSpace: "normal"}} span>
 | 
			
		||||
                    {row.original.comment}<br/>
 | 
			
		||||
                </Text>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
.bottom-panel {
 | 
			
		||||
    padding: rem(10);
 | 
			
		||||
    border-radius: rem(5);
 | 
			
		||||
    @mixin light {
 | 
			
		||||
        background-color: var(--mantine-color-gray-1);
 | 
			
		||||
    }
 | 
			
		||||
    @mixin dark {
 | 
			
		||||
        background-color: var(--mantine-color-dark-5);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,7 @@ import {IconBarcode, IconBox, IconCalendarUser, IconSettings} from "@tabler/icon
 | 
			
		||||
import DealStatusChangeTable from "../../components/DealStatusChangeTable/DealStatusChangeTable.tsx";
 | 
			
		||||
import DealEditDrawerGeneralTab from "./tabs/DealEditDrawerGeneralTab.tsx";
 | 
			
		||||
import {useQueryClient} from "@tanstack/react-query";
 | 
			
		||||
// import styles from './DealEditDrawer.module.css';
 | 
			
		||||
 | 
			
		||||
const useDealServicesTableState = () => {
 | 
			
		||||
    const {selectedDeal, setSelectedDeal} = useDealPageContext();
 | 
			
		||||
@@ -18,11 +19,10 @@ const useDealServicesTableState = () => {
 | 
			
		||||
 | 
			
		||||
    const onServiceUpdate = (service: DealServiceSchema) => {
 | 
			
		||||
        if (!selectedDeal) return;
 | 
			
		||||
        DealService.updateDealServiceQuantity({
 | 
			
		||||
        DealService.updateDealService({
 | 
			
		||||
            requestBody: {
 | 
			
		||||
                dealId: selectedDeal.id,
 | 
			
		||||
                serviceId: service.service.id,
 | 
			
		||||
                quantity: service.quantity
 | 
			
		||||
                service
 | 
			
		||||
            }
 | 
			
		||||
        }).then(async ({ok, message}) => {
 | 
			
		||||
 | 
			
		||||
@@ -72,14 +72,13 @@ const useDealServicesTableState = () => {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    const onServiceCreate = (service: DealServiceSchema) => {
 | 
			
		||||
        console.log('-------Drawer')
 | 
			
		||||
        console.log(service);
 | 
			
		||||
        if (!selectedDeal) return;
 | 
			
		||||
        DealService.addDealService({
 | 
			
		||||
            requestBody: {
 | 
			
		||||
                dealId: selectedDeal.id,
 | 
			
		||||
                serviceId: service.service.id,
 | 
			
		||||
                quantity: service.quantity
 | 
			
		||||
                quantity: service.quantity,
 | 
			
		||||
                price: service.price
 | 
			
		||||
            }
 | 
			
		||||
        }).then(async ({ok, message}) => {
 | 
			
		||||
            if (!ok) {
 | 
			
		||||
@@ -157,17 +156,14 @@ const useDealProductTableState = () => {
 | 
			
		||||
 | 
			
		||||
    const onProductUpdate = (product: DealProductSchema) => {
 | 
			
		||||
        if (!selectedDeal) return;
 | 
			
		||||
        DealService.updateDealProductQuantity({
 | 
			
		||||
        DealService.updateDealProduct({
 | 
			
		||||
            requestBody: {
 | 
			
		||||
                dealId: selectedDeal.id,
 | 
			
		||||
                productId: product.product.id,
 | 
			
		||||
                quantity: product.quantity
 | 
			
		||||
                product: product
 | 
			
		||||
            }
 | 
			
		||||
        }).then(async ({ok, message}) => {
 | 
			
		||||
            if (!ok) {
 | 
			
		||||
                notifications.guess(ok, {message});
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            notifications.guess(ok, {message});
 | 
			
		||||
            if (!ok) return;
 | 
			
		||||
            await DealService.getDealById({dealId: selectedDeal.id})
 | 
			
		||||
                .then(setSelectedDeal)
 | 
			
		||||
        })
 | 
			
		||||
@@ -361,7 +357,6 @@ const DealEditDrawer: FC = () => {
 | 
			
		||||
                </Tabs.Panel>
 | 
			
		||||
                <Tabs.Panel value={"services"}>
 | 
			
		||||
                    <Box p={rem(10)}>
 | 
			
		||||
 | 
			
		||||
                        <DealEditDrawerServicesTable/>
 | 
			
		||||
                    </Box>
 | 
			
		||||
                </Tabs.Panel>
 | 
			
		||||
@@ -370,9 +365,15 @@ const DealEditDrawer: FC = () => {
 | 
			
		||||
 | 
			
		||||
                        <DealEditDrawerProductsTable/>
 | 
			
		||||
                    </Box>
 | 
			
		||||
 | 
			
		||||
                </Tabs.Panel>
 | 
			
		||||
            </Tabs>
 | 
			
		||||
            {/*<Flex*/}
 | 
			
		||||
            {/*    h={"10%"}*/}
 | 
			
		||||
            {/*    align={'flex-end'}*/}
 | 
			
		||||
            {/*    justify={"flex-end"}*/}
 | 
			
		||||
            {/*>*/}
 | 
			
		||||
 | 
			
		||||
            {/*</Flex>*/}
 | 
			
		||||
        </Drawer>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,6 @@ const AddDealProductModal = ({
 | 
			
		||||
 | 
			
		||||
    const validateServices = (services?: DealProductServiceSchema[]) => {
 | 
			
		||||
        if (!services || services.length == 0) return null;
 | 
			
		||||
        console.log("validating...");
 | 
			
		||||
        console.log( services.filter(service => service.service === undefined))
 | 
			
		||||
        return services.find(service => service.service === undefined) ? "Удалите пустые услуги" : null;
 | 
			
		||||
    }
 | 
			
		||||
    const form = useForm<Partial<DealProductSchema>>({
 | 
			
		||||
@@ -39,11 +37,11 @@ const AddDealProductModal = ({
 | 
			
		||||
            services: validateServices
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    console.log(form.values);
 | 
			
		||||
 | 
			
		||||
    const onClose = () => {
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
    console.log(form.values)
 | 
			
		||||
    return (
 | 
			
		||||
 | 
			
		||||
        <BaseFormModal
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,24 @@ import {ContextModalProps} from "@mantine/modals";
 | 
			
		||||
import BaseFormModal, {CreateEditFormProps} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
			
		||||
import {DealServiceSchema} from "../../../client";
 | 
			
		||||
import {useForm} from "@mantine/form";
 | 
			
		||||
import {NumberInput} from "@mantine/core";
 | 
			
		||||
import ServiceSelect from "../../../components/ServiceSelect/ServiceSelect.tsx";
 | 
			
		||||
import {ComboboxItem, ComboboxItemGroup, NumberInput, OptionsFilter} from "@mantine/core";
 | 
			
		||||
import ServiceWithPriceInput from "../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
			
		||||
import {ServiceType} from "../../../shared/enums/ServiceType.ts";
 | 
			
		||||
 | 
			
		||||
type Props = CreateEditFormProps<Partial<DealServiceSchema>>;
 | 
			
		||||
type RestProps = {
 | 
			
		||||
    serviceIds?: number[];
 | 
			
		||||
}
 | 
			
		||||
type Props = CreateEditFormProps<Partial<DealServiceSchema>> & RestProps;
 | 
			
		||||
const AddDealServiceModal = ({
 | 
			
		||||
                                 context,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 innerProps
 | 
			
		||||
                             }: ContextModalProps<Props>) => {
 | 
			
		||||
    const isEditing = 'element' in innerProps;
 | 
			
		||||
    const form = useForm<Partial<DealServiceSchema>>({
 | 
			
		||||
        initialValues: {
 | 
			
		||||
        initialValues: isEditing ? innerProps.element : {
 | 
			
		||||
            service: undefined,
 | 
			
		||||
            quantity: 0,
 | 
			
		||||
            quantity: 1,
 | 
			
		||||
        },
 | 
			
		||||
        validate: {
 | 
			
		||||
            service: (service?: DealServiceSchema['service']) => service !== undefined ? null : "Необходимо выбрать услугу",
 | 
			
		||||
@@ -25,6 +30,16 @@ const AddDealServiceModal = ({
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const serviceOptionsFilter = ({options}: { options: ComboboxItemGroup[] }) => {
 | 
			
		||||
        if (!innerProps.serviceIds) return options;
 | 
			
		||||
        const productServiceIds = innerProps.serviceIds;
 | 
			
		||||
        return (options as ComboboxItemGroup[]).map(({items, group}) => {
 | 
			
		||||
            return {
 | 
			
		||||
                group,
 | 
			
		||||
                items: items.filter(item => !productServiceIds.includes(parseInt((item as ComboboxItem).value)))
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <BaseFormModal
 | 
			
		||||
@@ -34,10 +49,27 @@ const AddDealServiceModal = ({
 | 
			
		||||
            onClose={onClose}>
 | 
			
		||||
            <BaseFormModal.Body>
 | 
			
		||||
                <>
 | 
			
		||||
                    <ServiceSelect
 | 
			
		||||
                        placeholder={"Выберите услугу"}
 | 
			
		||||
                        label={"Услуга"}
 | 
			
		||||
                        {...form.getInputProps('service')}
 | 
			
		||||
                    <ServiceWithPriceInput
 | 
			
		||||
                        serviceProps={{
 | 
			
		||||
                            ...form.getInputProps('service'),
 | 
			
		||||
                            label: "Услуга",
 | 
			
		||||
                            placeholder: "Выберите услугу",
 | 
			
		||||
                            style: {width: '100%'},
 | 
			
		||||
                            disabled: isEditing,
 | 
			
		||||
                            filter: serviceOptionsFilter as OptionsFilter
 | 
			
		||||
                        }}
 | 
			
		||||
                        priceProps={{
 | 
			
		||||
                            ...form.getInputProps('price'),
 | 
			
		||||
                            label: "Цена",
 | 
			
		||||
                            placeholder: "Введите цену",
 | 
			
		||||
                            style: {width: '100%'}
 | 
			
		||||
                        }}
 | 
			
		||||
                        quantity={form.values.quantity || 1}
 | 
			
		||||
                        containerProps={{
 | 
			
		||||
                            direction: "column",
 | 
			
		||||
                            style: {width: "100%"}
 | 
			
		||||
                        }}
 | 
			
		||||
                        filterType={ServiceType.DEAL_SERVICE}
 | 
			
		||||
                    />
 | 
			
		||||
                    <NumberInput
 | 
			
		||||
                        placeholder={"Введите количество"}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {SegmentedControl, SegmentedControlProps} from "@mantine/core";
 | 
			
		||||
import {ServiceType} from "../../../../shared/enums/ServiceType.ts";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type Props = Omit<SegmentedControlProps, 'data'>;
 | 
			
		||||
const data = [
 | 
			
		||||
    {
 | 
			
		||||
        label: 'Для товара',
 | 
			
		||||
        value: ServiceType.PRODUCT_SERVICE.toString()
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        label: 'Для сделки',
 | 
			
		||||
        value: ServiceType.DEAL_SERVICE.toString()
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
const ServiceTypeSegmentedControl: FC<Props> = (props) => {
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <SegmentedControl
 | 
			
		||||
            data={data}
 | 
			
		||||
            {...props}
 | 
			
		||||
        />
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
export default ServiceTypeSegmentedControl
 | 
			
		||||
@@ -44,7 +44,6 @@ const CreateServiceModal = ({
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    console.log(form.values)
 | 
			
		||||
    const onCancelClick = () => {
 | 
			
		||||
        context.closeContextModal(id);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,9 @@
 | 
			
		||||
    padding: rem(5);
 | 
			
		||||
    gap: rem(10);
 | 
			
		||||
    display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.top-panel-last-item {
 | 
			
		||||
    margin-left: auto;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import {FC} from "react";
 | 
			
		||||
import {FC, useState} from "react";
 | 
			
		||||
import ServicesTable from "../components/ServicesTable/ServicesTable.tsx";
 | 
			
		||||
import useServicesList from "../hooks/useServicesList.tsx";
 | 
			
		||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
 | 
			
		||||
@@ -7,10 +7,12 @@ import {Button, Text} from "@mantine/core";
 | 
			
		||||
import {ServiceCategorySchema, ServiceSchema, ServiceService} from "../../../client";
 | 
			
		||||
import {notifications} from "../../../shared/lib/notifications.ts";
 | 
			
		||||
import {modals} from "@mantine/modals";
 | 
			
		||||
import ServiceTypeSegmentedControl from "../components/ServiceTypeSegmentedControl/ServiceTypeSegmentedControl.tsx";
 | 
			
		||||
import {ServiceType} from "../../../shared/enums/ServiceType.ts";
 | 
			
		||||
 | 
			
		||||
export const ServicesPage: FC = () => {
 | 
			
		||||
    const {services, refetch} = useServicesList();
 | 
			
		||||
 | 
			
		||||
    const [serviceType, setServiceType] = useState(ServiceType.DEAL_SERVICE)
 | 
			
		||||
    // region Service create
 | 
			
		||||
    const onCreateClick = () => {
 | 
			
		||||
        modals.openContextModal({
 | 
			
		||||
@@ -90,13 +92,18 @@ export const ServicesPage: FC = () => {
 | 
			
		||||
                <div className={styles['top-panel']}>
 | 
			
		||||
                    <Button onClick={onCreateClick} variant={"default"}>Создать услугу</Button>
 | 
			
		||||
                    <Button onClick={onCreateCategoryClick} variant={"default"}>Создать категорию</Button>
 | 
			
		||||
                    <ServiceTypeSegmentedControl
 | 
			
		||||
                        className={styles['top-panel-last-item']}
 | 
			
		||||
                        value={serviceType.toString()}
 | 
			
		||||
                        onChange={(event) => setServiceType(parseInt(event))}
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
            </PageBlock>
 | 
			
		||||
            <PageBlock>
 | 
			
		||||
                <ServicesTable
 | 
			
		||||
                    onDelete={onServiceDelete}
 | 
			
		||||
                    onChange={onServiceUpdate}
 | 
			
		||||
                    items={services}
 | 
			
		||||
                    items={services.filter(service => service.serviceType == serviceType)}
 | 
			
		||||
                />
 | 
			
		||||
            </PageBlock>
 | 
			
		||||
        </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,73 +1,14 @@
 | 
			
		||||
import {createLazyFileRoute} from "@tanstack/react-router";
 | 
			
		||||
import ServiceSelectNew from "../components/Selects/ServiceSelectNew/ServiceSelectNew.tsx";
 | 
			
		||||
import {ServiceType} from "../shared/enums/ServiceType.ts";
 | 
			
		||||
import ServiceWithPriceInput from "../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
 | 
			
		||||
import {useEffect, useState} from "react";
 | 
			
		||||
import {ServiceSchema, ServiceService} from "../client";
 | 
			
		||||
import {NumberInput} from "@mantine/core";
 | 
			
		||||
import {isNumber} from "lodash";
 | 
			
		||||
import useServicesList from "../pages/ServicesPage/hooks/useServicesList.tsx";
 | 
			
		||||
 | 
			
		||||
export const Route = createLazyFileRoute('/test')({
 | 
			
		||||
    component: TestPage
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const data = [{
 | 
			
		||||
    label: "test",
 | 
			
		||||
    value: '0'
 | 
			
		||||
},
 | 
			
		||||
    {
 | 
			
		||||
        label: "test2",
 | 
			
		||||
        value: '1'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
function TestPage() {
 | 
			
		||||
    const [service, setService] = useState<ServiceSchema | undefined>({
 | 
			
		||||
        "id": 96,
 | 
			
		||||
        "name": "123",
 | 
			
		||||
        "category": {"id": 1, "name": "Услуги по работе с товаром с учетом суммы всех сторон в см."},
 | 
			
		||||
        "price": 0,
 | 
			
		||||
        "serviceType": 1,
 | 
			
		||||
        "priceRanges": [{"id": 4, "fromQuantity": 1, "toQuantity": 200, "price": 35}, {
 | 
			
		||||
            "id": 3,
 | 
			
		||||
            "fromQuantity": 201,
 | 
			
		||||
            "toQuantity": 300,
 | 
			
		||||
            "price": 24
 | 
			
		||||
        }]
 | 
			
		||||
    });
 | 
			
		||||
    const [price, setPrice] = useState<number | string>();
 | 
			
		||||
    const [q, setQ] = useState(1);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    console.log('service:---------');
 | 
			
		||||
    console.log(service);
 | 
			
		||||
    console.log('price:---------');
 | 
			
		||||
    console.log(price);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <NumberInput
 | 
			
		||||
                value={q}
 | 
			
		||||
                onChange={event => {
 | 
			
		||||
                    if (!isNumber(event)) return;
 | 
			
		||||
                    setQ(event);
 | 
			
		||||
                }}
 | 
			
		||||
            />
 | 
			
		||||
            <ServiceWithPriceInput
 | 
			
		||||
                priceProps={{
 | 
			
		||||
                    onChange: setPrice,
 | 
			
		||||
                    value: price,
 | 
			
		||||
                    label: "Цена"
 | 
			
		||||
                }}
 | 
			
		||||
                quantity={q}
 | 
			
		||||
                serviceProps={{
 | 
			
		||||
                    onChange: setService,
 | 
			
		||||
                    value: service,
 | 
			
		||||
                    label: "Услуга"
 | 
			
		||||
                }}
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
        </>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user