feat: cards, attributes and modules

This commit is contained in:
2025-02-19 14:46:13 +04:00
parent cc3e72bf94
commit dc9455966e
286 changed files with 2355 additions and 2168 deletions

View File

@@ -0,0 +1,156 @@
import { FC } from "react";
import { CardService, CardSummary } from "../../../../client";
import styles from "./CardSummaryItem.module.css";
import { ActionIcon, Badge, CopyButton, Flex, Image, Popover, rem, Text, ThemeIcon, Tooltip } from "@mantine/core";
import { useCardPageContext } from "../../../../pages/CardsPage/contexts/CardPageContext.tsx";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheck } from "@fortawesome/free-solid-svg-icons";
import { IconCheck, IconLayoutGridRemove, IconTrash } from "@tabler/icons-react";
import { useContextMenu } from "mantine-contextmenu";
import useCardSummaryState from "./useCardSummaryState.tsx";
import isModuleInProject, { Modules } from "../../../../pages/CardsPage/utils/isModuleInProject.ts";
type Props = {
cardSummary: CardSummary;
color?: string
};
const CardSummaryItem: FC<Props> = ({ cardSummary, color }) => {
const { showContextMenu } = useContextMenu();
const { selectedProject, setSelectedCard } = useCardPageContext();
const { onDelete, onComplete, onDeleteFromGroup } = useCardSummaryState();
const isServicesAndProductsIncluded = isModuleInProject(Modules.SERVICES_AND_PRODUCTS, selectedProject);
const onDealSummaryClick = () => {
CardService.getCardById({ cardId: cardSummary.id }).then(card => {
setSelectedCard(card);
});
};
const isPaid = () => {
return cardSummary.billRequest?.paid || cardSummary.group?.billRequest?.paid;
};
const isLockedInsideGroup = () => {
return cardSummary.group && !cardSummary.group.billRequest;
};
return (
<div
onContextMenu={showContextMenu([
...isLockedInsideGroup() ? [{
key: "removeFromGroup",
onClick: () => onDeleteFromGroup(cardSummary),
title: "Убрать из группы",
icon: <IconLayoutGridRemove />,
}] : [],
{
key: "complete",
onClick: () => onComplete(cardSummary),
title: "Завершить",
icon: <IconCheck />,
},
{
key: "delete",
onClick: () => onDelete(cardSummary),
title: "Удалить",
icon: <IconTrash />,
},
])}
onClick={() => onDealSummaryClick()}
className={styles["container"]}
style={{ backgroundColor: color }}
>
<Flex direction={"column"} flex={1} gap={rem(3)}>
<Flex justify={"space-between"}>
<Text
c={"gray.6"}
size={"xs"}
>
{cardSummary.clientName}
</Text>
</Flex>
<Text
c={"blue.5"}
size={"sm"}>
{cardSummary.name}
</Text>
{isServicesAndProductsIncluded && (
<Flex
direction={"column"}
justify={"space-between"}
>
<Text
c={"gray.6"}
size={"sm"}
>
{cardSummary.totalPrice.toLocaleString("ru-RU")} руб,{" "}
</Text>
<Text
c={"gray.6"}
size={"sm"}>
{cardSummary.totalProducts.toLocaleString("ru-RU")} тов.
</Text>
</Flex>
)}
<Flex align={"center"} justify={"space-between"}>
<Flex align={"center"} gap={rem(5)}>
<CopyButton value={cardSummary.id.toString()}>
{({ copy, copied }) => (
<Popover
opened={copied}
withArrow>
<Popover.Target>
<div
onClick={e => {
e.stopPropagation();
copy();
}}
className={styles["flex-item"]}>
<Badge
variant={"light"}
radius={"sm"}>
ID: {cardSummary.id}
</Badge>
</div>
</Popover.Target>
<Popover.Dropdown>
<Flex
justify={"center"}
align={"center"}
gap={rem(5)}>
<FontAwesomeIcon
bounce
style={{ animationIterationCount: 1 }}
icon={faCheck}
/>
<Text size={"xs"}>
ID сделки скопирован
</Text>
</Flex>
</Popover.Dropdown>
</Popover>
)}
</CopyButton>
{isPaid() && (
<Tooltip label={"Оплачен"}>
<ThemeIcon variant={"transparent"}>
<IconCheck />
</ThemeIcon>
</Tooltip>
)}
</Flex>
<ActionIcon variant={"transparent"}>
<Image
src={cardSummary.baseMarketplace?.iconUrl || ""}
/>
</ActionIcon>
</Flex>
</Flex>
</div>
);
};
export default CardSummaryItem;