Create task in tocker

This commit is contained in:
hamid zarghami
2026-07-15 10:48:27 +03:30
parent 443d97f898
commit 1413744b6f
4 changed files with 230 additions and 2 deletions
+1 -1
View File
@@ -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'
VITE_BASE_URL = 'http://192.168.1.107:3500'
+10 -1
View File
@@ -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": "غیرفعال",
+8
View File
@@ -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 = () => {
</div>
</div>
{
getMessages.data?.data?.ticket?.status !== 'CLOSED' &&
<CreateTaskFromTicket
ticketSubject={getMessages.data?.data?.ticket?.subject ?? ''}
/>
}
{
<ReferTicket refetch={getMessages.refetch} />
}
@@ -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<Props> = ({ 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 (
<div className='bg-white p-6 rounded-3xl mt-8'>
<div className='text-sm'>
{t('ticket.create_task')}
</div>
<div className='flex justify-end mt-4'>
<Button
label={t('ticket.create_task')}
onClick={() => setOpen(true)}
className='w-fit px-7'
/>
</div>
<DefaulModal
open={open}
close={handleClose}
isHeader
title_header={t('ticket.create_task_modal_title')}
>
{
isLoadingOptions && !workspaceItems.length ?
<div className='py-8'>
<PageLoading />
</div>
:
<div className='mt-4 flex flex-col gap-6'>
<Select
label={t('taskmanager.workspacename')}
placeholder={t('taskmanager.select_workspace')}
items={workspaceItems}
value={workspaceId}
onChange={(e) => {
setWorkspaceId(e.target.value)
setProjectId('')
setTaskPhaseId('')
}}
className='border'
/>
<Select
label={t('taskmanager.project_name')}
placeholder={t('ticket.select_project')}
items={projectItems}
value={projectId}
onChange={(e) => {
setProjectId(e.target.value)
setTaskPhaseId('')
}}
className='border'
disabled={!workspaceId || getProjects.isPending}
/>
<Select
label={t('ticket.column')}
placeholder={t('ticket.select_column')}
items={columnItems}
value={taskPhaseId}
onChange={(e) => setTaskPhaseId(e.target.value)}
className='border'
disabled={!projectId || getProject.isPending}
/>
<Input
label={t('taskmanager.task_title')}
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<div className='flex justify-end'>
<Button
label={t('ticket.create_task')}
onClick={handleCreateTask}
isLoading={createTask.isPending}
className='w-fit px-7'
/>
</div>
</div>
}
</DefaulModal>
</div>
)
}
export default CreateTaskFromTicket