Files
Evandro Fonseca Junior 6adc8d96e8 refactor: reorganize hooks and add safety checks
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
2025-11-11 03:20:01 -03:00

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}
/>
)}
</>
);
}