Create task in tocker
This commit is contained in:
@@ -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
@@ -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": "غیرفعال",
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user