ticket list + create ticket
This commit is contained in:
+55
-80
@@ -1,28 +1,18 @@
|
||||
import { type FC, Fragment, useState } from 'react'
|
||||
// import { useTranslation } from 'react-i18next'
|
||||
import Input from '../../components/Input'
|
||||
import Textarea from '@/components/Textarea'
|
||||
import UploadBox from '../../components/UploadBox'
|
||||
import Button from '../../components/Button'
|
||||
import { CloseCircle, InfoCircle, Paperclip2, Send2 } from 'iconsax-react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { type MessageType, type AttachmentType } from './types/TicketTypes'
|
||||
// import { useAddMessageTicket, useCloseTicket, useGetMessages, useMultiUpload } from './hooks/useTicketData'
|
||||
import { staticTicketDetailData } from './data/staticData'
|
||||
// import PageLoading from '../../components/PageLoading'
|
||||
import { useGetTicketById, useCreateOrReplyTicket } from './hooks/useTicketData'
|
||||
import moment from 'moment-jalaali'
|
||||
// import { useFormik } from 'formik'
|
||||
// import { type AddMessageTicketType } from './types/TicketTypes'
|
||||
// import * as Yup from 'yup'
|
||||
// import { toast } from '../../components/Toast'
|
||||
// import { type ErrorType } from '../../helpers/types'
|
||||
import { clx } from '../../helpers/utils'
|
||||
import { fa } from '@/locale/fa'
|
||||
// import { Pages } from '../../config/Pages'
|
||||
import { Paths } from '@/config/Paths'
|
||||
|
||||
const TicketDetail: FC = () => {
|
||||
|
||||
// const { t } = useTranslation('global')
|
||||
const t = (key: string) => {
|
||||
const keys = key.split('.');
|
||||
let value: unknown = fa;
|
||||
@@ -32,57 +22,45 @@ const TicketDetail: FC = () => {
|
||||
return (value as string) || key;
|
||||
}
|
||||
const navigate = useNavigate()
|
||||
// const { id: _id } = useParams()
|
||||
const [, setFiles] = useState<File[]>([])
|
||||
const [percent] = useState<number>(0)
|
||||
// const getMessages = useGetMessages(id ? id : '')
|
||||
// const addMessage = useAddMessageTicket(id ? id : '')
|
||||
// const multiUpload = useMultiUpload(setPercent)
|
||||
// const closeTicket = useCloseTicket()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const [content, setContent] = useState('')
|
||||
const [files, setFiles] = useState<File[]>([])
|
||||
|
||||
// استفاده از دادههای استاتیک
|
||||
const getMessages = {
|
||||
isPending: false,
|
||||
data: staticTicketDetailData
|
||||
}
|
||||
const addMessage = {
|
||||
isPending: false,
|
||||
mutate: () => { },
|
||||
mutateAsync: () => Promise.resolve()
|
||||
}
|
||||
const multiUpload = {
|
||||
isPending: false,
|
||||
mutateAsync: () => Promise.resolve()
|
||||
}
|
||||
const closeTicket = {
|
||||
isPending: false,
|
||||
mutate: () => { }
|
||||
}
|
||||
const [isResetFiles] = useState<boolean>(false)
|
||||
const getTicket = useGetTicketById(id ?? '')
|
||||
const addMessage = useCreateOrReplyTicket()
|
||||
|
||||
// Mock formik
|
||||
const formik = {
|
||||
values: {
|
||||
content: '',
|
||||
attachmentUrls: [],
|
||||
},
|
||||
handleChange: () => { },
|
||||
handleSubmit: () => { },
|
||||
resetForm: () => { },
|
||||
touched: { content: false },
|
||||
errors: { content: '' }
|
||||
const raw = getTicket.data?.data
|
||||
const ticket = raw?.ticket ?? raw
|
||||
const messages: MessageType[] = raw?.messages ?? raw?.ticket?.messages ?? []
|
||||
|
||||
const handleSendReply = () => {
|
||||
if (!id || !content.trim()) return
|
||||
addMessage.mutate(
|
||||
{
|
||||
parentId: id,
|
||||
subject: (ticket as { subject?: string })?.subject ?? '',
|
||||
content: content.trim(),
|
||||
attachments: files.length ? files.map(() => ({})) : [],
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
setContent('')
|
||||
setFiles([])
|
||||
getTicket.refetch()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const hadleCloseTicket = () => {
|
||||
closeTicket.mutate()
|
||||
navigate('/tickets')
|
||||
navigate(Paths.tickets.list)
|
||||
}
|
||||
|
||||
const handleSendAnswer = () => {
|
||||
const messageEndRef = document.getElementById('content');
|
||||
const messageEndRef = document.getElementById('content')
|
||||
if (messageEndRef) {
|
||||
messageEndRef.scrollIntoView({ behavior: 'smooth' });
|
||||
messageEndRef.focus();
|
||||
messageEndRef.scrollIntoView({ behavior: 'smooth' })
|
||||
messageEndRef.focus()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,31 +70,31 @@ const TicketDetail: FC = () => {
|
||||
<div>{t('ticket.ticket_number')}</div>
|
||||
</div>
|
||||
{
|
||||
getMessages.isPending ?
|
||||
getTicket.isPending ?
|
||||
<div>Loading...</div>
|
||||
:
|
||||
<div className='flex xl:flex-row flex-col-reverse gap-6 xl:mt-8 mt-6'>
|
||||
<div className='flex-1 bg-white py-8 xl:px-10 px-4 rounded-3xl'>
|
||||
<Input
|
||||
label={t('ticket.subject')}
|
||||
value={getMessages.data?.data?.ticket?.subject}
|
||||
value={(ticket as { subject?: string })?.subject}
|
||||
readOnly
|
||||
/>
|
||||
<div className='gap-6 rowTwoInput mt-5'>
|
||||
<Input
|
||||
label={t('ticket.select_your_service')}
|
||||
value={getMessages.data?.data?.ticket?.danakService?.name}
|
||||
value={(ticket as { danakService?: { name?: string } })?.danakService?.name}
|
||||
readOnly
|
||||
/>
|
||||
<Input
|
||||
label={t('ticket.user_name')}
|
||||
value={getMessages.data?.data?.ticket?.user?.firstName + ' ' + getMessages.data?.data?.ticket?.user?.lastName}
|
||||
value={[(ticket as { user?: { firstName?: string; lastName?: string } })?.user?.firstName, (ticket as { user?: { lastName?: string } })?.user?.lastName].filter(Boolean).join(' ')}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
getMessages.data?.data?.messages.map((item: MessageType) => {
|
||||
messages.map((item: MessageType) => {
|
||||
if (item?.author?.roles[0]?.name === 'user') {
|
||||
return (
|
||||
<div key={item.id} className='mt-6 xl:text-sm text-xs bg-[#F6F7FA] p-6 rounded-3xl rounded-tr-none xl:max-w-[70%] max-w-[90%]'>
|
||||
@@ -184,16 +162,14 @@ const TicketDetail: FC = () => {
|
||||
|
||||
|
||||
{
|
||||
getMessages.data?.data?.ticket?.status !== 'CLOSED' &&
|
||||
(ticket as { status?: string })?.status !== 'CLOSED' &&
|
||||
<Fragment>
|
||||
<div className='mt-9'>
|
||||
<Textarea
|
||||
id='content'
|
||||
placeholder={t('ticket.your_description')}
|
||||
name='content'
|
||||
value={formik.values.content}
|
||||
onChange={formik.handleChange}
|
||||
error_text={formik.touched.content && formik.errors.content ? formik.errors.content : ''}
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -202,16 +178,14 @@ const TicketDetail: FC = () => {
|
||||
label={t('ticket.attachment')}
|
||||
onChange={setFiles}
|
||||
isMultiple
|
||||
isReset={isResetFiles}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-end mt-6'>
|
||||
<Button
|
||||
className='xl:max-w-[100px]'
|
||||
onClick={() => formik.handleSubmit()}
|
||||
percentage={percent}
|
||||
isLoading={addMessage.isPending || multiUpload.isPending}
|
||||
onClick={handleSendReply}
|
||||
isLoading={addMessage.isPending}
|
||||
>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Send2 size={20} color='black' />
|
||||
@@ -227,7 +201,7 @@ const TicketDetail: FC = () => {
|
||||
</div>
|
||||
<div className={`h-fit lg:sticky left-0 lg:top-0 xl:w-[300px] w-full`}>
|
||||
{
|
||||
getMessages.data?.data?.ticket?.status !== 'CLOSED' &&
|
||||
(ticket as { status?: string })?.status !== 'CLOSED' &&
|
||||
<div className='bg-white xl:p-6 p-4 rounded-3xl flex gap-4'>
|
||||
<Button
|
||||
label={t('ticket.send_answer')}
|
||||
@@ -237,7 +211,6 @@ const TicketDetail: FC = () => {
|
||||
<Button
|
||||
className='bg-[#D52903] xl:h-10 h-8'
|
||||
onClick={hadleCloseTicket}
|
||||
isLoading={closeTicket.isPending}
|
||||
>
|
||||
<div className='flex gap-2 text-xs items-center'>
|
||||
<CloseCircle
|
||||
@@ -253,7 +226,7 @@ const TicketDetail: FC = () => {
|
||||
}
|
||||
<div className={clx(
|
||||
'bg-white p-6 rounded-3xl mt-8',
|
||||
getMessages.data?.data?.ticket?.status === 'CLOSED' && 'mt-0'
|
||||
(ticket as { status?: string })?.status === 'CLOSED' && 'mt-0'
|
||||
)}>
|
||||
<div className='flex justify-between'>
|
||||
<div className='text-sm'>
|
||||
@@ -261,10 +234,10 @@ const TicketDetail: FC = () => {
|
||||
</div>
|
||||
<div className={clx(
|
||||
'h-7 px-3 rounded-xl flex items-center text-xs bg-green-100 text-green-400',
|
||||
getMessages.data?.data?.ticket?.status === 'PENDING' && 'bg-orange-100 text-orange-700',
|
||||
getMessages.data?.data?.ticket?.status === 'CLOSED' && 'bg-red-100 text-red-400'
|
||||
(ticket as { status?: string })?.status === 'PENDING' && 'bg-orange-100 text-orange-700',
|
||||
(ticket as { status?: string })?.status === 'CLOSED' && 'bg-red-100 text-red-400'
|
||||
)}>
|
||||
{t(`ticket.${getMessages.data?.data?.ticket?.status}`)}
|
||||
{t(`ticket.${(ticket as { status?: string })?.status}`)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -272,31 +245,33 @@ const TicketDetail: FC = () => {
|
||||
<div className='flex justify-between text-description'>
|
||||
<div>{t('ticket.ticket_number')}</div>
|
||||
<div>
|
||||
{getMessages.data?.data?.ticket?.numericId}
|
||||
{(ticket as { numericId?: string })?.numericId}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex mt-6 justify-between text-description'>
|
||||
<div>{t('ticket.asignto')}</div>
|
||||
<div>
|
||||
{getMessages.data?.data?.ticket?.assignedTo ? getMessages.data?.data?.ticket?.assignedTo?.firstName + ' ' + getMessages.data?.data?.ticket?.assignedTo?.lastName : ''}
|
||||
{(ticket as { assignedTo?: { firstName?: string; lastName?: string } })?.assignedTo
|
||||
? [(ticket as { assignedTo?: { firstName?: string } })?.assignedTo?.firstName, (ticket as { assignedTo?: { lastName?: string } })?.assignedTo?.lastName].filter(Boolean).join(' ')
|
||||
: ''}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex mt-6 justify-between text-description'>
|
||||
<div>{t('date')}</div>
|
||||
<div className='dltr'>
|
||||
{moment(getMessages.data?.data?.ticket?.createdAt).format('jYYYY/jMM/jDD HH:mm')}
|
||||
{moment((ticket as { createdAt?: string })?.createdAt).format('jYYYY/jMM/jDD HH:mm')}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex mt-6 justify-between text-description'>
|
||||
<div>{t('ticket.category')}</div>
|
||||
<div>
|
||||
{getMessages.data?.data?.ticket?.category?.title}
|
||||
{(ticket as { category?: { title?: string } })?.category?.title}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex mt-6 justify-between text-description'>
|
||||
<div>{t('ticket.priority')}</div>
|
||||
<div>
|
||||
{getMessages.data?.data?.ticket?.priority === 'low' ? t('ticket.low') : getMessages.data?.data?.ticket?.priority === 'medium' ? t('ticket.medium') : t('ticket.high')}
|
||||
{(ticket as { priority?: string })?.priority === 'low' ? t('ticket.low') : (ticket as { priority?: string })?.priority === 'medium' ? t('ticket.medium') : t('ticket.high')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user