feat: deal tags
This commit is contained in:
34
src/components/ui/DealTag/DealTag.tsx
Normal file
34
src/components/ui/DealTag/DealTag.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { lighten, Pill, useMantineColorScheme } from "@mantine/core";
|
||||
import { DealTagSchema } from "@/lib/client";
|
||||
|
||||
type Props = {
|
||||
tag: Partial<DealTagSchema>;
|
||||
};
|
||||
|
||||
const DealTag = ({ tag }: Props) => {
|
||||
const theme = useMantineColorScheme();
|
||||
const isInherit = tag.tagColor!.backgroundColor === "inherit";
|
||||
|
||||
let color = tag.tagColor!.color;
|
||||
const backgroundColor = tag.tagColor!.backgroundColor;
|
||||
|
||||
if (!(theme.colorScheme === "dark" || isInherit)) {
|
||||
color = lighten(color, 0.95);
|
||||
}
|
||||
|
||||
return (
|
||||
<Pill
|
||||
key={tag.id}
|
||||
style={{
|
||||
opacity: 0.7,
|
||||
color,
|
||||
backgroundColor,
|
||||
border: "1px solid",
|
||||
borderColor: color,
|
||||
}}>
|
||||
{tag.name}
|
||||
</Pill>
|
||||
);
|
||||
};
|
||||
|
||||
export default DealTag;
|
||||
30
src/components/ui/DealTags/DealTags.module.css
Normal file
30
src/components/ui/DealTags/DealTags.module.css
Normal file
@ -0,0 +1,30 @@
|
||||
.add-tag-button {
|
||||
@mixin light {
|
||||
background-color: var(--mantine-color-gray-1);
|
||||
}
|
||||
@mixin dark {
|
||||
background-color: var(--mantine-color-dark-6);
|
||||
}
|
||||
color: gray;
|
||||
border: 1px gray dashed;
|
||||
border-radius: 50%;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.add-tag-button:hover {
|
||||
@mixin light {
|
||||
border-color: black;
|
||||
color: black;
|
||||
}
|
||||
@mixin dark {
|
||||
border-color: white;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.add-tag-button-icon {
|
||||
color: inherit !important;
|
||||
}
|
||||
93
src/components/ui/DealTags/DealTags.tsx
Normal file
93
src/components/ui/DealTags/DealTags.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { IconPlus } from "@tabler/icons-react";
|
||||
import classNames from "classnames";
|
||||
import { Button, Center, Checkbox, Group, Menu, Stack } from "@mantine/core";
|
||||
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||
import DealTag from "@/components/ui/DealTag/DealTag";
|
||||
import useDealTags from "@/components/ui/DealTags/hooks/useDealTags";
|
||||
import { DealTagSchema } from "@/lib/client";
|
||||
import styles from "./DealTags.module.css";
|
||||
|
||||
type Props = {
|
||||
dealId?: number;
|
||||
groupId?: number;
|
||||
tags: DealTagSchema[];
|
||||
};
|
||||
|
||||
const DealTags = ({ tags, dealId, groupId }: Props) => {
|
||||
const { selectedProject } = useProjectsContext();
|
||||
const { switchTag } = useDealTags();
|
||||
const tagIdsSet = useMemo(() => new Set(tags.map(t => t.id)), [tags]);
|
||||
|
||||
if (selectedProject?.tags.length === 0) return;
|
||||
|
||||
const onTagClick = (tagId: number, event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
switchTag({ dealId, groupId, tagId });
|
||||
};
|
||||
|
||||
const addTagButton = useMemo(
|
||||
() => (
|
||||
<Menu withArrow>
|
||||
<Menu.Target>
|
||||
<Button
|
||||
onClick={e => e.stopPropagation()}
|
||||
unstyled
|
||||
className={classNames(styles["add-tag-button"])}>
|
||||
<Center>
|
||||
<IconPlus
|
||||
size={"1.2em"}
|
||||
className={classNames(
|
||||
styles["add-tag-button-icon"]
|
||||
)}
|
||||
/>
|
||||
</Center>
|
||||
</Button>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
<Stack
|
||||
p={"xs"}
|
||||
gap={"sm"}
|
||||
onClick={e => e.stopPropagation()}>
|
||||
{selectedProject?.tags.map(tag => (
|
||||
<Group
|
||||
key={tag.id}
|
||||
wrap={"nowrap"}>
|
||||
<Checkbox
|
||||
checked={tagIdsSet.has(tag.id)}
|
||||
onChange={event =>
|
||||
onTagClick(
|
||||
tag.id,
|
||||
event as unknown as any
|
||||
)
|
||||
}
|
||||
label={tag.name}
|
||||
/>
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
),
|
||||
[selectedProject?.tags, tags]
|
||||
);
|
||||
|
||||
return (
|
||||
<Group gap={"xs"}>
|
||||
{addTagButton}
|
||||
{selectedProject?.tags.map(
|
||||
tag =>
|
||||
tagIdsSet.has(tag.id) && (
|
||||
<DealTag
|
||||
key={tag.id}
|
||||
tag={tag}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default DealTags;
|
||||
25
src/components/ui/DealTags/hooks/useDealTags.ts
Normal file
25
src/components/ui/DealTags/hooks/useDealTags.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useDealsContext } from "@/app/deals/contexts/DealsContext";
|
||||
import { SwitchDealTagRequest } from "@/lib/client";
|
||||
import { switchDealTagMutation } from "@/lib/client/@tanstack/react-query.gen";
|
||||
|
||||
const useDealTags = () => {
|
||||
const { refetchDeals } = useDealsContext();
|
||||
|
||||
const switchTagMutation = useMutation({
|
||||
...switchDealTagMutation(),
|
||||
onSettled: refetchDeals,
|
||||
});
|
||||
|
||||
const switchTag = (data: SwitchDealTagRequest) => {
|
||||
switchTagMutation.mutate({
|
||||
body: data,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
switchTag,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDealTags;
|
||||
Reference in New Issue
Block a user