Remove debug mode from chat and optimize image usage
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
'use client'
|
||||
import { useState, useRef, useEffect, useMemo } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { Trash, More, EmojiHappy, AttachCircle, Send, Shop, Call, VideoPlay } from 'iconsax-react'
|
||||
import { useSocket } from '../hooks/useSocket'
|
||||
import { Message as SocketMessage } from '../service/SocketService'
|
||||
import { useChatMessages, useMarkChatAsRead } from '../../hooks/useChatData'
|
||||
import { useChatDetail, useMarkChatAsRead } from '../../hooks/useChatData'
|
||||
import { isAuthenticated } from '@/config/func'
|
||||
import { ChatMessage as APIMessage } from '../../types/ProfileTypes'
|
||||
|
||||
@@ -23,26 +24,13 @@ interface ChatMessagesProps {
|
||||
|
||||
export default function ChatMessages({ productId, shopId, chatId }: ChatMessagesProps) {
|
||||
const [messageText, setMessageText] = useState('')
|
||||
const [debugInfo, setDebugInfo] = useState<string>('')
|
||||
const [isTyping, setIsTyping] = useState(false)
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null)
|
||||
const [isUserAuthenticated, setIsUserAuthenticated] = useState<boolean | null>(null)
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||
const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
// Server capabilities - temporarily disable features not implemented yet
|
||||
const SERVER_CAPABILITIES = {
|
||||
socketChat: false, // Socket.IO chat not implemented yet
|
||||
markAsRead: false, // markAsRead endpoint not implemented yet
|
||||
}
|
||||
|
||||
// Calculate currentChatId from props
|
||||
const currentChatId = chatId || (productId && shopId ? `chat_${shopId}_${productId}` : '')
|
||||
|
||||
const { data: chatData, isLoading, error } = useChatMessages(currentChatId, {
|
||||
enabled: isUserAuthenticated === true // Only fetch if user is logged in
|
||||
})
|
||||
const markedAsReadRef = useRef<Set<string>>(new Set())
|
||||
|
||||
// Check authentication on mount
|
||||
useEffect(() => {
|
||||
@@ -52,7 +40,6 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
}
|
||||
checkAuth()
|
||||
}, [])
|
||||
const markAsRead = useMarkChatAsRead()
|
||||
|
||||
const {
|
||||
isConnected,
|
||||
@@ -60,9 +47,14 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
leaveChat,
|
||||
sendMessage,
|
||||
onNewMessage,
|
||||
onError
|
||||
onError,
|
||||
connect
|
||||
} = useSocket()
|
||||
|
||||
const { data: chatData, isLoading, error } = useChatDetail(chatId)
|
||||
|
||||
const markAsRead = useMarkChatAsRead()
|
||||
|
||||
// Convert API messages to component format
|
||||
const messages: Message[] = useMemo(() =>
|
||||
chatData?.results?.messages?.map((msg: APIMessage) => ({
|
||||
@@ -85,31 +77,52 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
scrollToBottom()
|
||||
}, [messages])
|
||||
|
||||
// Join chat room when chatId is set and socket is connected (only if server supports it and user is logged in)
|
||||
// اتصال به چت وقتی chatId تنظیم شده و کاربر لاگین کرده
|
||||
useEffect(() => {
|
||||
if (currentChatId && currentChatId !== '' && isUserAuthenticated === true) {
|
||||
if (SERVER_CAPABILITIES.socketChat && isConnected) {
|
||||
console.log('🔗 اتصال به چت:', currentChatId)
|
||||
joinChat(currentChatId)
|
||||
return () => {
|
||||
leaveChat(currentChatId)
|
||||
if (chatId && chatId !== '' && isUserAuthenticated === true) {
|
||||
// اتصال به سوکت اگر متصل نیست
|
||||
if (!isConnected) {
|
||||
console.log('🔌 اتصال به سوکت برای چت...')
|
||||
connect().catch((error) => {
|
||||
console.error('❌ خطا در اتصال سوکت:', error.message)
|
||||
|
||||
// اگر توکن expired است، پیام نمایش بده
|
||||
if (error.message === 'توکن منقضی شده' || error.message === 'توکن یافت نشد') {
|
||||
console.log('🔐 توکن نامعتبر برای چت')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Mark messages as read only if server supports it
|
||||
if (SERVER_CAPABILITIES.markAsRead) {
|
||||
markAsRead.mutate(currentChatId)
|
||||
// اتصال به چت
|
||||
if (isConnected) {
|
||||
console.log('🔗 اتصال به چت:', chatId)
|
||||
joinChat(chatId)
|
||||
return () => {
|
||||
leaveChat(chatId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [chatId, isConnected, joinChat, leaveChat, connect, isUserAuthenticated])
|
||||
|
||||
// Mark messages as read - فقط یک بار برای هر chatId
|
||||
useEffect(() => {
|
||||
if (chatId && chatId !== '' && isUserAuthenticated === true && isConnected) {
|
||||
// بررسی اینکه آیا قبلاً برای این chatId mark as read کردهایم
|
||||
if (!markedAsReadRef.current.has(chatId)) {
|
||||
console.log('📖 mark as read برای چت:', chatId)
|
||||
markedAsReadRef.current.add(chatId)
|
||||
markAsRead.mutate(chatId)
|
||||
} else {
|
||||
console.log('ℹ️ markAsRead غیرفعال است (سرور هنوز پشتیبانی نمیکند)')
|
||||
console.log('ℹ️ چت قبلاً mark as read شده:', chatId)
|
||||
}
|
||||
}
|
||||
}, [currentChatId, isConnected, joinChat, leaveChat, markAsRead, SERVER_CAPABILITIES.socketChat, SERVER_CAPABILITIES.markAsRead, isUserAuthenticated])
|
||||
}, [chatId, isUserAuthenticated, isConnected, markAsRead])
|
||||
|
||||
// Listen for new messages
|
||||
useEffect(() => {
|
||||
const handleNewMessage = (socketMessage: unknown) => {
|
||||
const message = socketMessage as SocketMessage
|
||||
if (message.chatId === currentChatId) {
|
||||
if (message.chatId === chatId) {
|
||||
// The message will be added via React Query invalidation
|
||||
// or we can update local state if needed
|
||||
console.log('New message received:', message)
|
||||
@@ -119,7 +132,6 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
const handleError = (error: unknown) => {
|
||||
const err = error as { message: string }
|
||||
console.error('🚨 خطای چت:', err.message)
|
||||
setDebugInfo(`خطا: ${err.message}`)
|
||||
// You can show a toast notification here
|
||||
if (err.message === 'اتصال سوکت برقرار نیست') {
|
||||
console.warn('⚠️ راهنمایی: اگر این خطا تکرار میشود، احتمالاً سرور سوکت اجرا نمیشود یا قابل دسترسی نیست.')
|
||||
@@ -132,13 +144,13 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
return () => {
|
||||
// Cleanup will be handled by the hook
|
||||
}
|
||||
}, [currentChatId, onNewMessage, onError])
|
||||
}, [chatId, onNewMessage, onError])
|
||||
|
||||
const handleTyping = () => {
|
||||
if (!isTyping) {
|
||||
setIsTyping(true)
|
||||
// Here you could emit a typing event to the server
|
||||
// socketService.emit('typing', { chatId: currentChatId })
|
||||
// socketService.emit('typing', { chatId: chatId })
|
||||
}
|
||||
|
||||
// Clear previous timeout
|
||||
@@ -149,7 +161,7 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
// Set new timeout to stop typing indicator
|
||||
typingTimeoutRef.current = setTimeout(() => {
|
||||
setIsTyping(false)
|
||||
// socketService.emit('stopTyping', { chatId: currentChatId })
|
||||
// socketService.emit('stopTyping', { chatId: chatId })
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
@@ -166,7 +178,7 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
}
|
||||
|
||||
const handleSend = () => {
|
||||
if ((messageText.trim() || selectedFile) && currentChatId) {
|
||||
if ((messageText.trim() || selectedFile) && chatId) {
|
||||
const content = messageText.trim()
|
||||
setMessageText('')
|
||||
setIsTyping(false)
|
||||
@@ -180,7 +192,7 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
// For now, just send text message
|
||||
// TODO: Implement file upload when server supports it
|
||||
if (content) {
|
||||
sendMessage(currentChatId, content)
|
||||
sendMessage(chatId, content)
|
||||
}
|
||||
|
||||
// Scroll to bottom after sending
|
||||
@@ -189,23 +201,10 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
}
|
||||
|
||||
const chat = chatData?.results?.chat
|
||||
const seller = chat?.participants?.seller
|
||||
const seller = chat?.shopLogo
|
||||
|
||||
return (
|
||||
<div className="bg-white flex flex-col h-full">
|
||||
{/* Debug Info - فقط در محیط توسعه */}
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<div className="px-4 py-2 bg-yellow-50 border-b border-yellow-200 text-xs text-yellow-800">
|
||||
<div>🔍 دیباگ چت:</div>
|
||||
<div>ChatId: {currentChatId || 'خالی'}</div>
|
||||
<div>ProductId: {productId || 'خالی'}</div>
|
||||
<div>ShopId: {shopId || 'خالی'}</div>
|
||||
<div>Socket: {isConnected ? '🟢 متصل' : '🔴 قطع'}</div>
|
||||
<div>Server Capabilities: Socket={SERVER_CAPABILITIES.socketChat ? '✅' : '❌'}, MarkAsRead={SERVER_CAPABILITIES.markAsRead ? '✅' : '❌'}</div>
|
||||
{debugInfo && <div className="mt-1 text-red-600">{debugInfo}</div>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Header */}
|
||||
<div className="px-6 py-4 border-b border-gray-100 bg-white">
|
||||
{isLoading ? (
|
||||
@@ -226,23 +225,22 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
<div className="relative">
|
||||
<div className="w-10 h-10 bg-gradient-to-br from-primary/10 to-primary/20 rounded-full flex items-center justify-center overflow-hidden">
|
||||
{seller.logo ? (
|
||||
<img
|
||||
<Image
|
||||
src={seller.logo}
|
||||
alt={seller.shopName}
|
||||
className="w-full h-full object-cover"
|
||||
alt={chat?.sellerRef || 'فروشگاه'}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
) : (
|
||||
<Shop size={18} className="text-primary" variant="Bold" />
|
||||
)}
|
||||
</div>
|
||||
{chat?.isOnline && (
|
||||
<div className="absolute -bottom-0.5 -right-0.5 w-3 h-3 bg-green-500 border-2 border-white rounded-full"></div>
|
||||
)}
|
||||
{/* وضعیت آنلاین در این API موجود نیست */}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900 text-sm">{seller.shopName}</h3>
|
||||
<h3 className="font-semibold text-gray-900 text-sm">{chat?.sellerRef || 'فروشگاه'}</h3>
|
||||
<p className="text-xs text-gray-500">
|
||||
{chat?.isOnline ? 'آنلاین' : 'آفلاین'}
|
||||
آفلاین
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -257,9 +255,9 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
<button
|
||||
onClick={() => {
|
||||
// TODO: Implement delete chat functionality
|
||||
console.log('🗑️ درخواست حذف چت:', currentChatId)
|
||||
console.log('🗑️ درخواست حذف چت:', chatId)
|
||||
if (confirm('آیا از حذف این گفتگو مطمئن هستید؟')) {
|
||||
// deleteChatMutation.mutate(currentChatId)
|
||||
// deleteChatMutation.mutate(chatId)
|
||||
alert('این قابلیت هنوز پیادهسازی نشده است.')
|
||||
}
|
||||
}}
|
||||
@@ -281,19 +279,15 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
|
||||
{/* Messages Area */}
|
||||
<div className="flex-1 overflow-y-auto bg-gray-50/30">
|
||||
{/* Server Status Alert */}
|
||||
{(!SERVER_CAPABILITIES.socketChat || !isConnected) && (
|
||||
{/* Socket Status Alert */}
|
||||
{!isConnected && (
|
||||
<div className="px-6 py-3">
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg px-4 py-3">
|
||||
<div className="text-xs text-blue-800 leading-relaxed">
|
||||
<div className="font-semibold mb-2">ℹ️ راهاندازی سرویس چت</div>
|
||||
<div className="font-semibold mb-2">ℹ️ اتصال به چت</div>
|
||||
<div className="space-y-1">
|
||||
<div>• سرور Socket.IO: پیادهسازی نشده</div>
|
||||
<div>• API markAsRead: پیادهسازی نشده</div>
|
||||
<div>• وضعیت: در حال توسعه توسط تیم بکند</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs opacity-75">
|
||||
چت در حالت آزمایشی کار میکند
|
||||
<div>• در حال اتصال به سرور چت...</div>
|
||||
<div>• لطفاً چند لحظه صبر کنید</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -332,7 +326,7 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
messages.map((message, index) => {
|
||||
const isFirstInGroup = index === 0 || messages[index - 1].sender !== message.sender
|
||||
const senderName = message.sender === 'admin' ?
|
||||
(seller?.shopName || 'فروشگاه') : 'شما'
|
||||
(chat?.sellerRef || 'فروشگاه') : 'شما'
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -391,7 +385,7 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
<div className="max-w-[70%]">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-xs text-gray-500 font-medium">
|
||||
{seller?.shopName || 'فروشگاه'}
|
||||
{chat?.sellerRef || 'فروشگاه'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="bg-white border border-gray-100 rounded-2xl px-4 py-3 shadow-sm">
|
||||
@@ -477,8 +471,8 @@ export default function ChatMessages({ productId, shopId, chatId }: ChatMessages
|
||||
|
||||
<button
|
||||
onClick={handleSend}
|
||||
disabled={(!messageText.trim() && !selectedFile) || (!SERVER_CAPABILITIES.socketChat && !isConnected)}
|
||||
className={`p-3 rounded-xl transition-all flex-shrink-0 ${(messageText.trim() || selectedFile) && (SERVER_CAPABILITIES.socketChat || isConnected)
|
||||
disabled={(!messageText.trim() && !selectedFile) || !isConnected}
|
||||
className={`p-3 rounded-xl transition-all flex-shrink-0 ${(messageText.trim() || selectedFile) && isConnected
|
||||
? 'bg-primary hover:bg-primary/90 text-primary-foreground shadow-lg'
|
||||
: 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
}`}
|
||||
|
||||
@@ -7,10 +7,11 @@ import {
|
||||
UpdateAddressType,
|
||||
WishlistResponse,
|
||||
CommentsResponse,
|
||||
ChatListResponse,
|
||||
ChatMessagesResponse,
|
||||
CreateChatRequest,
|
||||
CreateChatResponse,
|
||||
GetChatListResponse,
|
||||
ChatDetailResponse,
|
||||
} from "../types/ProfileTypes";
|
||||
|
||||
export const getProfile = async () => {
|
||||
@@ -54,15 +55,15 @@ export const changeEmail = async (email: string) => {
|
||||
};
|
||||
|
||||
// Chat Services
|
||||
export const getChatList = async (): Promise<ChatListResponse> => {
|
||||
const { data } = await axios.get("/chat/list");
|
||||
export const getChatList = async (): Promise<GetChatListResponse> => {
|
||||
const { data } = await axios.get("/chat/user");
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getChatMessages = async (
|
||||
export const getChatDetail = async (
|
||||
chatId: string
|
||||
): Promise<ChatMessagesResponse> => {
|
||||
const { data } = await axios.get(`/chat/${chatId}/messages`);
|
||||
): Promise<ChatDetailResponse> => {
|
||||
const { data } = await axios.get(`/chat/user/${chatId}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
@@ -359,9 +359,7 @@ export interface ChatMessagesResponse {
|
||||
}
|
||||
|
||||
export interface CreateChatRequest {
|
||||
productId: number;
|
||||
shopId: string;
|
||||
initialMessage?: string;
|
||||
sellerId: string;
|
||||
}
|
||||
|
||||
export interface CreateChatResponse {
|
||||
@@ -372,3 +370,67 @@ export interface CreateChatResponse {
|
||||
message?: ChatMessage;
|
||||
};
|
||||
}
|
||||
|
||||
// New Chat List Types
|
||||
export interface ChatListSeller {
|
||||
_id: string;
|
||||
fullName: string;
|
||||
}
|
||||
|
||||
export interface ChatListShopLogo {
|
||||
_id: string;
|
||||
address: string | null;
|
||||
logo: string;
|
||||
owner: string;
|
||||
}
|
||||
|
||||
export interface ChatListItem {
|
||||
_id: string;
|
||||
seller: ChatListSeller;
|
||||
sellerRef: string;
|
||||
user: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
shortId: number;
|
||||
lastMessage: string | null;
|
||||
shopLogo: ChatListShopLogo;
|
||||
}
|
||||
|
||||
export interface GetChatListResults {
|
||||
chats: ChatListItem[];
|
||||
}
|
||||
|
||||
export interface GetChatListResponse {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: GetChatListResults;
|
||||
}
|
||||
|
||||
// Chat Detail Types
|
||||
export interface ChatDetailShopLogo {
|
||||
_id: string;
|
||||
address: string | null;
|
||||
logo: string;
|
||||
owner: string;
|
||||
}
|
||||
|
||||
export interface ChatDetailItem {
|
||||
_id: string;
|
||||
seller: string;
|
||||
sellerRef: string;
|
||||
user: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
shortId: number;
|
||||
lastMessage: string | null;
|
||||
shopLogo: ChatDetailShopLogo;
|
||||
}
|
||||
|
||||
export interface ChatDetailResponse {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: {
|
||||
chat: ChatDetailItem;
|
||||
messages: ChatMessage[];
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user