feat: deal product services

This commit is contained in:
2024-05-18 07:01:08 +03:00
parent 2f589edacc
commit b0cfaf3a8b
13 changed files with 334 additions and 96 deletions

View File

@@ -1,30 +1,73 @@
import {Checkbox, Flex, NumberInput} from "@mantine/core";
import ServiceSelectNew from "../../../../components/Selects/ServiceSelectNew/ServiceSelectNew.tsx";
import {ServiceType} from "../../../../shared/enums/ServiceType.ts";
import {useForm} from "@mantine/form";
import {DealProductServiceSchema} from "../../../../client";
import {ActionIcon, Button, Flex, Input, rem} from "@mantine/core";
import {BaseFormInputProps} from "../../../../types/utils.ts";
import {DealProductServiceSchema, ServiceSchema} from "../../../../client";
import {FC, useEffect, useState} from "react";
import ServiceWithPriceInput from "../../../../components/ServiceWithPriceInput/ServiceWithPriceInput.tsx";
import {isNumber} from "lodash";
import {notifications} from "../../../../shared/lib/notifications.ts";
import {IconTrash} from "@tabler/icons-react";
const DealProductServiceTable = () => {
const initialValues: Partial<DealProductServiceSchema> = {}
const form = useForm<Partial<DealProductServiceSchema>>(
);
type RestProps = {
quantity: number;
}
type Props = BaseFormInputProps<DealProductServiceSchema[]> & RestProps;
const DealProductServiceTable: FC<Props> = (props: Props) => {
const {value, onChange, quantity, error} = props;
const [innerValue, setInnerValue] = useState<Partial<DealProductServiceSchema>[]>(value || []);
const onServiceChange = (idx: number, value: ServiceSchema) => {
setInnerValue(oldValue => oldValue.map((item, i) => i === idx ? {...item, service: value} : item));
}
const onQuantityChange = (idx: number, value: string | number) => {
if (!isNumber(value)) return;
setInnerValue(oldValue => oldValue.map((item, i) => i === idx ? {...item, price: value} : item));
}
const onCreate = () => {
if (innerValue.length > 0 && !innerValue.at(-1)?.service) {
notifications.error({message: "Заполните последнюю услугу"})
return;
}
setInnerValue(prevState => [...prevState, {service: undefined, quantity: 1}])
}
const onDelete = (idx: number) => {
setInnerValue(oldValue => oldValue.filter((_, i) => i !== idx));
}
useEffect(() => {
onChange(innerValue as DealProductServiceSchema[]);
}, [innerValue]);
return (
<Flex direction={"column"}>
<ServiceSelectNew
filterType={ServiceType.PRODUCT_SERVICE}
onChange={() => {
}}/>
<NumberInput
label={"Количество"}
/>
<Checkbox
label={"Привязать количество услуг к количеству товара"}
/>
<NumberInput
label={"Цена за единицу"}
/>
<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"}>
<ActionIcon onClick={() => onDelete(idx)} variant={"default"}>
<IconTrash/>
</ActionIcon>
<ServiceWithPriceInput
serviceProps={{
onChange: (event) => onServiceChange(idx, event),
value: service.service,
placeholder: "Выберите услугу",
style: {width: "100%"}
}}
priceProps={{
onChange: (event) => onQuantityChange(idx, event),
value: service.price,
placeholder: "Введите стоимость",
hideControls: true,
style: {width: "100%"},
suffix: "₽"
</Flex>
}}
containerProps={{w: "100%"}}
quantity={quantity}
/>
</Flex>
))}
<Button onClick={onCreate} variant={"default"}>Добавить услугу</Button>
</Flex>
</Input.Wrapper>
)
}
export default DealProductServiceTable;

View File

@@ -6,7 +6,7 @@ import {DealProductSchema, ProductService} from "../../../../client";
import {ActionIcon, Button, Flex, rem, Tooltip} from "@mantine/core";
import {MRT_TableOptions} from "mantine-react-table";
import {modals} from "@mantine/modals";
import {IconBarcode, IconTrash} from "@tabler/icons-react";
import {IconBarcode, IconEdit, IconTrash} from "@tabler/icons-react";
import {notifications} from "../../../../shared/lib/notifications.ts";
import {CreateProductRequest} from "../../../ProductsPage/types.ts";
@@ -39,7 +39,8 @@ const DealProductsTable: FC<Props> = (props: Props) => {
innerProps: {
onCreate: (product) => onCreate(product as DealProductSchema),
clientId
}
},
size:"lg"
})
}
const onPrintBarcodeClick = (product: DealProductSchema) => {
@@ -71,6 +72,21 @@ const DealProductsTable: FC<Props> = (props: Props) => {
}
})
}
const onEditClick = (product: DealProductSchema) => {
modals.openContextModal({
modal: "addDealProduct",
title: 'Создание товара',
withCloseButton: false,
innerProps: {
clientId: clientId,
element: product,
onChange: () => {
}
},
size:"lg"
})
}
return (
<BaseTable
data={items}
@@ -91,6 +107,11 @@ const DealProductsTable: FC<Props> = (props: Props) => {
<IconBarcode/>
</ActionIcon>
</Tooltip>
<Tooltip label="Редактировать">
<ActionIcon onClick={() => onEditClick(row.original)} variant={"default"}>
<IconEdit/>
</ActionIcon>
</Tooltip>
</Flex>
),
renderBottomToolbar: ({table}) => (

View File

@@ -214,8 +214,7 @@ const useDealProductTableState = () => {
DealService.addDealProduct({
requestBody: {
dealId: selectedDeal.id,
productId: product.product.id,
quantity: product.quantity
product: product
}
}).then(async ({ok, message}) => {
if (!ok) {

View File

@@ -1,37 +1,53 @@
import {ContextModalProps} from "@mantine/modals";
import BaseFormModal, {CreateEditFormProps} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
import {DealProductSchema} from "../../../client";
import {DealProductSchema, DealProductServiceSchema} from "../../../client";
import {useForm} from "@mantine/form";
import {NumberInput} from "@mantine/core";
import {Fieldset, NumberInput} from "@mantine/core";
import ProductSelect from "../../../components/ProductSelect/ProductSelect.tsx";
import DealProductServiceTable from "../components/DealProductsTable/DealProductServiceTable.tsx";
import {omit} from "lodash";
import {BaseFormInputProps} from "../../../types/utils.ts";
type RestProps = {
clientId: number
}
type Props = CreateEditFormProps<Partial<DealProductSchema>> & RestProps;
type Props = CreateEditFormProps<DealProductSchema> & RestProps;
const AddDealProductModal = ({
context,
id,
innerProps
}: ContextModalProps<Props>) => {
const isEditing = 'element' in innerProps;
const restProps = omit(innerProps, ['clientId']);
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>>({
initialValues: {
initialValues: isEditing ? innerProps.element : {
product: undefined,
quantity: 0
services: [],
quantity: 1
},
validate: {
product: (product?: DealProductSchema['product']) => product !== undefined ? null : "Необходимо выбрать товар",
quantity: (quantity?: number) => (quantity && quantity > 0) ? null : "Количество должно быть больше 0"
quantity: (quantity?: number) => (quantity && quantity > 0) ? null : "Количество должно быть больше 0",
services: validateServices
}
});
const onClose = () => {
context.closeContextModal(id);
}
console.log(form.values)
return (
<BaseFormModal
{...innerProps}
{...restProps as CreateEditFormProps<DealProductSchema>}
form={form}
closeOnSubmit
onClose={onClose}>
@@ -49,10 +65,19 @@ const AddDealProductModal = ({
min={1}
{...form.getInputProps('quantity')}
/>
<Fieldset legend={'Услуги'}>
<DealProductServiceTable
quantity={form.values.quantity || 1}
{...form.getInputProps('services') as
BaseFormInputProps<DealProductServiceSchema[]>}
/>
</Fieldset>
</>
</BaseFormModal.Body>
</BaseFormModal>
)
}