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