Remove debug mode from chat and optimize image usage

This commit is contained in:
hamid zarghami
2025-10-14 16:45:33 +03:30
parent 4378f0e5ef
commit 4af0082c03
3 changed files with 141 additions and 84 deletions
@@ -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)
} else {
console.log('️ markAsRead غیرفعال است (سرور هنوز پشتیبانی نمی‌کند)')
// اتصال به چت
if (isConnected) {
console.log('🔗 اتصال به چت:', chatId)
joinChat(chatId)
return () => {
leaveChat(chatId)
}
}
}
}, [currentChatId, isConnected, joinChat, leaveChat, markAsRead, SERVER_CAPABILITIES.socketChat, SERVER_CAPABILITIES.markAsRead, isUserAuthenticated])
}, [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('️ چت قبلاً mark as read شده:', chatId)
}
}
}, [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 -6
View File
@@ -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;
};
+65 -3
View File
@@ -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[];
};
}