fix(api): add validation for listing and seller in bid route feat(telemetry): add userId to MarketTelemetry style(globe): add null check for canvas element chore: add lint:fix script to package.json
181 lines
5.0 KiB
TypeScript
181 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { ChatModal } from "@/components/chat/ChatModal";
|
|
import {
|
|
Sheet,
|
|
SheetContent,
|
|
SheetDescription,
|
|
SheetHeader,
|
|
SheetTitle,
|
|
} from "@/components/ui/sheet";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import type { Chat } from "@/lib/hooks/use-chat";
|
|
import { useSession } from "@/lib/hooks/use-session";
|
|
import { ChatListItem } from "./ChatListItem";
|
|
|
|
interface MessagesPanelProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
onUnreadCountChange: (count: number) => void;
|
|
}
|
|
|
|
export function MessagesPanel({
|
|
open,
|
|
onOpenChange,
|
|
onUnreadCountChange,
|
|
}: MessagesPanelProps) {
|
|
const { user } = useSession();
|
|
const [chats, setChats] = useState<Chat[]>([]);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [selectedChatId, setSelectedChatId] = useState<string | null>(null);
|
|
const [showChatModal, setShowChatModal] = useState(false);
|
|
|
|
// Buscar chats do usuário
|
|
const fetchChats = async () => {
|
|
if (!user) return;
|
|
|
|
setIsLoading(true);
|
|
try {
|
|
const res = await fetch("/api/chats", {
|
|
credentials: "include",
|
|
});
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
setChats(data.chats || []);
|
|
|
|
// Calcular contagem de usuários únicos com não lidas
|
|
const uniqueUsersWithUnread = new Set<number>();
|
|
data.chats.forEach((chat: Chat) => {
|
|
const unreadCount =
|
|
chat.buyer_id === user.userId
|
|
? chat.buyer_unread_count
|
|
: chat.seller_unread_count;
|
|
const otherUserId =
|
|
chat.buyer_id === user.userId ? chat.seller_id : chat.buyer_id;
|
|
|
|
if (unreadCount > 0) {
|
|
uniqueUsersWithUnread.add(otherUserId);
|
|
}
|
|
});
|
|
|
|
onUnreadCountChange(uniqueUsersWithUnread.size);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("[CHAT-DEBUG] Erro ao buscar chats:", error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
const markAllAsRead = async () => {
|
|
try {
|
|
await fetch("/api/chats/mark-all-read", {
|
|
method: "POST",
|
|
credentials: "include",
|
|
});
|
|
// Atualizar estado local
|
|
setChats((prev) =>
|
|
prev.map((chat) => ({
|
|
...chat,
|
|
buyer_unread_count:
|
|
chat.buyer_id === user?.userId ? 0 : chat.buyer_unread_count,
|
|
seller_unread_count:
|
|
chat.seller_id === user?.userId ? 0 : chat.seller_unread_count,
|
|
})),
|
|
);
|
|
onUnreadCountChange(0);
|
|
} catch (error) {
|
|
console.error("[CHAT-DEBUG] Erro ao marcar como lido:", error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (open && user) {
|
|
fetchChats();
|
|
// Marcar todos como lidos ao abrir
|
|
markAllAsRead();
|
|
}
|
|
}, [
|
|
open,
|
|
user,
|
|
fetchChats, // Marcar todos como lidos ao abrir
|
|
markAllAsRead,
|
|
]);
|
|
|
|
const handleChatClick = (chatId: string, _listingId: number) => {
|
|
setSelectedChatId(chatId);
|
|
setShowChatModal(true);
|
|
onOpenChange(false);
|
|
};
|
|
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
<SheetContent side="right" className="w-full sm:max-w-lg p-0">
|
|
<SheetHeader className="px-6 pt-6 pb-4 border-b">
|
|
<SheetTitle>Mensagens</SheetTitle>
|
|
<SheetDescription>
|
|
Suas conversas com compradores e vendedores
|
|
</SheetDescription>
|
|
</SheetHeader>
|
|
|
|
<div
|
|
className="mt-4 px-4 overflow-y-auto"
|
|
style={{ maxHeight: "calc(100vh - 120px)" }}
|
|
>
|
|
{isLoading ? (
|
|
<div className="space-y-4">
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
<Skeleton key={i} className="h-20 w-full" />
|
|
))}
|
|
</div>
|
|
) : chats.length === 0 ? (
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
<p>Nenhuma conversa ainda</p>
|
|
<p className="text-sm mt-2">
|
|
Comece uma conversa a partir de um anúncio
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-2">
|
|
{chats.map((chat) => (
|
|
<ChatListItem
|
|
key={chat.chat_id}
|
|
chat={chat}
|
|
currentUserId={user.userId}
|
|
onChatClick={() =>
|
|
handleChatClick(chat.chat_id, chat.listing_id)
|
|
}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</SheetContent>
|
|
</Sheet>
|
|
|
|
{selectedChatId && (
|
|
<ChatModal
|
|
open={showChatModal}
|
|
onOpenChange={(open) => {
|
|
setShowChatModal(open);
|
|
if (!open) {
|
|
setSelectedChatId(null);
|
|
// Recarregar chats quando fechar o modal
|
|
fetchChats();
|
|
}
|
|
}}
|
|
listingId={null}
|
|
chatId={selectedChatId || undefined}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|