feat: added tags for cards, aligned status headers

This commit is contained in:
2025-03-09 19:32:45 +04:00
parent 56135ae10c
commit ea80e92c18
48 changed files with 876 additions and 85 deletions

View File

@@ -1,11 +1,12 @@
import { Box, Drawer, rem, Tabs } from "@mantine/core";
import { IconHexagons, IconSettings, IconSubtask } from "@tabler/icons-react";
import { IconHexagons, IconSettings, IconSubtask, IconTags } from "@tabler/icons-react";
import { ReactNode } from "react";
import { motion } from "framer-motion";
import { useProjectsEditorContext } from "../../contexts/ProjectsEditorContext.tsx";
import General from "./tabs/General/General.tsx";
import Attributes from "./tabs/Attributes/Attributes.tsx";
import Modules from "./tabs/Modules/Modules.tsx";
import Tags from "./tabs/Tags/Tags.tsx";
const ProjectEditDrawer = () => {
@@ -67,11 +68,17 @@ const ProjectEditDrawer = () => {
leftSection={<IconSubtask />}>
Атрибуты
</Tabs.Tab>
<Tabs.Tab
value={"tags"}
leftSection={<IconTags />}>
Теги
</Tabs.Tab>
</Tabs.List>
{getTabPanel("general", <General/>)}
{getTabPanel("attributes", <Attributes/>)}
{getTabPanel("general", <General />)}
{getTabPanel("attributes", <Attributes />)}
{getTabPanel("modules", <Modules />)}
{getTabPanel("tags", <Tags />)}
</Tabs>
</Drawer>
);

View File

@@ -0,0 +1,66 @@
import { ActionIcon, Flex, Group, rem, Stack, Tooltip } from "@mantine/core";
import { BaseTable } from "../../../../../../components/BaseTable/BaseTable.tsx";
import tagsTableColumns from "./hooks/tagsTableColumns.tsx";
import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react";
import { CardTagSchema } from "../../../../../../client";
import { MRT_TableOptions } from "mantine-react-table";
import useTags from "./hooks/useTags.tsx";
import InlineButton from "../../../../../../components/InlineButton/InlineButton.tsx";
const Tags = () => {
const columns = tagsTableColumns();
const {
project,
onDeleteClick,
onChangeClick,
onCreateClick,
} = useTags();
return (
<Stack gap={rem(10)}>
<Group>
<InlineButton onClick={onCreateClick}>
<IconPlus />
Создать
</InlineButton>
</Group>
<BaseTable
data={project?.tags}
columns={columns}
restProps={
{
enableSorting: false,
enableColumnActions: false,
enableRowActions: true,
renderRowActions: ({ row }) => {
return (
<Flex gap="md">
<Tooltip label="Удалить">
<ActionIcon
onClick={() => onDeleteClick(row.original)}
variant={"default"}>
<IconTrash />
</ActionIcon>
</Tooltip>
<Tooltip label="Редактировать">
<ActionIcon
onClick={() => onChangeClick(row.original)}
variant={"default"}>
<IconEdit />
</ActionIcon>
</Tooltip>
</Flex>
);
},
} as MRT_TableOptions<CardTagSchema>
}
/>
</Stack>
);
};
export default Tags;

View File

@@ -0,0 +1,18 @@
import { useMemo } from "react";
import { MRT_ColumnDef } from "mantine-react-table";
import { CardTagSchema } from "../../../../../../../client";
const useTagsTableColumns = () => {
return useMemo<MRT_ColumnDef<CardTagSchema>[]>(
() => [
{
header: "Название",
accessorKey: "name",
size: 1000,
},
],
[],
);
};
export default useTagsTableColumns;

View File

@@ -0,0 +1,109 @@
import {
CancelablePromise,
CardTagSchema,
CardTagService,
CreateTagResponse,
DeleteTagResponse,
UpdateTagResponse,
} from "../../../../../../../client";
import { notifications } from "../../../../../../../shared/lib/notifications.ts";
import { modals } from "@mantine/modals";
import { Text } from "@mantine/core";
import { useProjectsContext } from "../../../../../../../contexts/ProjectsContext.tsx";
import { useCardPageContext } from "../../../../../contexts/CardPageContext.tsx";
const useTags = () => {
const { selectedProject: project, refetchProjects } = useProjectsContext();
const { refetchCards } = useCardPageContext();
const processResponse = (
response: CancelablePromise<DeleteTagResponse | UpdateTagResponse | CreateTagResponse>,
) => {
response
.then(({ ok, message }) => {
if (!ok) {
notifications.error({ message });
return;
}
refetchProjects();
refetchCards();
})
.catch(err => console.log(err));
};
const onDelete = (tag: CardTagSchema) => {
const response = CardTagService.deleteTag({
cardTagId: tag.id,
});
processResponse(response);
};
const onDeleteClick = (tag: CardTagSchema) => {
modals.openConfirmModal({
title: "Удаление тега",
children: (
<Text size="sm">
Вы уверены что хотите удалить тег {tag.name}
</Text>
),
labels: { confirm: "Да", cancel: "Нет" },
confirmProps: { color: "red" },
onConfirm: () => onDelete(tag),
});
};
const onChange = (tag: CardTagSchema) => {
const response = CardTagService.updateTag({
requestBody: { tag },
});
processResponse(response);
};
const onChangeClick = (tag: CardTagSchema) => {
modals.openContextModal({
modal: "cardTagModal",
innerProps: {
element: tag,
onChange,
},
withCloseButton: false,
});
};
const onCreate = (tag: CardTagSchema) => {
if (!project) return;
const response = CardTagService.createTag({
requestBody: {
tag: {
name: tag.name,
projectId: project.id,
}
},
});
processResponse(response);
};
const onCreateClick = () => {
modals.openContextModal({
modal: "cardTagModal",
innerProps: {
onCreate,
},
withCloseButton: false,
});
};
return {
project,
onDeleteClick,
onChangeClick,
onCreateClick,
};
};
export default useTags;

View File

@@ -0,0 +1,47 @@
import { ContextModalProps } from "@mantine/modals";
import BaseFormModal, {
CreateEditFormProps,
} from "../../../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
import { CardTagSchema } from "../../../../../../../client";
import { useForm } from "@mantine/form";
import { TextInput } from "@mantine/core";
type Props = CreateEditFormProps<CardTagSchema>;
const CardTagModal = ({
context,
id,
innerProps,
}: ContextModalProps<Props>) => {
const isEditing = "element" in innerProps;
const initialValue: Partial<CardTagSchema> = isEditing
? innerProps.element
: {
name: "",
};
const form = useForm<Partial<CardTagSchema>>({
initialValues: initialValue,
validate: {
name: name => !name && "Необходимо указать название тега",
},
});
return (
<BaseFormModal
form={form}
closeOnSubmit
onClose={() => context.closeContextModal(id)}
{...innerProps}>
<BaseFormModal.Body>
<TextInput
label={"Название"}
placeholder={"Введите название тега"}
{...form.getInputProps("name")}
/>
</BaseFormModal.Body>
</BaseFormModal>
);
};
export default CardTagModal;