This commit is contained in:
2024-04-11 14:25:51 +03:00
parent 18157972a1
commit 9815ebbc3b
14 changed files with 254 additions and 14 deletions

View File

@@ -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';

View 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;
};

View File

@@ -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>;
};

View File

@@ -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',

View 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;

View File

@@ -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
}

View File

@@ -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;

View 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;

View File

@@ -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";

View File

@@ -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>
);
}

View 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;

View File

@@ -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>

View File

@@ -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;

View File

@@ -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>