diff --git a/client/src/components/DraggableTask.tsx b/client/src/components/DraggableTask.tsx index ca131f7..9259d9d 100644 --- a/client/src/components/DraggableTask.tsx +++ b/client/src/components/DraggableTask.tsx @@ -40,6 +40,24 @@ const DraggableTask = ({ } ${task.id && remoteDrag?.draggableId === task.id.toString() ? "hidden" : ""} `} style={{ ...provided.draggableProps.style }} > + {task.labels && task.labels.length > 0 && ( +
+ {task.labels.map((labelWrapper) => ( +
+ ))} +
+ )}
{task.title} diff --git a/client/src/components/TaskDetailModal.tsx b/client/src/components/TaskDetailModal.tsx index 747d0e2..0bef6fa 100644 --- a/client/src/components/TaskDetailModal.tsx +++ b/client/src/components/TaskDetailModal.tsx @@ -1,11 +1,13 @@ import React, { useState, useEffect, useRef, useCallback } from "react"; -import type { Task } from "../pages/boards/types"; +import type { Label, Task } from "../pages/boards/types"; import type { User } from "../pages/login/types"; import { getBoardUsers } from "../pages/boards/service"; import { Avatar } from "./ui/Avatar"; import { useAddAssigneeAction, + useAddLabelAction, useRemoveAssigneeAction, + useRemoveLabelAction, } from "../store/boards/hooks"; import type { Editor as TinyMCEEditor } from "tinymce"; import { Editor } from "@tinymce/tinymce-react"; @@ -16,12 +18,16 @@ import { useAI } from "../hooks/useAI"; import { CustomToast } from "./CustomToast"; import toast from "react-hot-toast"; import { SpinnerLoadingText } from "./ui/Spinner"; +import { getContrastColor } from "../lib/colorUtils"; import ConfirmDelete from "./ui/modals/confirm-delete"; import { useDismiss } from "../hooks/useDismissClickAndEsc"; +import { useAppDispatch } from "../../src/store"; +import { addLabel } from "../store/boards/actions"; interface TaskDetailModalProps { isOpen: boolean; task: Task; + boardLabels?: Label[]; columnId: string; boardId?: string; onClose: () => void; @@ -31,8 +37,50 @@ interface TaskDetailModalProps { onDeleteTask: (columnId: string, taskId: string) => void; } +const NewLabelForm: React.FC<{ + boardId: string; +}> = ({ boardId }) => { + const [name, setName] = useState(""); + const [color, setColor] = useState("#cccccc"); + const dispatch = useAppDispatch(); + + const handleCreate = async () => { + if (!name.trim()) return; + try { + await dispatch(addLabel(Number(boardId), { name, color } as Label)); + + setName(""); + setColor("#cccccc"); + } catch (error) { + console.error("Error creating label:", error); + } + }; + + return ( +
+ setColor(e.target.value)} + className="h-10 w-10 rounded border p-0" + /> + setName(e.target.value)} + className="flex-grow rounded border px-2" + /> + +
+ ); +}; + const TaskDetailModal: React.FC = ({ task, + boardLabels, columnId, boardId, isOpen, @@ -68,9 +116,13 @@ const TaskDetailModal: React.FC = ({ const contentInputRef = useRef(null); const usersRef = useRef(null); + const labelsRef = useRef(null); const addMenuRef = useRef(null); const { t: translate } = useTranslation(); const editorRef = useRef(null); + const [showLabels, setShowLabels] = useState(false); + const addLabelAction = useAddLabelAction(); + const removeLabelAction = useRemoveLabelAction(); const { generateDescriptionFromTitle, @@ -402,10 +454,97 @@ const TaskDetailModal: React.FC = ({ />
- + {showLabels && ( +
+
+

+ {translate("board.labels", "Etiquetas")} +

+ +
+ + {/* Lista de etiquetas */} +
+ {boardLabels!.map((label) => { + const isAssigned = task.labels?.some( + (l) => l.label.id === label.id, + ); + const contrastColor = getContrastColor(label.color); + + return ( +
{ + if (isAssigned && task.id && label.id) { + removeLabelAction( + task.id.toString(), + label.id.toString(), + ); + } else if (task.id && label.id) { + addLabelAction( + task.id.toString(), + label.id.toString(), + ); + } + }} + className={`flex cursor-pointer items-center justify-between rounded-md px-2 py-1 text-sm font-medium transition-colors duration-150 ${ + isAssigned + ? "ring-accent ring-1" + : "hover:bg-background-hover-column" + }`} + style={{ + backgroundColor: isAssigned ? label.color : "", + color: isAssigned ? contrastColor : "inherit", + }} + > +
+ + {label.name} + +
+ + {isAssigned && ( + + )} +
+ ); + })} +
+ + {/* Crear nueva etiqueta */} +
+ +
+
+ )}