feat: board name editing

This commit is contained in:
2025-08-07 12:31:00 +04:00
parent 41f8d19d49
commit 7e2dd9763b
6 changed files with 251 additions and 128 deletions

View File

@ -1,6 +1,6 @@
import React, { FC, useState } from "react";
import { IconDotsVertical, IconEdit, IconTrash } from "@tabler/icons-react";
import { Box, Group, Menu, Text } from "@mantine/core";
import React, { FC, useEffect, useRef, useState } from "react";
import { Group, Text, TextInput } from "@mantine/core";
import BoardMenu from "@/app/deals/components/Board/BoardMenu";
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import { BoardSchema } from "@/lib/client";
@ -10,7 +10,48 @@ type Props = {
const Board: FC<Props> = ({ board }) => {
const [isHovered, setIsHovered] = useState(false);
const { selectedBoard, onDeleteBoardClick } = useBoardsContext();
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState(board.name);
const { onUpdateBoard } = useBoardsContext();
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
}
}, [isEditing]);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
isEditing &&
inputRef.current &&
!inputRef.current.contains(event.target as Node)
) {
handleSave();
}
};
document.addEventListener("mousedown", handleClickOutside);
return () =>
document.removeEventListener("mousedown", handleClickOutside);
}, [isEditing, editValue]);
const handleSave = () => {
const newValue = editValue.trim();
if (newValue && newValue !== board.name) {
onUpdateBoard(board.id, { name: newValue });
}
setIsEditing(false);
};
const handleEdit = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.preventDefault();
e.stopPropagation();
setEditValue(board.name);
setIsEditing(true);
};
return (
<Group
@ -22,39 +63,34 @@ const Board: FC<Props> = ({ board }) => {
style={{ borderWidth: 1 }}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}>
<Text>{board.name}</Text>
<Menu>
<Menu.Target>
<Box
style={{
opacity:
isHovered || selectedBoard?.id === board.id
? 1
: 0,
cursor: "pointer",
}}
onClick={e => {
e.preventDefault();
e.stopPropagation();
}}>
<IconDotsVertical size={16} />
</Box>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item>
<Group wrap={"nowrap"}>
<IconEdit />
<Text>Переименовать</Text>
</Group>
</Menu.Item>
<Menu.Item onClick={() => onDeleteBoardClick(board.id)}>
<Group wrap={"nowrap"}>
<IconTrash />
<Text>Удалить</Text>
</Group>
</Menu.Item>
</Menu.Dropdown>
</Menu>
{isEditing ? (
<TextInput
ref={inputRef}
value={editValue}
onChange={e => setEditValue(e.target.value)}
onKeyDown={e => {
if (e.key === "Enter") handleSave();
if (e.key === "Escape") {
setEditValue(board.name);
setIsEditing(false);
}
}}
variant="unstyled"
styles={{
input: {
height: 25,
minHeight: 25,
},
}}
/>
) : (
<Text>{board.name}</Text>
)}
<BoardMenu
isHovered={isHovered}
board={board}
handleEdit={handleEdit}
/>
</Group>
);
};