diff --git a/src/langs/fa.json b/src/langs/fa.json index dffa79c..7455f67 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -989,6 +989,15 @@ "upload_background": "تصویر مورد نظر را دراپ کنید", "select_date": "انتخاب تاریخ", "projects": "پروژه‌ها", - "delete_project": "پاک کردن" + "delete_project": "پاک کردن", + "task_detail": { + "labels": "برچسب ها", + "user_management": "مدیریت کاربران", + "checklist": "چک لیست", + "attachment": "ضمیمه", + "date_settings": "تنظیمات تاریخ", + "description": "توضیحات", + "description_placeholder": "توضیحات خود را اضافه کنید" + } } } diff --git a/src/pages/taskmanager/components/Column.tsx b/src/pages/taskmanager/components/Column.tsx index 2c84c20..7823e34 100644 --- a/src/pages/taskmanager/components/Column.tsx +++ b/src/pages/taskmanager/components/Column.tsx @@ -10,6 +10,7 @@ type Props = { onDragStart: (taskId: string) => void; onDragEnd: () => void; onDrop: (columnId: string, index: number) => void; + onTaskClick?: (task: TaskType) => void; }; const Column: FC = ({ @@ -19,6 +20,7 @@ const Column: FC = ({ onDragStart, onDragEnd, onDrop, + onTaskClick, }) => { const [isAdding, setIsAdding] = useState(false); const [isDragOver, setIsDragOver] = useState(false); @@ -72,6 +74,7 @@ const Column: FC = ({ isDragging={draggedTaskId === task.id} onDragStart={onDragStart} onDragEnd={onDragEnd} + onClick={onTaskClick} /> ))} diff --git a/src/pages/taskmanager/components/Task.tsx b/src/pages/taskmanager/components/Task.tsx index a27a72c..0e80d05 100644 --- a/src/pages/taskmanager/components/Task.tsx +++ b/src/pages/taskmanager/components/Task.tsx @@ -1,5 +1,5 @@ import { AttachCircle, Calendar, TickSquare } from "iconsax-react"; -import { type FC } from "react"; +import { useRef, type FC } from "react"; import type { Task as TaskType } from "../types"; type Props = { @@ -7,14 +7,31 @@ type Props = { isDragging?: boolean; onDragStart: (taskId: string) => void; onDragEnd: () => void; + onClick?: (task: TaskType) => void; }; -const Task: FC = ({ task, isDragging, onDragStart, onDragEnd }) => { +const Task: FC = ({ task, isDragging, onDragStart, onDragEnd, onClick }) => { + const hasDraggedRef = useRef(false); + + const handleClick = () => { + if (hasDraggedRef.current) return; + onClick?.(task); + }; + return (
onDragStart(task.id)} - onDragEnd={onDragEnd} + onDragStart={() => { + hasDraggedRef.current = true; + onDragStart(task.id); + }} + onDragEnd={() => { + onDragEnd(); + requestAnimationFrame(() => { + hasDraggedRef.current = false; + }); + }} + onClick={handleClick} className={`bg-white rounded-lg p-2 cursor-grab active:cursor-grabbing transition-opacity ${ isDragging ? "opacity-40" : "" }`} diff --git a/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx b/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx new file mode 100644 index 0000000..e65930d --- /dev/null +++ b/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx @@ -0,0 +1,49 @@ +import { Calendar, Paperclip2, Profile2User, Tag, TickSquare, type Icon } from "iconsax-react"; +import { type FC } from "react"; +import { useTranslation } from "react-i18next"; +import type { TaskDetailTab } from "./types"; + +type TabItem = { + id: TaskDetailTab; + icon: Icon; + labelKey: string; +}; + +const TABS: TabItem[] = [ + { id: "labels", icon: Tag, labelKey: "taskmanager.task_detail.labels" }, + { id: "users", icon: Profile2User, labelKey: "taskmanager.task_detail.user_management" }, + { id: "checklist", icon: TickSquare, labelKey: "taskmanager.task_detail.checklist" }, + { id: "attachment", icon: Paperclip2, labelKey: "taskmanager.task_detail.attachment" }, + { id: "date", icon: Calendar, labelKey: "taskmanager.task_detail.date_settings" }, +]; + +type Props = { + activeTab: TaskDetailTab | null; + onTabChange: (tab: TaskDetailTab) => void; +}; + +const TaskDetailActionBar: FC = ({ activeTab, onTabChange }) => { + const { t } = useTranslation("global"); + + return ( +
+ {TABS.map(({ id, icon: Icon, labelKey }) => { + const isActive = activeTab === id; + + return ( + + ); + })} +
+ ); +}; + +export default TaskDetailActionBar; diff --git a/src/pages/taskmanager/components/task-detail/TaskDetailDescription.tsx b/src/pages/taskmanager/components/task-detail/TaskDetailDescription.tsx new file mode 100644 index 0000000..e659235 --- /dev/null +++ b/src/pages/taskmanager/components/task-detail/TaskDetailDescription.tsx @@ -0,0 +1,26 @@ +import { type FC } from "react"; +import { useTranslation } from "react-i18next"; + +type Props = { + value?: string; + onChange?: (value: string) => void; +}; + +const TaskDetailDescription: FC = ({ value = "", onChange }) => { + const { t } = useTranslation("global"); + + return ( +
+
{t("taskmanager.task_detail.description")}
+