feat: colors for card tags

This commit is contained in:
2025-03-13 19:28:12 +04:00
parent 86115f0263
commit e32ec1ff23
14 changed files with 177 additions and 31 deletions

View File

@@ -102,6 +102,7 @@ export type { CardStatusHistorySchema } from './models/CardStatusHistorySchema';
export type { CardSummary } from './models/CardSummary'; export type { CardSummary } from './models/CardSummary';
export type { CardSummaryReorderRequest } from './models/CardSummaryReorderRequest'; export type { CardSummaryReorderRequest } from './models/CardSummaryReorderRequest';
export type { CardSummaryResponse } from './models/CardSummaryResponse'; export type { CardSummaryResponse } from './models/CardSummaryResponse';
export type { CardTagColorSchema } from './models/CardTagColorSchema';
export type { CardTagSchema } from './models/CardTagSchema'; export type { CardTagSchema } from './models/CardTagSchema';
export type { CardUpdateGeneralInfoRequest } from './models/CardUpdateGeneralInfoRequest'; export type { CardUpdateGeneralInfoRequest } from './models/CardUpdateGeneralInfoRequest';
export type { CardUpdateGeneralInfoResponse } from './models/CardUpdateGeneralInfoResponse'; export type { CardUpdateGeneralInfoResponse } from './models/CardUpdateGeneralInfoResponse';
@@ -215,6 +216,8 @@ export type { FinishPauseByUserIdResponse } from './models/FinishPauseByUserIdRe
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse'; export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
export type { FinishShiftResponse } from './models/FinishShiftResponse'; export type { FinishShiftResponse } from './models/FinishShiftResponse';
export type { FullProjectSchema } from './models/FullProjectSchema'; export type { FullProjectSchema } from './models/FullProjectSchema';
export type { GenerateInviteCodeRequest } from './models/GenerateInviteCodeRequest';
export type { GenerateInviteCodeResponse } from './models/GenerateInviteCodeResponse';
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse'; export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse'; export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse'; export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
@@ -259,6 +262,7 @@ export type { GetProjectsResponse } from './models/GetProjectsResponse';
export type { GetResidualBoxResponse } from './models/GetResidualBoxResponse'; export type { GetResidualBoxResponse } from './models/GetResidualBoxResponse';
export type { GetResidualPalletResponse } from './models/GetResidualPalletResponse'; export type { GetResidualPalletResponse } from './models/GetResidualPalletResponse';
export type { GetServiceKitSchema } from './models/GetServiceKitSchema'; export type { GetServiceKitSchema } from './models/GetServiceKitSchema';
export type { GetTagColorsResponse } from './models/GetTagColorsResponse';
export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest'; export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest';
export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse'; export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse';
export type { GetTransactionTagsResponse } from './models/GetTransactionTagsResponse'; export type { GetTransactionTagsResponse } from './models/GetTransactionTagsResponse';

View File

@@ -5,5 +5,6 @@
export type BaseCardTagSchema = { export type BaseCardTagSchema = {
name: string; name: string;
projectId: number; projectId: number;
tagColorId: number;
}; };

View File

@@ -2,9 +2,12 @@
/* istanbul ignore file */ /* istanbul ignore file */
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
import type { CardTagColorSchema } from './CardTagColorSchema';
export type CardTagSchema = { export type CardTagSchema = {
name: string; name: string;
projectId: number; projectId: number;
tagColorId: number;
id: number; id: number;
tagColor: CardTagColorSchema;
}; };

View File

@@ -0,0 +1,9 @@
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { CardTagColorSchema } from './CardTagColorSchema';
export type GetTagColorsResponse = {
colors: Array<CardTagColorSchema>;
};

View File

@@ -5,6 +5,7 @@
import type { CreateTagRequest } from '../models/CreateTagRequest'; import type { CreateTagRequest } from '../models/CreateTagRequest';
import type { CreateTagResponse } from '../models/CreateTagResponse'; import type { CreateTagResponse } from '../models/CreateTagResponse';
import type { DeleteTagResponse } from '../models/DeleteTagResponse'; import type { DeleteTagResponse } from '../models/DeleteTagResponse';
import type { GetTagColorsResponse } from '../models/GetTagColorsResponse';
import type { SwitchTagRequest } from '../models/SwitchTagRequest'; import type { SwitchTagRequest } from '../models/SwitchTagRequest';
import type { SwitchTagResponse } from '../models/SwitchTagResponse'; import type { SwitchTagResponse } from '../models/SwitchTagResponse';
import type { UpdateTagRequest } from '../models/UpdateTagRequest'; import type { UpdateTagRequest } from '../models/UpdateTagRequest';
@@ -94,4 +95,15 @@ export class CardTagService {
}, },
}); });
} }
/**
* Get Colors
* @returns GetTagColorsResponse Successful Response
* @throws ApiError
*/
public static getColors(): CancelablePromise<GetTagColorsResponse> {
return __request(OpenAPI, {
method: 'GET',
url: '/card-tag/colors',
});
}
} }

View File

@@ -0,0 +1,30 @@
import { CardTagSchema } from "../../client";
import { Pill, useMantineColorScheme } from "@mantine/core";
type Props = {
tag: Partial<CardTagSchema>;
}
const CardTag = ({ tag }: Props) => {
const theme = useMantineColorScheme();
let color = "lightgray";
if (tag?.tagColor?.backgroundColor === "inherit" && theme.colorScheme == "light") {
color = "gray";
}
return (
<Pill
key={tag.id}
style={{
color,
backgroundColor: tag?.tagColor?.backgroundColor,
border: "1px solid " + tag?.tagColor?.color,
}}
>
{tag.name}
</Pill>
);
};
export default CardTag;

View File

@@ -83,6 +83,11 @@ const CardSummaryItem: FC<Props> = ({ cardSummary, color }) => {
direction={"column"} direction={"column"}
justify={"space-between"} justify={"space-between"}
> >
<Text
size={"sm"}
c={"gray.6"}>
{cardSummary.shipmentWarehouseName || "Склад не указан"}
</Text>
<Text <Text
c={"gray.6"} c={"gray.6"}
size={"sm"} size={"sm"}

View File

@@ -1,5 +1,11 @@
.add-tag-button { .add-tag-button {
background-color: var(--mantine-color-dark-6); @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: 1px gray dashed;
border-radius: 50%; border-radius: 50%;
width: 1.5rem; width: 1.5rem;
@@ -9,13 +15,16 @@
} }
.add-tag-button:hover { .add-tag-button:hover {
border-color: white; @mixin light {
border-color: black;
color: black;
}
@mixin dark {
border-color: white;
color: white;
}
} }
.add-tag-button-icon { .add-tag-button-icon {
color: gray; color: inherit !important;
}
.add-tag-button-icon:hover {
color: white;
} }

View File

@@ -1,4 +1,4 @@
import { Center, Checkbox, Group, Menu, Pill, rem, Stack } from "@mantine/core"; import { Center, Checkbox, Group, Menu, rem, Stack } from "@mantine/core";
import { CardTagSchema, CardTagService } from "../../../../client"; import { CardTagSchema, CardTagService } from "../../../../client";
import { IconPlus } from "@tabler/icons-react"; import { IconPlus } from "@tabler/icons-react";
import styles from "./CardTags.module.css"; import styles from "./CardTags.module.css";
@@ -7,6 +7,7 @@ import React from "react";
import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx"; import { useProjectsContext } from "../../../../contexts/ProjectsContext.tsx";
import { notifications } from "../../../../shared/lib/notifications.ts"; import { notifications } from "../../../../shared/lib/notifications.ts";
import { useCardPageContext } from "../../../../pages/CardsPage/contexts/CardPageContext.tsx"; import { useCardPageContext } from "../../../../pages/CardsPage/contexts/CardPageContext.tsx";
import CardTag from "../../../CardTag/CardTag.tsx";
type Props = { type Props = {
cardId?: number; cardId?: number;
@@ -72,25 +73,12 @@ const CardTags = ({ tags, cardId, groupId }: Props) => {
</Menu> </Menu>
); );
const pills = tags.map(tag => {
return (
<Pill
key={tag.id}
style={{
color: "gray",
backgroundColor: "var(--mantine-color-dark-6)",
border: "1px solid gray",
}}
>
{tag.name}
</Pill>
);
});
return ( return (
<Group gap={rem(4)}> <Group gap={rem(4)}>
{addTagButton} {addTagButton}
{pills} {tags.map(tag => (
<CardTag key={tag.id} tag={tag} />
))}
</Group> </Group>
); );
}; };

View File

@@ -0,0 +1,45 @@
import { Group, SelectProps } from "@mantine/core";
import { IconCheck } from "@tabler/icons-react";
import useTagColorsList from "../hooks/useTagColorList.tsx";
import ObjectSelect, { ObjectSelectProps } from "../../../../../../../components/ObjectSelect/ObjectSelect.tsx";
import { CardTagColorSchema } from "../../../../../../../client";
import CardTag from "../../../../../../../components/CardTag/CardTag.tsx";
type Props = Omit<ObjectSelectProps<CardTagColorSchema>, "data" | "getValueFn" | "getLabelFn">;
const TagColorInput = (props: Props) => {
const { objects: colors } = useTagColorsList();
const colorsMap = new Map<string, CardTagColorSchema>(
colors.map(color => [color.id.toString(), color] as [string, CardTagColorSchema]),
);
const renderSelectOption: SelectProps["renderOption"] = ({ option, checked }) => {
const tag = {
id: Number.parseInt(option.value),
name: "Тег-пример",
tagColor: colorsMap.get(option.value),
};
return (
<Group flex="1" gap="md">
<CardTag tag={tag} />
{option.label}
{checked && <IconCheck style={{ marginInlineStart: "auto" }} />}
</Group>
);
};
return (
<ObjectSelect
label={"Цвет"}
renderOption={renderSelectOption}
getValueFn={color => color.id.toString()}
getLabelFn={color => color.label}
data={colors}
searchable
{...props}
/>
);
};
export default TagColorInput;

View File

@@ -1,6 +1,7 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { MRT_ColumnDef } from "mantine-react-table"; import { MRT_ColumnDef } from "mantine-react-table";
import { CardTagSchema } from "../../../../../../../client"; import { CardTagSchema } from "../../../../../../../client";
import CardTag from "../../../../../../../components/CardTag/CardTag.tsx";
const useTagsTableColumns = () => { const useTagsTableColumns = () => {
return useMemo<MRT_ColumnDef<CardTagSchema>[]>( return useMemo<MRT_ColumnDef<CardTagSchema>[]>(
@@ -8,7 +9,20 @@ const useTagsTableColumns = () => {
{ {
header: "Название", header: "Название",
accessorKey: "name", accessorKey: "name",
size: 200,
},
{
header: "Цвет",
accessorKey: "tagColor.label",
size: 200,
},
{
header: "Пример",
accessorKey: "tagColor",
size: 1000, size: 1000,
Cell: ({ row }) => (
<CardTag tag={row.original} />
),
}, },
], ],
[], [],

View File

@@ -0,0 +1,11 @@
import { CardTagService } from "../../../../../../../client";
import ObjectList from "../../../../../../../hooks/objectList.tsx";
const useTagColorsList = () =>
ObjectList({
queryFn: CardTagService.getColors,
getObjectsFn: response => response.colors,
queryKey: "useTagColorsList",
});
export default useTagColorsList;

View File

@@ -56,7 +56,12 @@ const useTags = () => {
const onChange = (tag: CardTagSchema) => { const onChange = (tag: CardTagSchema) => {
const response = CardTagService.updateTag({ const response = CardTagService.updateTag({
requestBody: { tag }, requestBody: {
tag: {
...tag,
tagColorId: tag.tagColor.id,
}
},
}); });
processResponse(response); processResponse(response);
@@ -81,6 +86,7 @@ const useTags = () => {
tag: { tag: {
name: tag.name, name: tag.name,
projectId: project.id, projectId: project.id,
tagColorId: tag.tagColor.id,
} }
}, },
}); });

View File

@@ -4,7 +4,8 @@ import BaseFormModal, {
} from "../../../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx"; } from "../../../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
import { CardTagSchema } from "../../../../../../../client"; import { CardTagSchema } from "../../../../../../../client";
import { useForm } from "@mantine/form"; import { useForm } from "@mantine/form";
import { TextInput } from "@mantine/core"; import { Stack, TextInput } from "@mantine/core";
import TagColorInput from "../components/TagColorInput.tsx";
type Props = CreateEditFormProps<CardTagSchema>; type Props = CreateEditFormProps<CardTagSchema>;
@@ -18,12 +19,14 @@ const CardTagModal = ({
? innerProps.element ? innerProps.element
: { : {
name: "", name: "",
tagColor: undefined,
}; };
const form = useForm<Partial<CardTagSchema>>({ const form = useForm<Partial<CardTagSchema>>({
initialValues: initialValue, initialValues: initialValue,
validate: { validate: {
name: name => !name && "Необходимо указать название тега", name: name => !name && "Необходимо указать название тега",
tagColor: tagColor => !tagColor && "Необходимо указать цвет тега",
}, },
}); });
@@ -34,11 +37,17 @@ const CardTagModal = ({
onClose={() => context.closeContextModal(id)} onClose={() => context.closeContextModal(id)}
{...innerProps}> {...innerProps}>
<BaseFormModal.Body> <BaseFormModal.Body>
<TextInput <Stack>
label={"Название"} <TextInput
placeholder={"Введите название тега"} label={"Название"}
{...form.getInputProps("name")} placeholder={"Введите название тега"}
/> {...form.getInputProps("name")}
/>
<TagColorInput
placeholder={"Укажите цвет"}
{...form.getInputProps("tagColor")}
/>
</Stack>
</BaseFormModal.Body> </BaseFormModal.Body>
</BaseFormModal> </BaseFormModal>
); );