From 92033fb94cebcfdec3e5d68fab40f44d5328284d Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Wed, 17 Jun 2026 15:34:47 +0330 Subject: [PATCH] task detail attachment form --- src/langs/fa.json | 5 +- .../task-detail/TaskDetailActionBar.tsx | 13 +++- .../task-detail/TaskDetailToolbar.tsx | 15 ++++ .../attachment/TaskDetailAttachmentForm.tsx | 78 +++++++++++++++++++ .../TaskDetailAttachmentPopover.tsx | 17 ++++ .../task-detail/attachment/types.ts | 6 ++ 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/pages/taskmanager/components/task-detail/attachment/TaskDetailAttachmentForm.tsx create mode 100644 src/pages/taskmanager/components/task-detail/attachment/TaskDetailAttachmentPopover.tsx create mode 100644 src/pages/taskmanager/components/task-detail/attachment/types.ts diff --git a/src/langs/fa.json b/src/langs/fa.json index c693a8c..0098b65 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -1003,7 +1003,10 @@ "choose_custom_color": "انتخاب رنگ دلخواه", "members": "اعضا", "copy_from": "کپی از", - "none": "هیچ کدام" + "none": "هیچ کدام", + "link": "لینک", + "or": "یا", + "insert": "درج" } } } diff --git a/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx b/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx index da2b7e9..8f067dc 100644 --- a/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx +++ b/src/pages/taskmanager/components/task-detail/TaskDetailActionBar.tsx @@ -23,9 +23,10 @@ type Props = { labelsPopover?: ReactNode; usersPopover?: ReactNode; checklistPopover?: ReactNode; + attachmentPopover?: ReactNode; }; -const TaskDetailActionBar: FC = ({ activeTab, onTabChange, labelsPopover, usersPopover, checklistPopover }) => { +const TaskDetailActionBar: FC = ({ activeTab, onTabChange, labelsPopover, usersPopover, checklistPopover, attachmentPopover }) => { const { t } = useTranslation("global"); return ( @@ -44,11 +45,17 @@ const TaskDetailActionBar: FC = ({ activeTab, onTabChange, labelsPopover, ); - if (id === "labels" || id === "users" || id === "checklist") { + if (id === "labels" || id === "users" || id === "checklist" || id === "attachment") { return (
{button} - {id === "labels" ? labelsPopover : id === "users" ? usersPopover : checklistPopover} + {id === "labels" + ? labelsPopover + : id === "users" + ? usersPopover + : id === "checklist" + ? checklistPopover + : attachmentPopover}
); } diff --git a/src/pages/taskmanager/components/task-detail/TaskDetailToolbar.tsx b/src/pages/taskmanager/components/task-detail/TaskDetailToolbar.tsx index 536717c..bd006a2 100644 --- a/src/pages/taskmanager/components/task-detail/TaskDetailToolbar.tsx +++ b/src/pages/taskmanager/components/task-detail/TaskDetailToolbar.tsx @@ -1,4 +1,5 @@ import { type FC, useState } from "react"; +import TaskDetailAttachmentPopover from "./attachment/TaskDetailAttachmentPopover"; import { DEFAULT_CHECKLISTS } from "./checklist/constants"; import TaskDetailChecklistPopover from "./checklist/TaskDetailChecklistPopover"; import type { TaskChecklist } from "./checklist/types"; @@ -28,6 +29,7 @@ const TaskDetailToolbar: FC = ({ activeTab, onTabChange }) => { const isLabelsOpen = activeTab === "labels"; const isUsersOpen = activeTab === "users"; const isChecklistOpen = activeTab === "checklist"; + const isAttachmentOpen = activeTab === "attachment"; const handleTabChange = (tab: TaskDetailTab) => { if (tab === "labels" && activeTab !== "labels") { @@ -84,6 +86,14 @@ const TaskDetailToolbar: FC = ({ activeTab, onTabChange }) => { handleChecklistClose(); }; + const handleAttachmentClose = () => { + if (isAttachmentOpen) onTabChange("attachment"); + }; + + const handleAttachmentCreate = (_data: { file?: File; title: string; linkId: string }) => { + handleAttachmentClose(); + }; + return (
= ({ activeTab, onTabChange }) => { /> ) : null } + attachmentPopover={ + isAttachmentOpen ? ( + + ) : null + } /> diff --git a/src/pages/taskmanager/components/task-detail/attachment/TaskDetailAttachmentForm.tsx b/src/pages/taskmanager/components/task-detail/attachment/TaskDetailAttachmentForm.tsx new file mode 100644 index 0000000..52790ad --- /dev/null +++ b/src/pages/taskmanager/components/task-detail/attachment/TaskDetailAttachmentForm.tsx @@ -0,0 +1,78 @@ +import { type FC, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import Button from "../../../../../components/Button"; +import Input from "../../../../../components/Input"; +import Select from "../../../../../components/Select"; + +type Props = { + onClose: () => void; + onSubmit: (data: { file?: File; title: string; linkId: string }) => void; +}; + +const TaskDetailAttachmentForm: FC = ({ onClose, onSubmit }) => { + const { t } = useTranslation("global"); + const fileInputRef = useRef(null); + const [file, setFile] = useState(null); + const [title, setTitle] = useState(""); + const [linkId, setLinkId] = useState(""); + + const linkItems = [{ value: "", label: t("taskmanager.task_detail.none") }]; + + const canSubmit = Boolean(file) || Boolean(title.trim()); + + const handleFileChange = (e: React.ChangeEvent) => { + const selected = e.target.files?.[0]; + if (selected) setFile(selected); + }; + + const handleSubmit = () => { + if (!canSubmit) return; + onSubmit({ + file: file ?? undefined, + title: title.trim(), + linkId, + }); + }; + + return ( +
+

{t("taskmanager.task_detail.attachment")}

+ +
+ + {file ? file.name : t("no_select_file")} + +
+ +
+
+ {t("taskmanager.task_detail.or")} +
+
+ + setTitle(e.target.value)} className="h-8 bg-white/63 border-white" labelClassName="text-xs" /> + +