feat: filling deals from excel file
This commit is contained in:
150
src/pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx
Normal file
150
src/pages/LeadsPage/contexts/PrefillDealsWithExcelContext.tsx
Normal file
@@ -0,0 +1,150 @@
|
||||
import { createContext, FC, useContext, useState } from "react";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { DealsWithExcelForm, ProductExcelData } from "../drawers/PrefillDealWithExcelDrawer/types.tsx";
|
||||
import { FileWithPath } from "@mantine/dropzone";
|
||||
import { notifications } from "../../../shared/lib/notifications.ts";
|
||||
import { DealService, type ProductFromExcelSchema, ProductSchema } from "../../../client";
|
||||
import UseExcelDropzone from "../../../types/UseExcelDropzone.tsx";
|
||||
import { useForm, UseFormReturnType } from "@mantine/form";
|
||||
import { useDealPageContext } from "./DealPageContext.tsx";
|
||||
|
||||
type PrefillDealsWithExcelContextState = {
|
||||
prefillWithExcelOpened: boolean;
|
||||
prefillWithExcelOnClose: () => void;
|
||||
prefillWithExcelOnOpen: () => void;
|
||||
barcodeProductsMap: Map<string, ProductExcelData>,
|
||||
onProductSelectChange: (barcode: string, selectedProduct: ProductSchema) => void,
|
||||
onDrop: (files: FileWithPath[]) => void;
|
||||
excelDropzone: UseExcelDropzone;
|
||||
createDeals: (values: DealsWithExcelForm) => void;
|
||||
form: UseFormReturnType<DealsWithExcelForm>;
|
||||
errors: string[];
|
||||
};
|
||||
|
||||
const PrefillDealsWithExcelContext = createContext<PrefillDealsWithExcelContextState | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const usePrefillDealsWithExcelContextState = () => {
|
||||
const [prefillWithExcelOpened, { open, close }] = useDisclosure(false);
|
||||
const { refetchDeals } = useDealPageContext();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
const excelDropzone: UseExcelDropzone = {
|
||||
isLoading,
|
||||
setIsLoading,
|
||||
};
|
||||
|
||||
const form = useForm<DealsWithExcelForm>({
|
||||
validate: {
|
||||
client: client => !client && "Выберите клиента",
|
||||
},
|
||||
});
|
||||
|
||||
const [barcodeProductsMap, setBarcodeProductsMap] = useState<Map<string, ProductExcelData>>(new Map());
|
||||
|
||||
const onDrop = (files: FileWithPath[]) => {
|
||||
if (files.length > 1) {
|
||||
notifications.error({ message: "Прикрепите одно изображение" });
|
||||
return;
|
||||
}
|
||||
const file = files[0];
|
||||
|
||||
setIsLoading(true);
|
||||
DealService.parseDealsExcel({
|
||||
formData: {
|
||||
upload_file: file,
|
||||
},
|
||||
})
|
||||
.then(res => {
|
||||
const barcodeProductsMap = new Map();
|
||||
res.rows.forEach((row) => {
|
||||
const productsData: ProductExcelData = row;
|
||||
productsData.selectedProduct = productsData.products[0];
|
||||
barcodeProductsMap.set(row.barcode, row);
|
||||
});
|
||||
setBarcodeProductsMap(barcodeProductsMap);
|
||||
setErrors(res.errors);
|
||||
})
|
||||
.catch(error => {
|
||||
notifications.error({ message: error.toString() });
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
const onProductSelectChange = (barcode: string, selectedProduct: ProductSchema) => {
|
||||
const newBarcodeProductsMap = new Map(barcodeProductsMap);
|
||||
const productsData = newBarcodeProductsMap.get(barcode);
|
||||
if (!productsData) return;
|
||||
productsData.selectedProduct = selectedProduct;
|
||||
|
||||
newBarcodeProductsMap.set(
|
||||
barcode,
|
||||
productsData,
|
||||
);
|
||||
setBarcodeProductsMap(newBarcodeProductsMap);
|
||||
};
|
||||
|
||||
const prefillWithExcelOnClose = () => {
|
||||
close();
|
||||
setBarcodeProductsMap(new Map());
|
||||
form.reset();
|
||||
};
|
||||
|
||||
const createDeals = (values: DealsWithExcelForm) => {
|
||||
const products: ProductFromExcelSchema[] = barcodeProductsMap.entries().map(([, productData]) => {
|
||||
return {
|
||||
productId: productData.selectedProduct!.id,
|
||||
citiesBreakdown: productData.breakdowns,
|
||||
};
|
||||
}).toArray();
|
||||
|
||||
DealService.createDealsExcel({
|
||||
requestBody: {
|
||||
products,
|
||||
clientId: values.client?.id ?? -1,
|
||||
},
|
||||
})
|
||||
.then(({ ok, message }) => {
|
||||
notifications.guess(ok, { message });
|
||||
if (ok) prefillWithExcelOnClose();
|
||||
refetchDeals();
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
};
|
||||
|
||||
return {
|
||||
prefillWithExcelOpened,
|
||||
prefillWithExcelOnClose,
|
||||
prefillWithExcelOnOpen: open,
|
||||
barcodeProductsMap,
|
||||
onProductSelectChange,
|
||||
onDrop,
|
||||
excelDropzone,
|
||||
createDeals,
|
||||
form,
|
||||
errors,
|
||||
};
|
||||
};
|
||||
|
||||
type PrefillDealsWithExcelContextProviderProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const PrefillDealsWithExcelContextProvider: FC<PrefillDealsWithExcelContextProviderProps> = ({ children }) => {
|
||||
const state = usePrefillDealsWithExcelContextState();
|
||||
return (
|
||||
<PrefillDealsWithExcelContext.Provider value={state}>
|
||||
{children}
|
||||
</PrefillDealsWithExcelContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePrefillDealsWithExcelContext = () => {
|
||||
const context = useContext(PrefillDealsWithExcelContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"usePrefillDealsWithExcelContext must be used within a PrefillDealsWithExcelContextProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: rem(10);
|
||||
max-height: 95vh;
|
||||
}
|
||||
|
||||
.deal-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: rem(10);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.deal-container-wrapper {
|
||||
border: dashed var(--item-border-size) var(--mantine-color-default-border);
|
||||
border-radius: var(--item-border-radius);
|
||||
padding: rem(10);
|
||||
}
|
||||
|
||||
.deal-container-buttons {
|
||||
gap: rem(10);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.top-panel {
|
||||
padding-bottom: rem(9);
|
||||
gap: rem(10);
|
||||
display: flex;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Drawer, rem } from "@mantine/core";
|
||||
import ExcelDropzone from "../../../../components/ExcelDropzone/ExcelDropzone.tsx";
|
||||
import styles from "../PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.module.css";
|
||||
import { usePrefillDealsWithExcelContext } from "../../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import ProductsPreview from "./components/ProductsPreview.tsx";
|
||||
|
||||
const PrefillDealsWithExcelDrawer = () => {
|
||||
const {
|
||||
prefillWithExcelOpened,
|
||||
prefillWithExcelOnClose,
|
||||
barcodeProductsMap,
|
||||
onDrop,
|
||||
excelDropzone,
|
||||
} = usePrefillDealsWithExcelContext();
|
||||
|
||||
const getBody = () => {
|
||||
if (barcodeProductsMap?.size === 0) {
|
||||
return <ExcelDropzone dropzone={excelDropzone} onDrop={onDrop} />;
|
||||
}
|
||||
return <ProductsPreview />;
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
size={"calc(77vw)"}
|
||||
position={"right"}
|
||||
onClose={prefillWithExcelOnClose}
|
||||
removeScrollProps={{ allowPinchZoom: true }}
|
||||
withCloseButton={false}
|
||||
opened={prefillWithExcelOpened}
|
||||
styles={{
|
||||
body: {
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: rem(20),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className={styles["deal-container"]}>
|
||||
{getBody()}
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrefillDealsWithExcelDrawer;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { ParsedCityBreakdownSchema } from "../../../../../client";
|
||||
import { useBreakdownByCityTableColumns } from "../hooks/useBreakdownByCityTableColumns.tsx";
|
||||
|
||||
type Props = {
|
||||
breakdowns: ParsedCityBreakdownSchema[];
|
||||
}
|
||||
|
||||
const BreakdownByCityTable = ({ breakdowns }: Props) => {
|
||||
const columns = useBreakdownByCityTableColumns();
|
||||
|
||||
return (
|
||||
<BaseTable
|
||||
data={breakdowns}
|
||||
columns={columns}
|
||||
w={"30%"}
|
||||
|
||||
restProps={{
|
||||
enableSorting: false,
|
||||
enableRowActions: false,
|
||||
enableTopToolbar: false,
|
||||
enableColumnActions: false,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default BreakdownByCityTable;
|
||||
@@ -0,0 +1,30 @@
|
||||
import { usePrefillDealsWithExcelContext } from "../../../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import { Text, Tooltip } from "@mantine/core";
|
||||
import { IconAlertCircle, IconCircleCheck } from "@tabler/icons-react";
|
||||
|
||||
const ParsingResultsTooltip = () => {
|
||||
const { errors } = usePrefillDealsWithExcelContext();
|
||||
const isError = errors.length !== 0;
|
||||
|
||||
const errorLines = errors.map((error, i) => <Text key={i}>{error}</Text>);
|
||||
const tooltipData = isError ? errorLines : "Ошибок при обработке нет";
|
||||
const color = isError ? "red" : "grey";
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
label={tooltipData}
|
||||
multiline
|
||||
w={350}
|
||||
withArrow
|
||||
color={color}
|
||||
>
|
||||
{isError ? (
|
||||
<IconAlertCircle color={"red"}/>
|
||||
) : (
|
||||
<IconCircleCheck color={"green"}/>
|
||||
)}
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default ParsingResultsTooltip;
|
||||
@@ -0,0 +1,68 @@
|
||||
import styles from "../PrefillDealsWithExcelDrawer.module.css";
|
||||
import ProductsTable from "./ProductsTable.tsx";
|
||||
import { usePrefillDealsWithExcelContext } from "../../../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import { Box, Button, Flex, Group, Stack, Title } from "@mantine/core";
|
||||
import { ProductExcelData } from "../types.tsx";
|
||||
import BreakdownByCityTable from "./BreakdownByCityTable.tsx";
|
||||
import ClientSelect from "../../../../../components/Selects/ClientSelect/ClientSelect.tsx";
|
||||
import ParsingResultsTooltip from "./ParsingResultsTooltip.tsx";
|
||||
|
||||
const ProductsPreview = () => {
|
||||
const { barcodeProductsMap, createDeals, form } = usePrefillDealsWithExcelContext();
|
||||
|
||||
const getTitle = (barcode: string, productsData: ProductExcelData) => {
|
||||
if (productsData.products.length === 1) {
|
||||
return `Товар со штрихкодом ${barcode}`;
|
||||
}
|
||||
return `Товары со штрихкодом ${barcode}`;
|
||||
};
|
||||
|
||||
const getProductsData = () => {
|
||||
return barcodeProductsMap.entries().map(([barcode, productsData]) => (
|
||||
<div key={barcode} className={styles["deal-container-wrapper"]}>
|
||||
<Stack>
|
||||
<Title order={5}>
|
||||
{getTitle(barcode, productsData)}
|
||||
</Title>
|
||||
<Flex direction={"row"} gap={"md"} flex={10}>
|
||||
<Box flex={7}>
|
||||
<ProductsTable barcode={barcode} productsData={productsData} />
|
||||
</Box>
|
||||
<Box flex={3}>
|
||||
<BreakdownByCityTable breakdowns={productsData.breakdowns} />
|
||||
</Box>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</div>
|
||||
),
|
||||
).toArray();
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack gap={"md"}>
|
||||
<Title order={3}>Предпросмотр</Title>
|
||||
<form onSubmit={form.onSubmit((values) => createDeals(values))}>
|
||||
<ClientSelect
|
||||
{...form.getInputProps("client")}
|
||||
inputContainer={(children) => (
|
||||
<Group align={"flex-start"}>
|
||||
{children}
|
||||
<Group>
|
||||
<Button
|
||||
variant="outline"
|
||||
type="submit"
|
||||
>
|
||||
Создать сделки
|
||||
</Button>
|
||||
<ParsingResultsTooltip />
|
||||
</Group>
|
||||
</Group>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
{getProductsData()}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductsPreview;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { useProductsTableColumns } from "../hooks/useProductsTableColumns.tsx";
|
||||
import { ProductExcelData } from "../types.tsx";
|
||||
|
||||
type Props = {
|
||||
barcode: string;
|
||||
productsData: ProductExcelData;
|
||||
}
|
||||
|
||||
const ProductsTable = ({ barcode, productsData }: Props) => {
|
||||
const columns = useProductsTableColumns({ barcode });
|
||||
|
||||
return (
|
||||
<BaseTable
|
||||
data={productsData.products}
|
||||
columns={columns}
|
||||
w={"100%"}
|
||||
|
||||
restProps={{
|
||||
enableSorting: false,
|
||||
enableRowActions: false,
|
||||
enableTopToolbar: false,
|
||||
enableColumnActions: false,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProductsTable;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useMemo } from "react";
|
||||
import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { ParsedCityBreakdownSchema } from "../../../../../client";
|
||||
import { ActionIcon, Image } from "@mantine/core";
|
||||
|
||||
export const useBreakdownByCityTableColumns = () => {
|
||||
return useMemo<MRT_ColumnDef<ParsedCityBreakdownSchema>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "baseMarketplace.iconUrl",
|
||||
header: "Маркетплейс",
|
||||
Cell: ({ cell }) => (
|
||||
<ActionIcon
|
||||
radius={"md"}
|
||||
variant={"transparent"}>
|
||||
<Image src={cell.getValue()} />
|
||||
</ActionIcon>
|
||||
),
|
||||
size: 10,
|
||||
},
|
||||
{
|
||||
accessorKey: "shippingWarehouse.name",
|
||||
header: "Склад отгрузки",
|
||||
size: 10,
|
||||
},
|
||||
{
|
||||
accessorKey: "quantity",
|
||||
header: "Количество",
|
||||
size: 10,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { ProductSchema } from "../../../../../client";
|
||||
import { Radio } from "@mantine/core";
|
||||
import { usePrefillDealsWithExcelContext } from "../../../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import { ProductExcelData } from "../types.tsx";
|
||||
|
||||
type Props = {
|
||||
barcode: string;
|
||||
}
|
||||
|
||||
export const useProductsTableColumns = ({ barcode }: Props) => {
|
||||
const { onProductSelectChange, barcodeProductsMap } = usePrefillDealsWithExcelContext();
|
||||
const [productData, setProductData] = useState<ProductExcelData>();
|
||||
|
||||
useEffect(() => {
|
||||
setProductData(barcodeProductsMap.get(barcode));
|
||||
}, [barcodeProductsMap]);
|
||||
|
||||
return useMemo<MRT_ColumnDef<ProductSchema>[]>(
|
||||
() => [
|
||||
{
|
||||
header: "Выбор",
|
||||
size: 10,
|
||||
Cell: ({ row }) => {
|
||||
return (
|
||||
<Radio
|
||||
checked={productData?.selectedProduct?.id === row.original.id}
|
||||
onChange={() => onProductSelectChange(barcode, row.original)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "article",
|
||||
header: "Артикул",
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название",
|
||||
},
|
||||
{
|
||||
accessorKey: "brand",
|
||||
header: "Бренд",
|
||||
size: 30,
|
||||
},
|
||||
{
|
||||
accessorKey: "color",
|
||||
header: "Цвет",
|
||||
size: 30,
|
||||
},
|
||||
{
|
||||
accessorKey: "size",
|
||||
header: "Размер",
|
||||
size: 10,
|
||||
},
|
||||
],
|
||||
[productData],
|
||||
).filter(columnDef => (
|
||||
!(columnDef.header === "Выбор" && (productData?.products.length ?? 0) === 1)
|
||||
));
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ClientSchema, type ParsedCityBreakdownSchema, ProductSchema } from "../../../../client";
|
||||
|
||||
export type ProductExcelData = {
|
||||
products: ProductSchema[];
|
||||
breakdowns: ParsedCityBreakdownSchema[];
|
||||
selectedProduct?: ProductSchema;
|
||||
}
|
||||
|
||||
export type DealsWithExcelForm = {
|
||||
client?: ClientSchema;
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import { dateWithoutTimezone } from "../../../shared/lib/date.ts";
|
||||
import DealPrefillDrawer from "../drawers/DealPrefillDrawer/DealPrefillDrawer.tsx";
|
||||
import { PrefillDealContextProvider } from "../contexts/PrefillDealContext.tsx";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { PrefillDealsWithExcelContextProvider } from "../contexts/PrefillDealsWithExcelContext.tsx";
|
||||
import PrefillDealsWithExcelDrawer from "../drawers/PrefillDealWithExcelDrawer/PrefillDealsWithExcelDrawer.tsx";
|
||||
|
||||
enum DisplayMode {
|
||||
BOARD,
|
||||
@@ -401,101 +403,104 @@ export const LeadsPage: FC = () => {
|
||||
await refetch();
|
||||
}}>
|
||||
<PrefillDealContextProvider>
|
||||
<PageBlock style={{ flex: 0 }}>
|
||||
<Flex
|
||||
align={"center"}
|
||||
justify={"space-between"}>
|
||||
<PrefillDealsWithExcelContextProvider>
|
||||
<PageBlock style={{ flex: 0 }}>
|
||||
<Flex
|
||||
gap={rem(10)}
|
||||
direction={"column"}
|
||||
align={"center"}>
|
||||
<Text size={"xs"}>Вид</Text>
|
||||
<Flex gap={rem(10)}>
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
setDisplayMode(DisplayMode.BOARD)
|
||||
}
|
||||
variant={
|
||||
displayMode === DisplayMode.BOARD
|
||||
? "filled"
|
||||
: "default"
|
||||
}>
|
||||
<IconMenuDeep
|
||||
style={{ rotate: "-90deg" }}
|
||||
/>
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
setDisplayMode(DisplayMode.TABLE)
|
||||
}
|
||||
variant={
|
||||
displayMode === DisplayMode.TABLE
|
||||
? "filled"
|
||||
: "default"
|
||||
}>
|
||||
<IconMenu2 />
|
||||
</ActionIcon>
|
||||
align={"center"}
|
||||
justify={"space-between"}>
|
||||
<Flex
|
||||
gap={rem(10)}
|
||||
direction={"column"}
|
||||
align={"center"}>
|
||||
<Text size={"xs"}>Вид</Text>
|
||||
<Flex gap={rem(10)}>
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
setDisplayMode(DisplayMode.BOARD)
|
||||
}
|
||||
variant={
|
||||
displayMode === DisplayMode.BOARD
|
||||
? "filled"
|
||||
: "default"
|
||||
}>
|
||||
<IconMenuDeep
|
||||
style={{ rotate: "-90deg" }}
|
||||
/>
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
setDisplayMode(DisplayMode.TABLE)
|
||||
}
|
||||
variant={
|
||||
displayMode === DisplayMode.TABLE
|
||||
? "filled"
|
||||
: "default"
|
||||
}>
|
||||
<IconMenu2 />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<motion.div
|
||||
key={displayMode}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}>
|
||||
<div
|
||||
className={styles["top-panel"]}
|
||||
style={{
|
||||
display:
|
||||
displayMode === DisplayMode.TABLE
|
||||
? "flex"
|
||||
: "none",
|
||||
}}>
|
||||
<NumberInput
|
||||
min={1}
|
||||
placeholder={"Введите номер"}
|
||||
{...form.getInputProps("id")}
|
||||
hideControls
|
||||
/>
|
||||
<DealStatusSelect
|
||||
onClear={() =>
|
||||
form.setFieldValue("dealStatus", null)
|
||||
}
|
||||
clearable
|
||||
placeholder={"Выберите статус "}
|
||||
{...form.getInputProps("dealStatus")}
|
||||
/>
|
||||
<BaseMarketplaceSelect
|
||||
onClear={() =>
|
||||
form.setFieldValue("marketplace", null)
|
||||
}
|
||||
clearable
|
||||
placeholder={"Выберите маркетплейс"}
|
||||
{...form.getInputProps("marketplace")}
|
||||
/>
|
||||
<ClientSelectNew
|
||||
onClear={() =>
|
||||
form.setFieldValue("client", null)
|
||||
}
|
||||
clearable
|
||||
searchable
|
||||
placeholder={"Выберите клиента"}
|
||||
{...form.getInputProps("client")}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Flex>
|
||||
<motion.div
|
||||
key={displayMode}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}>
|
||||
<div
|
||||
className={styles["top-panel"]}
|
||||
style={{
|
||||
display:
|
||||
displayMode === DisplayMode.TABLE
|
||||
? "flex"
|
||||
: "none",
|
||||
}}>
|
||||
<NumberInput
|
||||
min={1}
|
||||
placeholder={"Введите номер"}
|
||||
{...form.getInputProps("id")}
|
||||
hideControls
|
||||
/>
|
||||
<DealStatusSelect
|
||||
onClear={() =>
|
||||
form.setFieldValue("dealStatus", null)
|
||||
}
|
||||
clearable
|
||||
placeholder={"Выберите статус "}
|
||||
{...form.getInputProps("dealStatus")}
|
||||
/>
|
||||
<BaseMarketplaceSelect
|
||||
onClear={() =>
|
||||
form.setFieldValue("marketplace", null)
|
||||
}
|
||||
clearable
|
||||
placeholder={"Выберите маркетплейс"}
|
||||
{...form.getInputProps("marketplace")}
|
||||
/>
|
||||
<ClientSelectNew
|
||||
onClear={() =>
|
||||
form.setFieldValue("client", null)
|
||||
}
|
||||
clearable
|
||||
searchable
|
||||
placeholder={"Выберите клиента"}
|
||||
{...form.getInputProps("client")}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Flex>
|
||||
</PageBlock>
|
||||
<PageBlock
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: 1,
|
||||
height: "100%",
|
||||
}}>
|
||||
{getBody()}
|
||||
</PageBlock>
|
||||
<DealEditDrawer />
|
||||
<DealPrefillDrawer />
|
||||
</PageBlock>
|
||||
<PageBlock
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: 1,
|
||||
height: "100%",
|
||||
}}>
|
||||
{getBody()}
|
||||
</PageBlock>
|
||||
<DealEditDrawer />
|
||||
<DealPrefillDrawer />
|
||||
<PrefillDealsWithExcelDrawer />
|
||||
</PrefillDealsWithExcelContextProvider>
|
||||
</PrefillDealContextProvider>
|
||||
</DealPageContextProvider>
|
||||
</PageBlock>
|
||||
|
||||
Reference in New Issue
Block a user