From 1413744b6fa0e863ab0f57c117195f349a0ae008 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Wed, 15 Jul 2026 10:48:27 +0330 Subject: [PATCH] Create task in tocker --- .env | 2 +- src/langs/fa.json | 11 +- src/pages/ticket/Detail.tsx | 8 + .../components/CreateTaskFromTicket.tsx | 211 ++++++++++++++++++ 4 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 src/pages/ticket/components/CreateTaskFromTicket.tsx diff --git a/.env b/.env index 7c2fdf8..37be1b6 100644 --- a/.env +++ b/.env @@ -2,4 +2,4 @@ VITE_TOKEN_NAME = 'admin_token' VITE_REFRESH_TOKEN_NAME = 'admin_refresh_token' VITE_BASE_URL = 'https://api.danakcorp.com' -#VITE_BASE_URL = 'http://192.168.99.131:3500' \ No newline at end of file +VITE_BASE_URL = 'http://192.168.1.107:3500' \ No newline at end of file diff --git a/src/langs/fa.json b/src/langs/fa.json index 27d152c..f9bbb7f 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -349,7 +349,16 @@ "assign_to": "کارشناس پاسخگویی", "user_plan": "پلن کاربر", "refer_ticket_success": "تیکت با موفقیت ارجاع شد", - "refer_ticket_error": "تیکت ارجاع نشد" + "refer_ticket_error": "تیکت ارجاع نشد", + "create_task": "ساخت تسک", + "create_task_modal_title": "ساخت تسک از تیکت", + "create_task_success": "تسک با موفقیت ساخته شد", + "select_project": "انتخاب پروژه", + "select_column": "انتخاب ستون", + "column": "ستون", + "select_workspace_required": "فضای کاری را انتخاب کنید", + "select_project_required": "پروژه را انتخاب کنید", + "select_column_required": "ستون را انتخاب کنید" }, "active": "فعال", "inactive": "غیرفعال", diff --git a/src/pages/ticket/Detail.tsx b/src/pages/ticket/Detail.tsx index da15f4b..6933b3e 100644 --- a/src/pages/ticket/Detail.tsx +++ b/src/pages/ticket/Detail.tsx @@ -18,6 +18,7 @@ import { clx } from '../../helpers/utils' import { Pages } from '../../config/Pages' import { useMultiUpload } from '../service/hooks/useServiceData' import ReferTicket from './components/ReferTicket' +import CreateTaskFromTicket from './components/CreateTaskFromTicket' const TicketDetail: FC = () => { @@ -310,6 +311,13 @@ const TicketDetail: FC = () => { + { + getMessages.data?.data?.ticket?.status !== 'CLOSED' && + + } + { } diff --git a/src/pages/ticket/components/CreateTaskFromTicket.tsx b/src/pages/ticket/components/CreateTaskFromTicket.tsx new file mode 100644 index 0000000..43e22ea --- /dev/null +++ b/src/pages/ticket/components/CreateTaskFromTicket.tsx @@ -0,0 +1,211 @@ +import { FC, useEffect, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import DefaulModal from '../../../components/DefaulModal' +import Select from '../../../components/Select' +import Input from '../../../components/Input' +import Button from '../../../components/Button' +import PageLoading from '../../../components/PageLoading' +import { toast } from 'react-toastify' +import { ErrorType } from '../../../helpers/types' +import { useGetWorkspaces } from '../../taskmanager/workspace/hooks/useWorkspaceData' +import { WorkspaceItemType } from '../../taskmanager/workspace/types/WorkspaceTypes' +import { useGetProjectsByWorkspace, useGetProject } from '../../taskmanager/project/hooks/useProjectData' +import { ProjectItem, ProjectTaskPhaseType } from '../../taskmanager/project/types/ProjectTypes' +import { useCreateTask } from '../../taskmanager/task/hooks/useTaskData' + +type Props = { + ticketSubject: string +} + +const CreateTaskFromTicket: FC = ({ ticketSubject }) => { + const { t } = useTranslation('global') + const [open, setOpen] = useState(false) + const [workspaceId, setWorkspaceId] = useState('') + const [projectId, setProjectId] = useState('') + const [taskPhaseId, setTaskPhaseId] = useState('') + const [title, setTitle] = useState('') + + const getWorkspaces = useGetWorkspaces() + const getProjects = useGetProjectsByWorkspace(workspaceId) + const getProject = useGetProject(projectId) + const createTask = useCreateTask() + + const workspaces: WorkspaceItemType[] = + getWorkspaces.data?.data?.workspaces ?? + getWorkspaces.data?.data ?? + [] + + const projects: ProjectItem[] = + getProjects.data?.data?.projects ?? + getProjects.data?.data ?? + [] + + const taskPhases: ProjectTaskPhaseType[] = useMemo(() => { + const phases = getProject.data?.data?.taskPhases ?? getProject.data?.taskPhases ?? [] + return [...phases].sort((a, b) => a.order - b.order) + }, [getProject.data]) + + const workspaceItems = workspaces.map((workspace) => ({ + label: workspace.name, + value: workspace.id, + })) + + const projectItems = projects.map((project) => ({ + label: project.name, + value: project.id, + })) + + const columnItems = taskPhases.map((phase) => ({ + label: phase.name, + value: phase.id, + })) + + const selectedPhase = taskPhases.find((phase) => phase.id === taskPhaseId) + + const resetForm = () => { + setWorkspaceId('') + setProjectId('') + setTaskPhaseId('') + setTitle('') + } + + const handleClose = () => { + setOpen(false) + resetForm() + } + + useEffect(() => { + if (open) { + setTitle(ticketSubject) + } + }, [open, ticketSubject]) + + const handleCreateTask = () => { + const trimmedTitle = title.trim() + + if (!workspaceId) { + toast.error(t('ticket.select_workspace_required')) + return + } + + if (!projectId) { + toast.error(t('ticket.select_project_required')) + return + } + + if (!taskPhaseId) { + toast.error(t('ticket.select_column_required')) + return + } + + if (!trimmedTitle) { + toast.error(t('errors.required')) + return + } + + createTask.mutate( + { + title: trimmedTitle, + taskPhaseId, + order: selectedPhase?.tasks?.length ?? 0, + projectId, + }, + { + onSuccess: () => { + toast.success(t('ticket.create_task_success')) + handleClose() + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message[0]) + }, + }, + ) + } + + const isLoadingOptions = getWorkspaces.isPending || getProjects.isPending || getProject.isPending + + return ( +
+
+ {t('ticket.create_task')} +
+ +
+
+ + + { + isLoadingOptions && !workspaceItems.length ? +
+ +
+ : +
+ { + setProjectId(e.target.value) + setTaskPhaseId('') + }} + className='border' + disabled={!workspaceId || getProjects.isPending} + /> + + setTitle(e.target.value)} + /> + +
+
+
+ } +
+
+ ) +} + +export default CreateTaskFromTicket