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_REFRESH_TOKEN_NAME = 'admin_refresh_token'
|
||||||
VITE_BASE_URL = 'https://api.danakcorp.com'
|
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": "کارشناس پاسخگویی",
|
"assign_to": "کارشناس پاسخگویی",
|
||||||
"user_plan": "پلن کاربر",
|
"user_plan": "پلن کاربر",
|
||||||
"refer_ticket_success": "تیکت با موفقیت ارجاع شد",
|
"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": "فعال",
|
"active": "فعال",
|
||||||
"inactive": "غیرفعال",
|
"inactive": "غیرفعال",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { clx } from '../../helpers/utils'
|
|||||||
import { Pages } from '../../config/Pages'
|
import { Pages } from '../../config/Pages'
|
||||||
import { useMultiUpload } from '../service/hooks/useServiceData'
|
import { useMultiUpload } from '../service/hooks/useServiceData'
|
||||||
import ReferTicket from './components/ReferTicket'
|
import ReferTicket from './components/ReferTicket'
|
||||||
|
import CreateTaskFromTicket from './components/CreateTaskFromTicket'
|
||||||
|
|
||||||
const TicketDetail: FC = () => {
|
const TicketDetail: FC = () => {
|
||||||
|
|
||||||
@@ -310,6 +311,13 @@ const TicketDetail: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
getMessages.data?.data?.ticket?.status !== 'CLOSED' &&
|
||||||
|
<CreateTaskFromTicket
|
||||||
|
ticketSubject={getMessages.data?.data?.ticket?.subject ?? ''}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
<ReferTicket refetch={getMessages.refetch} />
|
<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