diff --git a/src/pages/requests/components/TicketMessage.tsx b/src/pages/chat/components/ChatMessage.tsx similarity index 83% rename from src/pages/requests/components/TicketMessage.tsx rename to src/pages/chat/components/ChatMessage.tsx index 18d16a2..b467f8e 100644 --- a/src/pages/requests/components/TicketMessage.tsx +++ b/src/pages/chat/components/ChatMessage.tsx @@ -5,11 +5,11 @@ import { getFileNameAndExtensionFromUrl } from '@/config/func' import { getPresignedUrl } from '@/pages/uploader/service/UploaderService' import VoicePlayer from '@/components/VoicePlayer' import UserAvatar from '@/components/UserAvatar' -import type { AttachmentsType } from '@/pages/order/types/Types' +import type { ChatAttachmentType } from '../type/Types' type Props = { content: string - attachments?: AttachmentsType[] + attachments?: ChatAttachmentType[] senderName?: string senderLabel?: string createdAt?: string @@ -19,7 +19,7 @@ type Props = { lastName?: string | null } -const TicketMessage: FC = ({ +const ChatMessage: FC = ({ content, attachments = [], senderName, @@ -61,7 +61,9 @@ const TicketMessage: FC = ({ {content && ( -

{content}

+

+ {content} +

)} {fileAttachments.length > 0 && ( @@ -75,7 +77,11 @@ const TicketMessage: FC = ({ > - {getFileNameAndExtensionFromUrl(attach.url).fileName} + { + getFileNameAndExtensionFromUrl( + attach.url, + ).fileName + } ))} @@ -91,7 +97,10 @@ const TicketMessage: FC = ({ )} {createdAt && ( -
+
{moment(createdAt).format('jYYYY/jMM/jDD HH:mm')}
)} @@ -101,4 +110,4 @@ const TicketMessage: FC = ({ ) } -export default TicketMessage +export default ChatMessage diff --git a/src/pages/requests/components/TicketSection.tsx b/src/pages/chat/components/ChatSection.tsx similarity index 64% rename from src/pages/requests/components/TicketSection.tsx rename to src/pages/chat/components/ChatSection.tsx index 960d168..467dacb 100644 --- a/src/pages/requests/components/TicketSection.tsx +++ b/src/pages/chat/components/ChatSection.tsx @@ -5,23 +5,48 @@ import { Microphone, Play, Pause } from 'iconsax-react' import { useState, type FC } from 'react' import { useVoiceRecorder } from '@/hooks/useVoiceRecorder' import { useMultiUpload, useSingleUpload } from '@/pages/uploader/hooks/useUploader' -import type { AddTicketType } from '@/pages/order/types/Types' -import { useAddTicket, useGetTickets } from '@/pages/order/hooks/useOrderData' -import { useParams } from 'react-router-dom' +import type { AddChatMessageType } from '../type/Types' +import { getChatSenderName } from '../type/Types' +import { useAddChatMessage, useGetChatMessages } from '../hooks/useChatData' import { toast } from '@/shared/toast' import { extractErrorMessage } from '@/config/func' -import TicketMessage from './TicketMessage' +import ChatMessage from './ChatMessage' -type Props = { +export type ChatSectionProps = { + refId: string + title?: string + description?: string + /** Label for admin / support / designer side */ + senderLabel?: string + /** Label for customer / user side */ + userLabel?: string + /** Optional fallback when message.user has no name */ customerName?: string + submitLabel?: string + uploadLabel?: string + showRefresh?: boolean } -const TicketSection: FC = ({ customerName }) => { - const { id } = useParams() +const ChatSection: FC = ({ + refId, + title = 'گفتگو', + description, + senderLabel = 'پشتیبان', + userLabel = 'مشتری', + customerName, + submitLabel = 'ارسال پیام', + uploadLabel = 'فایل‌های ضمیمه', + showRefresh = true, +}) => { const [message, setMessage] = useState('') const [files, setFiles] = useState([]) - const addTicket = useAddTicket() - const { data, refetch, isFetching, isPending: isLoadingTickets } = useGetTickets(id!) + const addMessage = useAddChatMessage() + const { + data, + refetch, + isFetching, + isPending: isLoadingMessages, + } = useGetChatMessages(refId) const singleUpload = useSingleUpload() const multiUpload = useMultiUpload() @@ -38,9 +63,9 @@ const TicketSection: FC = ({ customerName }) => { resetRecorder, } = useVoiceRecorder() - const tickets = data?.data ?? [] + const messages = data?.data ?? [] const isSubmitting = - singleUpload.isPending || multiUpload.isPending || addTicket.isPending + singleUpload.isPending || multiUpload.isPending || addMessage.isPending const handleSubmit = async () => { if (!message.trim() && !audioFile && files.length === 0) { @@ -48,7 +73,7 @@ const TicketSection: FC = ({ customerName }) => { return } - const params: AddTicketType = { + const params: AddChatMessageType = { attachments: [], content: message.trim(), } @@ -71,8 +96,8 @@ const TicketSection: FC = ({ customerName }) => { }) } - addTicket.mutate( - { orderId: id!, params }, + addMessage.mutate( + { refId, params }, { onSuccess: () => { toast('پیام شما با موفقیت ارسال شد') @@ -84,7 +109,7 @@ const TicketSection: FC = ({ customerName }) => { onError: (error) => { toast(extractErrorMessage(error), 'error') }, - } + }, ) } @@ -92,45 +117,53 @@ const TicketSection: FC = ({ customerName }) => {
-

گفتگو با مشتری

-

- پیام‌ها و فایل‌های مرتبط با درخواست -

+

{title}

+ {description && ( +

+ {description} +

+ )}
- refetch()} isLoading={isFetching} /> + {showRefresh && ( + refetch()} + isLoading={isFetching} + /> + )}
- {isLoadingTickets && tickets.length === 0 && ( -

در حال بارگذاری پیام‌ها...

+ {isLoadingMessages && messages.length === 0 && ( +

+ در حال بارگذاری پیام‌ها... +

)} - {!isLoadingTickets && tickets.length === 0 && ( + {!isLoadingMessages && messages.length === 0 && (
-

هنوز پیامی ثبت نشده است.

+

+ هنوز پیامی ثبت نشده است. +

اولین پیام را در فرم زیر ارسال کنید.

)} - {tickets.map((item) => { + {messages.map((item) => { if (item.user) { return ( - = ({ customerName }) => { if (item.admin) { return ( - = ({ customerName }) => { @@ -208,25 +253,35 @@ const TicketSection: FC = ({ customerName }) => { className="w-[2px] rounded-full transition-all" style={{ height: `${Math.random() * 18 + 4}px`, - backgroundColor: passed ? '#0047FF' : '#E5E7EB', + backgroundColor: passed + ? '#0047FF' + : '#E5E7EB', }} /> ) })}
-
)}
- +