"use client"; import { Grid, List, Search, SortAsc, SortDesc, X } from "lucide-react"; import { useLocale } from "next-intl"; import { useEffect, useState } from "react"; import { AdCard } from "@/components/marketplace/AdCard"; import { CreateAdModal } from "@/components/marketplace/CreateAdModal"; import { MyAdsPanel } from "@/components/marketplace/MyAdsPanel"; import { MyPurchaseIntentionsPanel } from "@/components/marketplace/MyPurchaseIntentionsPanel"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Skeleton } from "@/components/ui/skeleton"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useInvalidateListings, useListings } from "@/lib/hooks/use-listings"; import { useMyPurchaseIntentions } from "@/lib/hooks/use-purchase-intentions"; import { useSession } from "@/lib/hooks/use-session"; import { useMarketTelemetry } from "@/lib/hooks/use-telemetry"; interface Listing { listing_id: number; seller_id: number; item_id: number; item_name: string; quantity: number; server_name: string; price_pix: number | null; price_tibia_coins: number | null; price_gold_coins: number | null; is_auction: boolean; description: string | null; listing_status: string; created_at: string; views_count: number; favorites_count: number; is_featured?: boolean; } interface InitialData { listings: Listing[]; total: number; page: number; pageSize: number; totalPages: number; } export default function MarketClient({ initial }: { initial: InitialData }) { const { user } = useSession(); const { trackSearch, trackFilter, trackPageView } = useMarketTelemetry(); const invalidateListings = useInvalidateListings(); const locale = useLocale(); const [page, setPage] = useState(initial.page || 1); const [pageSize] = useState(initial.pageSize || 20); const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); // Filtros const [searchQuery, setSearchQuery] = useState(""); const [serverName, setServerName] = useState(""); const [sortBy, setSortBy] = useState("created_at"); const [sortOrder, setSortOrder] = useState<"ASC" | "DESC">("DESC"); const [priceMin, setPriceMin] = useState(""); const [priceMax, setPriceMax] = useState(""); const [showCreateModal, setShowCreateModal] = useState(false); const [activeTab, setActiveTab] = useState("explore"); // Usar React Query para buscar listings com atualização automática const { listings, total, totalPages, isLoading: loading, } = useListings({ search: searchQuery || undefined, server_name: serverName || undefined, price_min: priceMin || undefined, price_max: priceMax || undefined, sortBy, sortOrder, page, pageSize, }); // Tracking de página useEffect(() => { trackPageView("marketplace"); }, [trackPageView]); const handleSearch = (query: string) => { setPage(1); setSearchQuery(query); if (query) { trackSearch(query, { server: serverName }); } }; const handleSort = (newSortBy: string) => { setPage(1); if (sortBy === newSortBy) { // Alternar ordem se já está ordenando por esse campo setSortOrder(sortOrder === "ASC" ? "DESC" : "ASC"); } else { setSortBy(newSortBy); setSortOrder("DESC"); } }; const handleFilter = (filters: Record) => { setPage(1); if (filters.server) setServerName(filters.server); if (filters.priceMin !== undefined) setPriceMin(String(filters.priceMin)); if (filters.priceMax !== undefined) setPriceMax(String(filters.priceMax)); trackFilter(filters); }; const clearFilters = () => { setSearchQuery(""); setServerName(""); setPriceMin(""); setPriceMax(""); setPage(1); }; const sortOptions = [ { value: "created_at", label: "Mais recentes", icon: SortDesc }, { value: "price_pix", label: "Menor preço (PIX)", icon: SortAsc }, { value: "views_count", label: "Mais populares", icon: SortDesc }, ]; const activeFiltersCount = [ searchQuery, serverName, priceMin, priceMax, ].filter(Boolean).length; return (
{/* Header com botão de criar anúncio */}

Marketplace

{activeTab === "explore" ? `${total} ${total === 1 ? "anúncio" : "anúncios"} disponíveis` : "Gerencie seus anúncios"}

{user && ( )}
{/* Tabs para Explorar, Meus Anúncios e Minhas Intenções */} Explorar {user && Meus Anúncios} {user && } {/* Aba: Explorar Anúncios */} {/* Barra de busca */}
handleSearch(e.target.value)} className="pl-10 pr-4" />
{/* Filtros e controles */}
{/* Filtro por servidor */} { setServerName(e.target.value); handleFilter({ server: e.target.value }); }} className="w-48" /> {/* Filtro por preço mínimo */} { setPriceMin(e.target.value); handleFilter({ priceMin: e.target.value ? parseFloat(e.target.value) : undefined, }); }} className="w-32" /> {/* Filtro por preço máximo */} { setPriceMax(e.target.value); handleFilter({ priceMax: e.target.value ? parseFloat(e.target.value) : undefined, }); }} className="w-32" /> {/* Ordenação */} Ordenar por {sortOptions.map((option) => { const Icon = option.icon; return ( handleSort(option.value)} className="flex items-center gap-2" > {option.label} {sortBy === option.value && (
)} ); })} {/* Toggle de visualização */}
{/* Limpar filtros */} {activeFiltersCount > 0 && ( )}
{/* Badges de filtros ativos */} {activeFiltersCount > 0 && (
{searchQuery && ( Busca: {searchQuery} { setSearchQuery(""); setPage(1); }} /> )} {serverName && ( Servidor: {serverName} { setServerName(""); setPage(1); }} /> )} {(priceMin || priceMax) && ( Preço: {priceMin || "0"} - {priceMax || "∞"} { setPriceMin(""); setPriceMax(""); setPage(1); }} /> )}
)} {/* Listagem de anúncios */} {loading ? (
{Array.from({ length: 8 }).map((_, i) => ( ))}
) : listings.length === 0 ? (

Nenhum anúncio encontrado

Tente ajustar os filtros ou criar um novo anúncio

) : ( <>
{listings.map((listing) => ( ))}
{/* Paginação */} {totalPages > 1 && (
Página {page} de {totalPages}
)} )} {/* Modal de criação de anúncio */} {showCreateModal && ( { setShowCreateModal(false); // Invalidar cache para recarregar lista automaticamente invalidateListings(); // Se estiver na aba explore, mudar para meus anúncios para ver o novo if (activeTab === "explore") { setActiveTab("my-ads"); } }} /> )} {/* Aba: Meus Anúncios */} {user && ( )} {/* Aba: Minhas Intenções */} {user && ( )}
); } // Componente para o trigger da tab com badge de contador function MyPurchaseIntentionsTabTrigger() { const { intentions } = useMyPurchaseIntentions(); const pendingCount = intentions.filter((i) => i.status === "pending").length; return ( Minhas Intenções {pendingCount > 0 && ( {pendingCount} )} ); }