Files
shop-admin/src/pages/ticket/TicketMessages.tsx
T
hamid zarghami 361c761435 Fix sender detection logic to use senderRef field
- 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
2025-10-12 17:05:46 +03:30

231 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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