361c761435
- Change IMessage interface to use senderRef instead of sender - Update message rendering logic to check if senderRef === 'Admin' for admin messages - All other messages are treated as seller messages
231 lines
9.8 KiB
TypeScript
231 lines
9.8 KiB
TypeScript
import { type FC, useState } from 'react'
|
||
import { useGetTicket, useAddTicketMessage } from './hooks/useTicketData'
|
||
import { useParams } from 'react-router-dom'
|
||
import { type IMessage, type TicketStatus } from './types/Types'
|
||
import PageLoading from '../../components/PageLoading'
|
||
import Error from '../../components/Error'
|
||
import StatusWithText from '../../components/StatusWithText'
|
||
import { formatDate } from '../../helpers/func'
|
||
import { MessageQuestion, User as UserIcon, Category, Calendar } from 'iconsax-react'
|
||
import Button from '@/components/Button'
|
||
import Textarea from '@/components/Textarea'
|
||
import UploadBox from '@/components/UploadBox'
|
||
|
||
const TicketMessages: FC = () => {
|
||
const { id } = useParams()
|
||
const { data, isLoading, refetch } = useGetTicket(id as string)
|
||
const [messageContent, setMessageContent] = useState('')
|
||
const [attachments, setAttachments] = useState<File[]>([])
|
||
|
||
const addMessageMutation = useAddTicketMessage()
|
||
|
||
if (isLoading) {
|
||
return (
|
||
<div className="flex justify-center items-center min-h-[400px]">
|
||
<PageLoading />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
if (!data) {
|
||
return (
|
||
<div className="flex justify-center items-center min-h-[400px]">
|
||
<Error errorText="تیکت یافت نشد" />
|
||
</div>
|
||
)
|
||
}
|
||
|
||
const ticket = data.results.ticket
|
||
const messages = data.results.messages
|
||
|
||
const getStatusVariant = (status: TicketStatus) => {
|
||
switch (status) {
|
||
case 'closed': return 'error'
|
||
case 'answered': return 'success'
|
||
case 'pending': return 'warning'
|
||
default: return 'warning'
|
||
}
|
||
}
|
||
|
||
const getStatusText = (status: TicketStatus) => {
|
||
switch (status) {
|
||
case 'closed': return 'بسته شده'
|
||
case 'answered': return 'پاسخ داده شده'
|
||
case 'pending': return 'در انتظار'
|
||
default: return status
|
||
}
|
||
}
|
||
|
||
const handleSendMessage = async () => {
|
||
if (!messageContent.trim()) return
|
||
|
||
try {
|
||
await addMessageMutation.mutateAsync({
|
||
ticketId: ticket._id,
|
||
params: {
|
||
content: messageContent,
|
||
attachments: [] // TODO: handle file uploads
|
||
}
|
||
})
|
||
setMessageContent('')
|
||
setAttachments([])
|
||
refetch()
|
||
} catch (error) {
|
||
console.error('Error sending message:', error)
|
||
}
|
||
}
|
||
|
||
const handleFileChange = (files: File[]) => {
|
||
setAttachments(files)
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* Ticket Info */}
|
||
<div className="bg-white rounded-2xl p-6 shadow-sm">
|
||
<div className="flex items-center gap-2 mb-4">
|
||
<MessageQuestion size={24} color="#2563eb" />
|
||
<h1 className="text-xl font-semibold">جزئیات تیکت</h1>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">شماره تیکت</div>
|
||
<div className="flex items-center gap-2">
|
||
<MessageQuestion size={16} color="#8C90A3" />
|
||
<span className="font-medium">{ticket.numericId}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">فروشنده</div>
|
||
<div className="flex items-center gap-2">
|
||
<UserIcon size={16} color="#8C90A3" />
|
||
<span>{ticket.seller?.fullName || '-'}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">موضوع</div>
|
||
<div className="font-medium">{ticket.subject}</div>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">دستهبندی</div>
|
||
<div className="flex items-center gap-2">
|
||
<Category size={16} color="#8C90A3" />
|
||
<span>{ticket.category?.title_fa || '-'}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">وضعیت</div>
|
||
<StatusWithText
|
||
variant={getStatusVariant(ticket.status)}
|
||
text={getStatusText(ticket.status)}
|
||
/>
|
||
</div>
|
||
|
||
<div className="space-y-1">
|
||
<div className="text-sm text-gray-500">تاریخ بروزرسانی</div>
|
||
<div className="flex items-center gap-2">
|
||
<Calendar size={16} color="#8C90A3" />
|
||
<span>{formatDate(ticket.updatedAt)}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Messages Section */}
|
||
<div className="bg-white rounded-2xl p-6 shadow-sm">
|
||
<h2 className="text-lg font-semibold mb-4">پیامها</h2>
|
||
|
||
<div className="space-y-4 max-h-96 overflow-y-auto">
|
||
{messages.length === 0 ? (
|
||
<div className="text-center py-8 text-gray-500">
|
||
هیچ پیامی یافت نشد
|
||
</div>
|
||
) : (
|
||
messages.map((message: IMessage) => {
|
||
const isAdmin = message.senderRef === 'Admin'
|
||
return (
|
||
<div
|
||
key={message._id}
|
||
className={`flex ${isAdmin ? 'justify-end' : 'justify-start'}`}
|
||
>
|
||
<div
|
||
className={`max-w-[70%] p-4 rounded-2xl ${
|
||
isAdmin
|
||
? 'bg-blue-500 text-white rounded-br-md'
|
||
: 'bg-gray-100 text-gray-900 rounded-bl-md'
|
||
}`}
|
||
>
|
||
<div className="text-sm mb-2">
|
||
{isAdmin ? 'ادمین' : 'فروشنده'}
|
||
</div>
|
||
<div className="whitespace-pre-wrap">
|
||
{message.content}
|
||
</div>
|
||
{message.attachments && message.attachments.length > 0 && (
|
||
<div className="mt-2 space-y-1">
|
||
{message.attachments.map((attachment, index) => (
|
||
<div
|
||
key={index}
|
||
className={`text-xs underline ${
|
||
isAdmin ? 'text-blue-100' : 'text-blue-600'
|
||
}`}
|
||
>
|
||
فایل ضمیمه: {attachment}
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
<div className={`text-xs mt-2 ${
|
||
isAdmin ? 'text-blue-100' : 'text-gray-500'
|
||
}`}>
|
||
{message.createdAt && formatDate(message.createdAt)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
})
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Send Message Form */}
|
||
<div className="bg-white rounded-2xl p-6 shadow-sm">
|
||
<h2 className="text-lg font-semibold mb-4">ارسال پیام جدید</h2>
|
||
|
||
<div className="space-y-4">
|
||
<Textarea
|
||
label="متن پیام"
|
||
placeholder="پیام خود را وارد کنید..."
|
||
value={messageContent}
|
||
onChange={(e) => setMessageContent(e.target.value)}
|
||
rows={4}
|
||
/>
|
||
|
||
<UploadBox
|
||
label="فایلهای ضمیمه (اختیاری)"
|
||
isMultiple={true}
|
||
onChange={handleFileChange}
|
||
isReset={attachments.length === 0}
|
||
/>
|
||
|
||
<div className="flex justify-end">
|
||
<Button
|
||
label="ارسال پیام"
|
||
onClick={handleSendMessage}
|
||
isLoading={addMessageMutation.isPending}
|
||
disabled={!messageContent.trim()}
|
||
className="w-fit"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default TicketMessages |