fix: cards fetch optimization
This commit is contained in:
@@ -252,6 +252,7 @@ export type { GetBoardsResponse } from './models/GetBoardsResponse';
|
||||
export type { GetCardBillById } from './models/GetCardBillById';
|
||||
export type { GetCardProductsBarcodesPdfRequest } from './models/GetCardProductsBarcodesPdfRequest';
|
||||
export type { GetCardProductsBarcodesPdfResponse } from './models/GetCardProductsBarcodesPdfResponse';
|
||||
export type { GetCardSummariesRequest } from './models/GetCardSummariesRequest';
|
||||
export type { GetChatRequest } from './models/GetChatRequest';
|
||||
export type { GetChatResponse } from './models/GetChatResponse';
|
||||
export type { GetClientMarketplacesRequest } from './models/GetClientMarketplacesRequest';
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { CardSummary } from './CardSummary';
|
||||
import type { PaginationInfoSchema } from './PaginationInfoSchema';
|
||||
export type CardSummaryResponse = {
|
||||
summaries: Array<CardSummary>;
|
||||
paginationInfo: PaginationInfoSchema;
|
||||
};
|
||||
|
||||
|
||||
16
src/client/models/GetCardSummariesRequest.ts
Normal file
16
src/client/models/GetCardSummariesRequest.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/* generated using openapi-typescript-codegen -- do not edit */
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type GetCardSummariesRequest = {
|
||||
full: boolean;
|
||||
cardId?: (number | string | null);
|
||||
cardName?: (string | null);
|
||||
marketplaceKey?: (string | null);
|
||||
shippingWarehouseId?: (number | null);
|
||||
clientId?: (number | null);
|
||||
projectId?: (number | null);
|
||||
boardId?: (number | null);
|
||||
statusId?: (number | null);
|
||||
};
|
||||
|
||||
@@ -56,6 +56,7 @@ import type { CreateCardsFromExcelResponse } from '../models/CreateCardsFromExce
|
||||
import type { GetAvailableEmployeesToAssignResponse } from '../models/GetAvailableEmployeesToAssignResponse';
|
||||
import type { GetCardProductsBarcodesPdfRequest } from '../models/GetCardProductsBarcodesPdfRequest';
|
||||
import type { GetCardProductsBarcodesPdfResponse } from '../models/GetCardProductsBarcodesPdfResponse';
|
||||
import type { GetCardSummariesRequest } from '../models/GetCardSummariesRequest';
|
||||
import type { ManageEmployeeRequest } from '../models/ManageEmployeeRequest';
|
||||
import type { ManageEmployeeResponse } from '../models/ManageEmployeeResponse';
|
||||
import type { ParseCardsExcelResponse } from '../models/ParseCardsExcelResponse';
|
||||
@@ -155,16 +156,23 @@ export class CardService {
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static getCardSummaries({
|
||||
full,
|
||||
requestBody,
|
||||
page,
|
||||
itemsPerPage,
|
||||
}: {
|
||||
full: (boolean | null),
|
||||
requestBody: GetCardSummariesRequest,
|
||||
page?: (number | null),
|
||||
itemsPerPage?: (number | null),
|
||||
}): CancelablePromise<CardSummaryResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
method: 'POST',
|
||||
url: '/card/summaries',
|
||||
query: {
|
||||
'full': full,
|
||||
'page': page,
|
||||
'items_per_page': itemsPerPage,
|
||||
},
|
||||
body: requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: `Validation Error`,
|
||||
},
|
||||
|
||||
@@ -56,7 +56,11 @@ const CardAttributesInSummaryItem = ({ cardSummary }: Props) => {
|
||||
.map(cardAttr => {
|
||||
const isHighlight = isHighlightNeeded(cardAttr);
|
||||
return (
|
||||
<Text c={isHighlight ? "red" : "gray.6"} size={"sm"}>
|
||||
<Text
|
||||
key={cardAttr.attribute.id}
|
||||
c={isHighlight ? "red" : "gray.6"}
|
||||
size={"sm"}
|
||||
>
|
||||
{cardAttr.attribute.label}: {getAttrValueValue(cardAttr)}
|
||||
</Text>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import styles from "../../ui/CardsPage.module.css";
|
||||
import PageBlock from "../../../../components/PageBlock/PageBlock.tsx";
|
||||
import DisplayMode from "../../enums/DisplayMode.ts";
|
||||
import { UseFormReturnType } from "@mantine/form";
|
||||
import { CardsPageState } from "../../hooks/useCardsPageState.tsx";
|
||||
import { CardsPageState } from "../../hooks/useCardsTableForm.tsx";
|
||||
import React from "react";
|
||||
import ObjectSelect from "../../../../components/ObjectSelect/ObjectSelect.tsx";
|
||||
import CardsTableFiltersModal from "../../modals/CardsTableFiltersModal.tsx";
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
import { CRUDTableProps } from "../../../../types/CRUDTable.tsx";
|
||||
import { CardService, CardSummary } from "../../../../client";
|
||||
import { FC } from "react";
|
||||
import { FC, useEffect, useRef } from "react";
|
||||
import useCardsTableColumns from "./columns.tsx";
|
||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
|
||||
import { ActionIcon, Flex, Group, Pagination, Stack, Tooltip } from "@mantine/core";
|
||||
import { IconEdit } from "@tabler/icons-react";
|
||||
import { MRT_TableOptions } from "mantine-react-table";
|
||||
import { useCardPageContext } from "../../contexts/CardPageContext.tsx";
|
||||
import useCardSummaries from "../../hooks/useCardSummaries.tsx";
|
||||
import { CardsPageState } from "../../hooks/useCardsTableForm.tsx";
|
||||
import { UseFormReturnType } from "@mantine/form";
|
||||
import { useDebouncedValue } from "@mantine/hooks";
|
||||
|
||||
type RestProps = {
|
||||
viewOnly?: boolean;
|
||||
form: UseFormReturnType<CardsPageState>;
|
||||
};
|
||||
type Props = CRUDTableProps<CardSummary> & RestProps;
|
||||
type Props = Omit<CRUDTableProps<CardSummary>, "items"> & RestProps;
|
||||
|
||||
const CardsTable: FC<Props> = ({ form, onSelectionChange, viewOnly = false }) => {
|
||||
const [debouncedForm] = useDebouncedValue(form, 300);
|
||||
const prevDebouncedValues = useRef(debouncedForm?.values);
|
||||
|
||||
const CardsTable: FC<Props> = ({ items, onSelectionChange, viewOnly = false }) => {
|
||||
const columns = useCardsTableColumns();
|
||||
const { setSelectedCard } = useCardPageContext();
|
||||
const onEditClick = (cardSummary: CardSummary) => {
|
||||
@@ -22,35 +30,65 @@ const CardsTable: FC<Props> = ({ items, onSelectionChange, viewOnly = false }) =
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
summaries,
|
||||
fetchSummaries,
|
||||
totalPages,
|
||||
page,
|
||||
setPage,
|
||||
} = useCardSummaries({
|
||||
full: true,
|
||||
values: form?.values,
|
||||
withPagination: true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (prevDebouncedValues.current !== debouncedForm.values) {
|
||||
prevDebouncedValues.current = debouncedForm.values;
|
||||
setPage(1);
|
||||
}
|
||||
fetchSummaries();
|
||||
}, [debouncedForm.values, page]);
|
||||
|
||||
return (
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
onSelectionChange={onSelectionChange}
|
||||
restProps={
|
||||
{
|
||||
enableSorting: true,
|
||||
enableColumnActions: false,
|
||||
enablePagination: !viewOnly,
|
||||
enableBottomToolbar: !viewOnly,
|
||||
paginationDisplayMode: "pages",
|
||||
enableRowActions: true,
|
||||
enableRowSelection: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
disabled={viewOnly}
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<CardSummary>
|
||||
}
|
||||
/>
|
||||
<Stack>
|
||||
<BaseTable
|
||||
data={summaries}
|
||||
columns={columns}
|
||||
onSelectionChange={onSelectionChange}
|
||||
restProps={
|
||||
{
|
||||
enableSorting: true,
|
||||
enableColumnActions: false,
|
||||
paginationDisplayMode: "pages",
|
||||
enableRowActions: true,
|
||||
enableRowSelection: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
disabled={viewOnly}
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<CardSummary>
|
||||
}
|
||||
/>
|
||||
{!viewOnly && (
|
||||
<Group justify={"flex-end"}>
|
||||
<Pagination
|
||||
withEdges
|
||||
total={totalPages}
|
||||
value={page}
|
||||
onChange={setPage}
|
||||
/>
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CardSchema, CardService } from "../../../client";
|
||||
type CardPageContextState = {
|
||||
selectedCard?: CardSchema;
|
||||
setSelectedCard: (card: CardSchema | undefined) => void;
|
||||
refetchCards: () => Promise<void>;
|
||||
refetchCards: () => void;
|
||||
refetchCard: () => void;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ const CardPageContext = createContext<CardPageContextState | undefined>(
|
||||
);
|
||||
|
||||
type CardPageContextStateProps = {
|
||||
refetchCards: () => Promise<void>;
|
||||
refetchCards: () => void;
|
||||
defaultCardId?: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,8 @@ const PrefillCardContext = createContext<PrefillCardContextState | undefined>(
|
||||
undefined
|
||||
);
|
||||
const usePrefillCardContextState = () => {
|
||||
const [selectedPrefillCard, setSelectedPrefillCard] = useState<CardSchema | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [prefillCard, setPrefillCard] = useState<CardSchema | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [selectedPrefillCard, setSelectedPrefillCard] = useState<CardSchema | undefined>(undefined);
|
||||
const [prefillCard, setPrefillCard] = useState<CardSchema | undefined>(undefined);
|
||||
const [prefillOpened, { open, close }] = useDisclosure(false);
|
||||
const prefillOnClose = close;
|
||||
const prefillOnOpen = open;
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
import { FC, useEffect } from "react";
|
||||
import { Button, Drawer, Flex, rem, TextInput } from "@mantine/core";
|
||||
import CardsTable from "./components/tables/CardsTable/CardsTable.tsx";
|
||||
import Preview from "./components/Preview/Preview.tsx";
|
||||
import styles from "./CardPrefillDrawer.module.css";
|
||||
import BaseMarketplaceSelect from "../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
|
||||
import usePrefillCard from "./hooks/usePrefillCard.tsx";
|
||||
import { notifications } from "../../../../shared/lib/notifications.ts";
|
||||
import { FC } from "react";
|
||||
import { Drawer, rem } from "@mantine/core";
|
||||
import { usePrefillCardContext } from "../../contexts/PrefillCardContext.tsx";
|
||||
import CardPrefillDrawerContent from "./components/CardPrefillDrawerContent/CardPrefillDrawerContent.tsx";
|
||||
|
||||
const CardPrefillDrawer: FC = () => {
|
||||
const { prefillOpened, prefillOnClose, selectedPrefillCard, setPrefillCard, prefillCard } = usePrefillCardContext();
|
||||
const { data, form } = usePrefillCard();
|
||||
|
||||
useEffect(() => {
|
||||
if (prefillOpened) return;
|
||||
}, [prefillOpened]);
|
||||
const { prefillOpened, prefillOnClose } = usePrefillCardContext();
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
@@ -33,48 +23,7 @@ const CardPrefillDrawer: FC = () => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className={styles["card-container"]}>
|
||||
<div className={styles["card-container-wrapper"]}>
|
||||
<div className={styles["top-panel"]}>
|
||||
<TextInput
|
||||
placeholder={"Введите название / id"}
|
||||
{...form.getInputProps("idOrName")}
|
||||
/>
|
||||
<BaseMarketplaceSelect
|
||||
onClear={() =>
|
||||
form.setFieldValue("marketplace", null)
|
||||
}
|
||||
clearable
|
||||
placeholder={"Выберите маркетплейс"}
|
||||
{...form.getInputProps("marketplace")}
|
||||
/>
|
||||
</div>
|
||||
<CardsTable items={data} />
|
||||
<Flex direction={"row"} gap="sm">
|
||||
<Button mt={10} w={"100%"} onClick={() => {
|
||||
if (!selectedPrefillCard) {
|
||||
notifications.error({ message: "Карточка не выбрана." });
|
||||
return;
|
||||
}
|
||||
setPrefillCard(selectedPrefillCard);
|
||||
prefillOnClose();
|
||||
}}>
|
||||
Предзаполнить
|
||||
</Button>
|
||||
{
|
||||
prefillCard &&
|
||||
<Button mt={10} w={"100%"} variant={"outline"} onClick={() => {
|
||||
setPrefillCard(undefined);
|
||||
notifications.success({ message: "Предзаполнение отменено." });
|
||||
prefillOnClose();
|
||||
}}>
|
||||
Отменить предзаполнение
|
||||
</Button>
|
||||
}
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
<Preview />
|
||||
<CardPrefillDrawerContent />
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import styles from "../../CardPrefillDrawer.module.css";
|
||||
import { Button, Flex, TextInput } from "@mantine/core";
|
||||
import BaseMarketplaceSelect
|
||||
from "../../../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
|
||||
import CardsTable from "../tables/CardsTable/CardsTable.tsx";
|
||||
import { notifications } from "../../../../../../shared/lib/notifications.ts";
|
||||
import Preview from "../Preview/Preview.tsx";
|
||||
import usePrefillCard from "../../hooks/usePrefillCard.tsx";
|
||||
import { usePrefillCardContext } from "../../../../contexts/PrefillCardContext.tsx";
|
||||
|
||||
|
||||
const CardPrefillDrawerContent = () => {
|
||||
const { prefillOnClose, selectedPrefillCard, setPrefillCard, prefillCard } = usePrefillCardContext();
|
||||
const {
|
||||
summaries,
|
||||
idOrName,
|
||||
setIdOrName,
|
||||
marketplace,
|
||||
setMarketplace,
|
||||
totalPages,
|
||||
page,
|
||||
setPage,
|
||||
} = usePrefillCard();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles["card-container"]}>
|
||||
<div className={styles["card-container-wrapper"]}>
|
||||
<div className={styles["top-panel"]}>
|
||||
<TextInput
|
||||
placeholder={"Введите название / id"}
|
||||
value={idOrName}
|
||||
onChange={e => setIdOrName(e.target.value)}
|
||||
/>
|
||||
<BaseMarketplaceSelect
|
||||
onClear={() => setMarketplace(null)}
|
||||
clearable
|
||||
placeholder={"Выберите маркетплейс"}
|
||||
value={marketplace || undefined}
|
||||
onChange={setMarketplace}
|
||||
/>
|
||||
</div>
|
||||
<CardsTable
|
||||
items={summaries}
|
||||
totalPages={totalPages}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
/>
|
||||
<Flex direction={"row"} gap="sm">
|
||||
<Button mt={10} w={"100%"} onClick={() => {
|
||||
if (!selectedPrefillCard) {
|
||||
notifications.error({ message: "Карточка не выбрана." });
|
||||
return;
|
||||
}
|
||||
setPrefillCard(selectedPrefillCard);
|
||||
prefillOnClose();
|
||||
}}>
|
||||
Предзаполнить
|
||||
</Button>
|
||||
{
|
||||
prefillCard &&
|
||||
<Button mt={10} w={"100%"} variant={"outline"} onClick={() => {
|
||||
setPrefillCard(undefined);
|
||||
notifications.success({ message: "Предзаполнение отменено." });
|
||||
prefillOnClose();
|
||||
}}>
|
||||
Отменить предзаполнение
|
||||
</Button>
|
||||
}
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
<Preview />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardPrefillDrawerContent;
|
||||
@@ -1,47 +1,62 @@
|
||||
import { FC, useEffect } from "react";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import useCardsTableColumns from "./columns.tsx";
|
||||
import { CardSummary } from "../../../../../../../client";
|
||||
import { BaseTable } from "../../../../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { usePrefillCardContext } from "../../../../../contexts/PrefillCardContext.tsx";
|
||||
import { Group, Pagination, Stack } from "@mantine/core";
|
||||
|
||||
type Props = {
|
||||
items: CardSummary[];
|
||||
totalPages: number;
|
||||
page: number;
|
||||
setPage: (page: number) => void;
|
||||
};
|
||||
|
||||
const CardsTable: FC<Props> = ({ items }) => {
|
||||
const CardsTable: FC<Props> = ({ items, totalPages, page, setPage }) => {
|
||||
const { selectPrefillCard } = usePrefillCardContext();
|
||||
const columns = useCardsTableColumns();
|
||||
const defaultSorting = [{ id: "createdAt", desc: false }];
|
||||
const [isInitial, setIsInitial] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (items.length < 1) return;
|
||||
selectPrefillCard(items[0].id);
|
||||
}, []);
|
||||
if (isInitial && items.length > 0) {
|
||||
selectPrefillCard(items[0].id);
|
||||
setIsInitial(false);
|
||||
}
|
||||
}, [items]);
|
||||
|
||||
return (
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
<Stack gap={"xs"}>
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
|
||||
restProps={
|
||||
{
|
||||
enableSorting: true,
|
||||
enableColumnActions: false,
|
||||
enablePagination: true,
|
||||
enableBottomToolbar: true,
|
||||
paginationDisplayMode: "pages",
|
||||
initialState: {
|
||||
sorting: defaultSorting,
|
||||
},
|
||||
mantinePaginationProps: {
|
||||
showRowsPerPage: false,
|
||||
},
|
||||
enableStickyHeader: true,
|
||||
enableStickyFooter: true,
|
||||
mantineTableContainerProps: { style: { maxHeight: "81vh", height: "81vh" } },
|
||||
restProps={
|
||||
{
|
||||
enableSorting: true,
|
||||
enableColumnActions: false,
|
||||
paginationDisplayMode: "pages",
|
||||
initialState: {
|
||||
sorting: defaultSorting,
|
||||
},
|
||||
mantinePaginationProps: {
|
||||
showRowsPerPage: false,
|
||||
},
|
||||
enableStickyHeader: true,
|
||||
enableStickyFooter: true,
|
||||
mantineTableContainerProps: { style: { maxHeight: "81vh", height: "81vh" } },
|
||||
}
|
||||
}
|
||||
}
|
||||
/>
|
||||
/>
|
||||
<Group justify={"flex-end"}>
|
||||
<Pagination
|
||||
withEdges
|
||||
total={totalPages}
|
||||
value={page}
|
||||
onChange={setPage}
|
||||
/>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,56 +1,58 @@
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { BaseMarketplaceSchema } from "../../../../../client";
|
||||
import { useCardSummariesFull } from "../../../hooks/useCardSummaries.tsx";
|
||||
import isModuleInProject from "../../../../../modules/utils/isModuleInProject.ts";
|
||||
import { ModuleNames } from "../../../../../modules/modules.tsx";
|
||||
import useCardSummaries from "../../../hooks/useCardSummaries.tsx";
|
||||
import { useDebouncedValue } from "@mantine/hooks";
|
||||
|
||||
type State = {
|
||||
idOrName: string | null;
|
||||
marketplace: BaseMarketplaceSchema | null;
|
||||
};
|
||||
|
||||
const usePrefillCard = () => {
|
||||
const { objects } = useCardSummariesFull();
|
||||
const form = useForm<State>({
|
||||
initialValues: {
|
||||
idOrName: null,
|
||||
marketplace: null,
|
||||
},
|
||||
});
|
||||
const [data, setData] = useState(objects);
|
||||
const [idOrName, setIdOrName] = useState<string>("");
|
||||
const [debouncedIdOrName] = useDebouncedValue(idOrName, 500);
|
||||
const prevIdOrName = useRef(idOrName);
|
||||
const [marketplace, setMarketplace] = useState<BaseMarketplaceSchema | null>(null);
|
||||
const prevMarketplace = useRef(marketplace);
|
||||
|
||||
const applyFilters = () => {
|
||||
let result = objects;
|
||||
const getValues = () => {
|
||||
let id: number | null = parseInt(debouncedIdOrName || "");
|
||||
if (isNaN(id)) id = null;
|
||||
|
||||
result = result.filter(obj => isModuleInProject(ModuleNames.SERVICES_AND_PRODUCTS, obj.board.project));
|
||||
|
||||
if (form.values.idOrName) {
|
||||
if (isNaN(parseInt(form.values.idOrName))) {
|
||||
const name: string = form.values.idOrName.toLowerCase();
|
||||
result = result.filter(
|
||||
obj => obj.name.toLowerCase().search(name) !== -1,
|
||||
);
|
||||
} else {
|
||||
const id = parseInt(form.values.idOrName);
|
||||
result = result.filter(
|
||||
obj => obj.id === id,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (form.values.marketplace) {
|
||||
result = result.filter(
|
||||
obj => obj.baseMarketplace?.key === form.values.marketplace?.key,
|
||||
);
|
||||
}
|
||||
setData(result);
|
||||
return {
|
||||
cardId: id,
|
||||
cardName: id ? null : debouncedIdOrName,
|
||||
marketplace,
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
applyFilters();
|
||||
}, [form.values, objects]);
|
||||
const {
|
||||
summaries,
|
||||
fetchSummaries,
|
||||
totalPages,
|
||||
page,
|
||||
setPage,
|
||||
} = useCardSummaries({
|
||||
full: true,
|
||||
values: getValues(),
|
||||
withPagination: true,
|
||||
});
|
||||
|
||||
return { data, form };
|
||||
useEffect(() => {
|
||||
if (prevIdOrName.current !== debouncedIdOrName || prevMarketplace.current !== marketplace) {
|
||||
prevIdOrName.current = debouncedIdOrName;
|
||||
prevMarketplace.current = marketplace;
|
||||
setPage(1);
|
||||
}
|
||||
fetchSummaries();
|
||||
}, [debouncedIdOrName, marketplace, page]);
|
||||
|
||||
return {
|
||||
summaries,
|
||||
idOrName,
|
||||
setIdOrName,
|
||||
marketplace,
|
||||
setMarketplace,
|
||||
totalPages,
|
||||
page,
|
||||
setPage,
|
||||
};
|
||||
};
|
||||
|
||||
export default usePrefillCard;
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { CardService } from "../../../client";
|
||||
import ObjectList from "../../../hooks/objectList.tsx";
|
||||
import { useState } from "react";
|
||||
import { CardService, CardSummary } from "../../../client";
|
||||
import { CardsPageState } from "./useCardsTableForm.tsx";
|
||||
|
||||
export const useCardSummaries = () => {
|
||||
const { data: summariesRaw = [], refetch } = useQuery({
|
||||
queryKey: ["getCardSummaries"],
|
||||
queryFn: () => CardService.getCardSummaries({ full: false }),
|
||||
select: data => data.summaries || [], // Трансформируем полученные данные
|
||||
});
|
||||
|
||||
// Теперь summaries будет содержать либо трансформированные данные, либо пустой массив по умолчанию
|
||||
// isLoading и isError могут быть использованы для отображения индикаторов загрузки или ошибки
|
||||
type Props = {
|
||||
full: boolean;
|
||||
values?: CardsPageState;
|
||||
withPagination?: boolean;
|
||||
itemsPerPage?: number;
|
||||
}
|
||||
|
||||
return { summariesRaw, refetch };
|
||||
const useCardSummaries = ({ full, values, withPagination = false, itemsPerPage = 10 }: Props) => {
|
||||
const [summaries, setSummaries] = useState<CardSummary[]>([]);
|
||||
const [page, setPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
|
||||
const fetchSummaries = () => {
|
||||
CardService.getCardSummaries({
|
||||
page: withPagination ? page : null,
|
||||
itemsPerPage: withPagination ? itemsPerPage : null,
|
||||
requestBody: {
|
||||
full,
|
||||
cardId: values?.cardId,
|
||||
cardName: values?.cardName,
|
||||
marketplaceKey: values?.marketplace?.key,
|
||||
shippingWarehouseId: values?.shippingWarehouse?.id,
|
||||
clientId: values?.client?.id,
|
||||
projectId: values?.project?.id,
|
||||
boardId: values?.board?.id,
|
||||
statusId: values?.status?.id,
|
||||
},
|
||||
})
|
||||
.then(({ summaries, paginationInfo }) => {
|
||||
setSummaries(summaries);
|
||||
setTotalPages(paginationInfo.totalPages);
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
};
|
||||
|
||||
return {
|
||||
summaries,
|
||||
fetchSummaries,
|
||||
page,
|
||||
setPage,
|
||||
totalPages,
|
||||
};
|
||||
};
|
||||
export const useCardSummariesFull = () =>
|
||||
ObjectList({
|
||||
queryFn: () => CardService.getCardSummaries({ full: true }),
|
||||
queryKey: "getCardSummariesFull",
|
||||
getObjectsFn: response => response.summaries,
|
||||
});
|
||||
|
||||
export default useCardSummaries;
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { useCardSummariesFull } from "./useCardSummaries.tsx";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useEffect, useState } from "react";
|
||||
import { BaseMarketplaceSchema, BoardSchema, ClientSchema, ProjectSchema, StatusSchema } from "../../../client";
|
||||
|
||||
export type CardsPageState = {
|
||||
id: number | null;
|
||||
marketplace: BaseMarketplaceSchema | null;
|
||||
client: ClientSchema | null;
|
||||
|
||||
projectForTable: ProjectSchema | null;
|
||||
board: BoardSchema | null;
|
||||
status: StatusSchema | null;
|
||||
};
|
||||
|
||||
const useCardsPageState = () => {
|
||||
const { objects } = useCardSummariesFull();
|
||||
|
||||
const form = useForm<CardsPageState>({
|
||||
initialValues: {
|
||||
id: null,
|
||||
marketplace: null,
|
||||
client: null,
|
||||
|
||||
projectForTable: null,
|
||||
board: null,
|
||||
status: null,
|
||||
},
|
||||
});
|
||||
|
||||
const [data, setData] = useState(objects);
|
||||
|
||||
const applyFilters = () => {
|
||||
let result = objects;
|
||||
if (form.values.id) {
|
||||
result = result.filter(
|
||||
obj => obj.id === form.values.id,
|
||||
);
|
||||
}
|
||||
if (form.values.marketplace) {
|
||||
result = result.filter(
|
||||
obj => obj.baseMarketplace?.key === form.values.marketplace?.key,
|
||||
);
|
||||
}
|
||||
if (form.values.projectForTable) {
|
||||
result = result.filter(
|
||||
obj => obj.board.projectId === form.values.projectForTable?.id,
|
||||
);
|
||||
|
||||
if (form.values.board) {
|
||||
result = result.filter(
|
||||
obj => obj.board.id === form.values.board?.id,
|
||||
);
|
||||
|
||||
if (form.values.status) {
|
||||
result = result.filter(
|
||||
obj => obj.status.id === form.values.status?.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (form.values.client) {
|
||||
result = result.filter(
|
||||
obj => obj.clientName === form.values.client?.name,
|
||||
);
|
||||
}
|
||||
setData(result);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
applyFilters();
|
||||
}, [form.values, objects]);
|
||||
|
||||
return { data, form };
|
||||
};
|
||||
|
||||
export default useCardsPageState;
|
||||
39
src/pages/CardsPage/hooks/useCardsTableForm.tsx
Normal file
39
src/pages/CardsPage/hooks/useCardsTableForm.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useForm } from "@mantine/form";
|
||||
import {
|
||||
BaseMarketplaceSchema,
|
||||
BoardSchema,
|
||||
ClientSchema,
|
||||
ProjectSchema,
|
||||
ShippingWarehouseSchema,
|
||||
StatusSchema,
|
||||
} from "../../../client";
|
||||
|
||||
export type CardsPageState = {
|
||||
cardId?: number | null;
|
||||
cardName?: string | null;
|
||||
marketplace?: BaseMarketplaceSchema | null;
|
||||
shippingWarehouse?: ShippingWarehouseSchema | null;
|
||||
client?: ClientSchema | null;
|
||||
|
||||
project?: ProjectSchema | null;
|
||||
board?: BoardSchema | null;
|
||||
status?: StatusSchema | null;
|
||||
};
|
||||
|
||||
const useCardsTableForm = () => {
|
||||
const form = useForm<CardsPageState>({
|
||||
initialValues: {
|
||||
cardId: null,
|
||||
marketplace: null,
|
||||
client: null,
|
||||
|
||||
project: null,
|
||||
board: null,
|
||||
status: null,
|
||||
},
|
||||
});
|
||||
|
||||
return { form };
|
||||
};
|
||||
|
||||
export default useCardsTableForm;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ProjectSchema } from "../../../client";
|
||||
import { Flex, Modal, NumberInput, rem } from "@mantine/core";
|
||||
import { UseFormReturnType } from "@mantine/form";
|
||||
import { CardsPageState } from "../hooks/useCardsPageState.tsx";
|
||||
import { CardsPageState } from "../hooks/useCardsTableForm.tsx";
|
||||
import ObjectSelect from "../../../components/ObjectSelect/ObjectSelect.tsx";
|
||||
import CardStatusSelect from "../../../components/CardStatusSelect/CardStatusSelect.tsx";
|
||||
import BaseMarketplaceSelect from "../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx";
|
||||
@@ -33,7 +33,7 @@ const CardsTableFiltersModal = ({ form, projects }: Props) => {
|
||||
<NumberInput
|
||||
min={1}
|
||||
placeholder={"Введите номер"}
|
||||
{...form.getInputProps("id")}
|
||||
{...form.getInputProps("cardId")}
|
||||
hideControls
|
||||
/>
|
||||
<ObjectSelect
|
||||
@@ -41,16 +41,16 @@ const CardsTableFiltersModal = ({ form, projects }: Props) => {
|
||||
data={projects}
|
||||
clearable
|
||||
searchable
|
||||
{...form.getInputProps("projectForTable")}
|
||||
onClear={() => form.setFieldValue("projectForTable", null)}
|
||||
{...form.getInputProps("project")}
|
||||
onClear={() => form.setFieldValue("project", null)}
|
||||
/>
|
||||
<BoardSelect
|
||||
project={form.values.projectForTable}
|
||||
project={form.values.project || null}
|
||||
{...form.getInputProps("board")}
|
||||
clearable
|
||||
/>
|
||||
<CardStatusSelect
|
||||
board={form.values.board}
|
||||
board={form.values.board || null}
|
||||
{...form.getInputProps("status")}
|
||||
clearable
|
||||
/>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { FC, useMemo, useState } from "react";
|
||||
import { useCardSummaries } from "../hooks/useCardSummaries.tsx";
|
||||
import { FC, useEffect, useMemo, useState } from "react";
|
||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
||||
import CardEditDrawer from "../drawers/CardEditDrawer/CardEditDrawer.tsx";
|
||||
import { CardPageContextProvider } from "../contexts/CardPageContext.tsx";
|
||||
import { rem } from "@mantine/core";
|
||||
import useCardsPageState from "../hooks/useCardsPageState.tsx";
|
||||
import useCardsTableForm from "../hooks/useCardsTableForm.tsx";
|
||||
import CardsTable from "../components/CardsTable/CardsTable.tsx";
|
||||
import { motion } from "framer-motion";
|
||||
import CardPrefillDrawer from "../drawers/CardPrefillDrawer/CardPrefillDrawer.tsx";
|
||||
@@ -17,30 +16,35 @@ import { ProjectsEditorContextProvider } from "../contexts/ProjectsEditorContext
|
||||
import ProjectEditDrawer from "../drawers/ProjectEditDrawer/ProjectEditDrawer.tsx";
|
||||
import Boards from "../../../components/Dnd/Boards/Boards/Boards.tsx";
|
||||
import { DndContextProvider } from "../contexts/DndContext.tsx";
|
||||
import useCardSummaries from "../hooks/useCardSummaries.tsx";
|
||||
|
||||
export const CardsPage: FC = () => {
|
||||
const { data, form } = useCardsPageState();
|
||||
const { form } = useCardsTableForm();
|
||||
const { dealId } = useParams({ strict: false });
|
||||
const { summariesRaw, refetch: refetchSummaries } = useCardSummaries();
|
||||
const { summaries, fetchSummaries } = useCardSummaries({ full: false });
|
||||
|
||||
const [displayMode, setDisplayMode] = useState<DisplayMode>(DisplayMode.BOARD);
|
||||
|
||||
useEffect(() => {
|
||||
fetchSummaries();
|
||||
}, []);
|
||||
|
||||
const tableBody = useMemo(() => {
|
||||
return (
|
||||
<CardsTable items={data} />
|
||||
<CardsTable form={form} />
|
||||
);
|
||||
}, [data]);
|
||||
}, [form]);
|
||||
|
||||
const boardsBody = useMemo(() => {
|
||||
return (
|
||||
<DndContextProvider
|
||||
summariesRaw={summariesRaw}
|
||||
refetchSummaries={refetchSummaries}
|
||||
summariesRaw={summaries}
|
||||
refetchSummaries={fetchSummaries}
|
||||
>
|
||||
<Boards />
|
||||
</DndContextProvider>
|
||||
);
|
||||
}, [summariesRaw]);
|
||||
}, [summaries]);
|
||||
|
||||
const getBody = () => {
|
||||
return (
|
||||
@@ -72,9 +76,7 @@ export const CardsPage: FC = () => {
|
||||
<ProjectsEditorContextProvider>
|
||||
<CardPageContextProvider
|
||||
defaultCardId={(dealId && parseInt(dealId)) || undefined}
|
||||
refetchCards={async () => {
|
||||
await refetchSummaries();
|
||||
}}
|
||||
refetchCards={fetchSummaries}
|
||||
>
|
||||
<PrefillCardContextProvider>
|
||||
<PrefillCardsWithExcelContextProvider>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { CRUDTableProps } from "../../../../types/CRUDTable.tsx";
|
||||
import { CardSummary, ShippingWarehouseSchema } from "../../../../client";
|
||||
import { FC, useEffect } from "react";
|
||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { MRT_TableOptions } from "mantine-react-table";
|
||||
import useCardsTablePreviewColumns from "./columns.tsx";
|
||||
import useCardSummaries from "../../../CardsPage/hooks/useCardSummaries.tsx";
|
||||
|
||||
type RestProps = {
|
||||
viewOnly?: boolean;
|
||||
shippingWarehouse: ShippingWarehouseSchema;
|
||||
};
|
||||
type Props = Omit<CRUDTableProps<CardSummary>, "items"> & RestProps;
|
||||
|
||||
const CardsTablePreview: FC<Props> = ({ shippingWarehouse, onSelectionChange }) => {
|
||||
const columns = useCardsTablePreviewColumns();
|
||||
|
||||
const { summaries, fetchSummaries } = useCardSummaries({
|
||||
full: true,
|
||||
values: {
|
||||
shippingWarehouse,
|
||||
},
|
||||
withPagination: true,
|
||||
itemsPerPage: 5,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchSummaries();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<BaseTable
|
||||
data={summaries}
|
||||
columns={columns}
|
||||
onSelectionChange={onSelectionChange}
|
||||
restProps={
|
||||
{
|
||||
enableSorting: true,
|
||||
enableColumnActions: false,
|
||||
paginationDisplayMode: "pages",
|
||||
} as MRT_TableOptions<CardSummary>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardsTablePreview;
|
||||
@@ -0,0 +1,56 @@
|
||||
import { useMemo } from "react";
|
||||
import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { CardSummary } from "../../../../client";
|
||||
import { ActionIcon, Image } from "@mantine/core";
|
||||
|
||||
const useCardsTablePreviewColumns = () => {
|
||||
return useMemo<MRT_ColumnDef<CardSummary>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "Номер",
|
||||
size: 20,
|
||||
},
|
||||
{
|
||||
header: "Маркетплейс",
|
||||
size: 10,
|
||||
Cell: ({ row }) => (
|
||||
<ActionIcon variant={"transparent"}>
|
||||
<Image
|
||||
src={row.original.baseMarketplace?.iconUrl || ""}
|
||||
/>
|
||||
</ActionIcon>
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Дата создания",
|
||||
accessorKey: "createdAt",
|
||||
Cell: ({ row }) =>
|
||||
new Date(row.original.createdAt).toLocaleString("ru-RU"),
|
||||
enableSorting: true,
|
||||
sortingFn: (rowA, rowB) =>
|
||||
new Date(rowB.original.createdAt).getTime() -
|
||||
new Date(rowA.original.createdAt).getTime(),
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название",
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "clientName",
|
||||
header: "Клиент",
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
header: "Общая стоимость",
|
||||
Cell: ({ row }) =>
|
||||
row.original.totalPrice.toLocaleString("ru-RU") + "₽",
|
||||
accessorKey: "totalPrice",
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
};
|
||||
|
||||
export default useCardsTablePreviewColumns;
|
||||
@@ -3,9 +3,7 @@ import { CardSummary, ShippingWarehouseSchema } from "../../../client";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { Input, TextInput } from "@mantine/core";
|
||||
import CardsTable from "../../CardsPage/components/CardsTable/CardsTable.tsx";
|
||||
import { CardPageContextProvider } from "../../CardsPage/contexts/CardPageContext.tsx";
|
||||
import CardEditDrawer from "../../CardsPage/drawers/CardEditDrawer/CardEditDrawer.tsx";
|
||||
import CardsTablePreview from "../components/CardsTablePreview/CardsTablePreview.tsx";
|
||||
|
||||
type RestProps = {
|
||||
summaries: CardSummary[];
|
||||
@@ -27,34 +25,28 @@ const ShippingWarehouseForm = ({
|
||||
},
|
||||
});
|
||||
return (
|
||||
<CardPageContextProvider refetchCards={async () => {}}>
|
||||
<BaseFormModal
|
||||
{...innerProps}
|
||||
closeOnSubmit
|
||||
form={form}
|
||||
onClose={() => context.closeContextModal(id)}>
|
||||
<BaseFormModal.Body>
|
||||
<>
|
||||
<TextInput
|
||||
label={"Склад отгрузки"}
|
||||
placeholder={"Введите название склада отгрузки"}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
{isEditing && (
|
||||
<Input.Wrapper
|
||||
label={"Последние 5 сделок"}
|
||||
error={form.getInputProps("phoneNumber").error}>
|
||||
<CardsTable
|
||||
viewOnly={true}
|
||||
items={innerProps.summaries}
|
||||
/>
|
||||
</Input.Wrapper>
|
||||
)}
|
||||
</>
|
||||
</BaseFormModal.Body>
|
||||
</BaseFormModal>
|
||||
<CardEditDrawer />
|
||||
</CardPageContextProvider>
|
||||
<BaseFormModal
|
||||
{...innerProps}
|
||||
closeOnSubmit
|
||||
form={form}
|
||||
onClose={() => context.closeContextModal(id)}>
|
||||
<BaseFormModal.Body>
|
||||
<>
|
||||
<TextInput
|
||||
label={"Склад отгрузки"}
|
||||
placeholder={"Введите название склада отгрузки"}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
{isEditing && (
|
||||
<Input.Wrapper
|
||||
label={"Последние 5 сделок"}
|
||||
error={form.getInputProps("phoneNumber").error}>
|
||||
<CardsTablePreview shippingWarehouse={form.values} />
|
||||
</Input.Wrapper>
|
||||
)}
|
||||
</>
|
||||
</BaseFormModal.Body>
|
||||
</BaseFormModal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import styles from "../../ServicesPage/ui/ServicesPage.module.css";
|
||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
||||
import ShippingWarehousesTable from "../components/ShippingWarehousesTable/ShippingWarehousesTable.tsx";
|
||||
import useShippingWarehousesList from "../../../components/Selects/ShippingWarehouseAutocomplete/hooks/useShippingWarehousesList.tsx";
|
||||
import useShippingWarehousesList
|
||||
from "../../../components/Selects/ShippingWarehouseAutocomplete/hooks/useShippingWarehousesList.tsx";
|
||||
import { Button } from "@mantine/core";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { useCRUD } from "../../../hooks/useCRUD.tsx";
|
||||
import {
|
||||
ShippingWarehouseSchema,
|
||||
ShippingWarehouseService,
|
||||
} from "../../../client";
|
||||
import { ShippingWarehouseSchema, ShippingWarehouseService } from "../../../client";
|
||||
import { notifications } from "../../../shared/lib/notifications.ts";
|
||||
import { useCardSummariesFull } from "../../CardsPage/hooks/useCardSummaries.tsx";
|
||||
import useCardSummaries from "../../CardsPage/hooks/useCardSummaries.tsx";
|
||||
|
||||
export const ShippingWarehousesPage = () => {
|
||||
const { shippingWarehouses, refetch } = useShippingWarehousesList();
|
||||
const { objects: summaries } = useCardSummariesFull();
|
||||
const { summaries } = useCardSummaries({
|
||||
full: true,
|
||||
withPagination: true,
|
||||
values: {},
|
||||
});
|
||||
|
||||
const crud = useCRUD<ShippingWarehouseSchema>({
|
||||
onChange: element => {
|
||||
ShippingWarehouseService.updateShippingWarehouse({
|
||||
|
||||
Reference in New Issue
Block a user