718 lines
24 KiB
TypeScript
718 lines
24 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
AlertCircle,
|
|
CheckCircle2,
|
|
Clock,
|
|
Coins,
|
|
DollarSign,
|
|
ExternalLink,
|
|
MapPin,
|
|
MessageSquare,
|
|
Package,
|
|
RefreshCw,
|
|
ShoppingCart,
|
|
User,
|
|
XCircle,
|
|
} from "lucide-react";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
import { ChatModal } from "@/components/chat/ChatModal";
|
|
import { ChangePaymentMethodButton } from "@/components/purchase-intentions/ChangePaymentMethodButton";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import {
|
|
type PurchaseIntention,
|
|
type PurchaseIntentionStatus,
|
|
useMyPurchaseIntentions,
|
|
} from "@/lib/hooks/use-purchase-intentions";
|
|
import { useSession } from "@/lib/hooks/use-session";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
function formatTimeAgo(date: Date | string): string {
|
|
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
const seconds = Math.floor((Date.now() - dateObj.getTime()) / 1000);
|
|
if (seconds < 60) return "há alguns segundos";
|
|
const minutes = Math.floor(seconds / 60);
|
|
if (minutes < 60)
|
|
return `há ${minutes} ${minutes === 1 ? "minuto" : "minutos"}`;
|
|
const hours = Math.floor(minutes / 60);
|
|
if (hours < 24) return `há ${hours} ${hours === 1 ? "hora" : "horas"}`;
|
|
const days = Math.floor(hours / 24);
|
|
if (days < 30) return `há ${days} ${days === 1 ? "dia" : "dias"}`;
|
|
const months = Math.floor(days / 30);
|
|
if (months < 12) return `há ${months} ${months === 1 ? "mês" : "meses"}`;
|
|
const years = Math.floor(months / 12);
|
|
return `há ${years} ${years === 1 ? "ano" : "anos"}`;
|
|
}
|
|
|
|
function getStatusBadge(status: PurchaseIntentionStatus) {
|
|
switch (status) {
|
|
case "pending":
|
|
return (
|
|
<Badge
|
|
variant="secondary"
|
|
className="bg-yellow-500/20 text-yellow-700 dark:text-yellow-400"
|
|
>
|
|
<Clock className="h-3 w-3 mr-1" />
|
|
Pendente
|
|
</Badge>
|
|
);
|
|
case "accepted":
|
|
return (
|
|
<Badge
|
|
variant="secondary"
|
|
className="bg-green-500/20 text-green-700 dark:text-green-400"
|
|
>
|
|
<CheckCircle2 className="h-3 w-3 mr-1" />
|
|
Aceita
|
|
</Badge>
|
|
);
|
|
case "rejected":
|
|
return (
|
|
<Badge
|
|
variant="secondary"
|
|
className="bg-red-500/20 text-red-700 dark:text-red-400"
|
|
>
|
|
<XCircle className="h-3 w-3 mr-1" />
|
|
Rejeitada
|
|
</Badge>
|
|
);
|
|
case "expired":
|
|
return (
|
|
<Badge
|
|
variant="secondary"
|
|
className="bg-gray-500/20 text-gray-700 dark:text-gray-400"
|
|
>
|
|
<AlertCircle className="h-3 w-3 mr-1" />
|
|
Expirada
|
|
</Badge>
|
|
);
|
|
case "completed":
|
|
return (
|
|
<Badge
|
|
variant="secondary"
|
|
className="bg-blue-500/20 text-blue-700 dark:text-blue-400"
|
|
>
|
|
<CheckCircle2 className="h-3 w-3 mr-1" />
|
|
Concluída
|
|
</Badge>
|
|
);
|
|
default:
|
|
return <Badge variant="secondary">{status}</Badge>;
|
|
}
|
|
}
|
|
|
|
function getPaymentMethodLabel(method: string): string {
|
|
switch (method) {
|
|
case "pix":
|
|
return "PIX";
|
|
case "tibia_coins":
|
|
return "Tibia Coins";
|
|
case "gold_coins":
|
|
return "Gold Coins";
|
|
case "trade":
|
|
return "Troca";
|
|
default:
|
|
return method.toUpperCase();
|
|
}
|
|
}
|
|
|
|
function formatPrice(price: number | null, method: string): string {
|
|
if (price === null) return "N/A";
|
|
|
|
if (method === "pix") {
|
|
return new Intl.NumberFormat("pt-BR", {
|
|
style: "currency",
|
|
currency: "BRL",
|
|
}).format(price);
|
|
}
|
|
|
|
if (method === "tibia_coins") {
|
|
return `${price.toLocaleString("pt-BR")} TC`;
|
|
}
|
|
|
|
if (method === "gold_coins") {
|
|
const gold = price / 1000000;
|
|
if (gold >= 1) {
|
|
return `${gold.toFixed(2)}kk`;
|
|
}
|
|
return `${price.toLocaleString("pt-BR")} gp`;
|
|
}
|
|
|
|
return price.toLocaleString("pt-BR");
|
|
}
|
|
|
|
function formatCustomOffer(
|
|
amount: number | null | undefined,
|
|
currency: string | null | undefined,
|
|
): string | null {
|
|
if (amount === null || amount === undefined || !currency) {
|
|
return null;
|
|
}
|
|
|
|
switch (currency) {
|
|
case "pix":
|
|
return `R$ ${amount.toFixed(2)}`;
|
|
case "tibia_coins":
|
|
return `${Math.round(amount).toLocaleString("pt-BR")} TC`;
|
|
case "gold_coins":
|
|
return `${Math.round(amount).toLocaleString("pt-BR")} GP`;
|
|
default:
|
|
return amount.toLocaleString("pt-BR");
|
|
}
|
|
}
|
|
|
|
interface IntentionCardProps {
|
|
intention: PurchaseIntention;
|
|
locale?: string;
|
|
}
|
|
|
|
function IntentionCard({ intention, locale = "pt" }: IntentionCardProps) {
|
|
const listing = intention.listing;
|
|
const [showListingModal, setShowListingModal] = useState(false);
|
|
const [showChatModal, setShowChatModal] = useState(false);
|
|
|
|
if (!listing) {
|
|
return (
|
|
<Card className="border-dashed opacity-60">
|
|
<CardHeader className="pb-3">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="flex items-start gap-4 flex-1 min-w-0">
|
|
<div className="relative w-16 h-16 rounded-lg bg-muted flex items-center justify-center flex-shrink-0">
|
|
<AlertCircle className="h-8 w-8 text-muted-foreground" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<h3 className="font-semibold text-lg">
|
|
Anúncio não disponível
|
|
</h3>
|
|
{getStatusBadge(intention.status)}
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Este anúncio foi removido ou não está mais disponível
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-xs text-muted-foreground">
|
|
Intenção criada {formatTimeAgo(intention.created_at)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
const getItemImageUrl = () => {
|
|
if (listing.image_url) {
|
|
return listing.image_url;
|
|
}
|
|
if (listing.image_local_path) {
|
|
const normalizedPath = listing.image_local_path.replace(/\\/g, "/");
|
|
if (normalizedPath.startsWith("data/")) {
|
|
return `/api/images?path=${encodeURIComponent(normalizedPath)}`;
|
|
}
|
|
const category = listing.item_category || "other";
|
|
return `/api/images?path=${encodeURIComponent(`data/images/${category}/${normalizedPath}`)}`;
|
|
}
|
|
if (listing.item_id_unified) {
|
|
const params = new URLSearchParams({
|
|
item: listing.item_id_unified.toString(),
|
|
});
|
|
if (listing.item_name) {
|
|
params.set("name", listing.item_name);
|
|
}
|
|
return `/api/images?${params.toString()}`;
|
|
}
|
|
const params = new URLSearchParams({ item: listing.item_id.toString() });
|
|
if (listing.item_name) {
|
|
params.set("name", listing.item_name);
|
|
}
|
|
return `/api/images?${params.toString()}`;
|
|
};
|
|
|
|
const itemImageUrl = getItemImageUrl();
|
|
const chatId =
|
|
intention.chat_id ??
|
|
(listing.seller_id != null
|
|
? `${listing.listing_id}_${intention.buyer_id}_${listing.seller_id}`
|
|
: null);
|
|
|
|
const price =
|
|
listing.price_pix && intention.payment_method === "pix"
|
|
? listing.price_pix
|
|
: listing.price_tibia_coins && intention.payment_method === "tibia_coins"
|
|
? listing.price_tibia_coins
|
|
: listing.price_gold_coins && intention.payment_method === "gold_coins"
|
|
? listing.price_gold_coins
|
|
: null;
|
|
const customOfferLabel = formatCustomOffer(
|
|
typeof intention.custom_offer_amount === "number"
|
|
? intention.custom_offer_amount
|
|
: null,
|
|
intention.custom_offer_currency ?? null,
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Card className="hover:shadow-md transition-shadow">
|
|
<CardHeader className="pb-3">
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="flex items-start gap-4 flex-1 min-w-0">
|
|
<div className="relative w-16 h-16 rounded-lg bg-muted flex items-center justify-center flex-shrink-0 overflow-hidden">
|
|
{itemImageUrl ? (
|
|
<Image
|
|
src={itemImageUrl}
|
|
alt={listing.item_name}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
) : (
|
|
<Package className="h-8 w-8 text-muted-foreground" />
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<h3 className="font-semibold text-lg truncate">
|
|
{listing.item_name}
|
|
</h3>
|
|
{getStatusBadge(intention.status)}
|
|
</div>
|
|
<div className="flex items-center gap-4 text-sm text-muted-foreground mb-2">
|
|
<div className="flex items-center gap-1">
|
|
<MapPin className="h-3 w-3" />
|
|
<span>{listing.server_name}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<Package className="h-3 w-3" />
|
|
<span>Qtd: {listing.quantity}</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<ShoppingCart className="h-3 w-3" />
|
|
<span>
|
|
{getPaymentMethodLabel(intention.payment_method)}
|
|
</span>
|
|
{price !== null && (
|
|
<span className="font-medium text-foreground ml-1">
|
|
{formatPrice(price, intention.payment_method)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
{customOfferLabel && (
|
|
<div className="flex items-center gap-1 text-foreground">
|
|
<Badge
|
|
variant="outline"
|
|
className="border-primary text-primary"
|
|
>
|
|
Sua oferta: {customOfferLabel}
|
|
</Badge>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
|
|
<CardContent className="space-y-3">
|
|
{/* Informações do vendedor */}
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<User className="h-4 w-4 text-muted-foreground" />
|
|
<span className="text-muted-foreground">Vendedor:</span>
|
|
<span className="font-medium">
|
|
{listing.seller_character_name ||
|
|
listing.seller_username ||
|
|
"Desconhecido"}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Mensagem do comprador */}
|
|
{intention.buyer_message && (
|
|
<div className="bg-muted/50 rounded-md p-3">
|
|
<div className="flex items-start gap-2">
|
|
<MessageSquare className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
|
|
<div className="flex-1 min-w-0">
|
|
<p className="text-xs text-muted-foreground mb-1">
|
|
Sua mensagem:
|
|
</p>
|
|
<p className="text-sm">{intention.buyer_message}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Resposta do vendedor */}
|
|
{intention.seller_response && (
|
|
<div
|
|
className={cn(
|
|
"rounded-md p-3 border",
|
|
intention.status === "accepted"
|
|
? "bg-green-500/10 border-green-500/20"
|
|
: intention.status === "rejected"
|
|
? "bg-red-500/10 border-red-500/20"
|
|
: "bg-blue-500/10 border-blue-500/20",
|
|
)}
|
|
>
|
|
<div className="flex items-start gap-2">
|
|
<MessageSquare
|
|
className={cn(
|
|
"h-4 w-4 mt-0.5 flex-shrink-0",
|
|
intention.status === "accepted"
|
|
? "text-green-600 dark:text-green-400"
|
|
: intention.status === "rejected"
|
|
? "text-red-600 dark:text-red-400"
|
|
: "text-blue-600 dark:text-blue-400",
|
|
)}
|
|
/>
|
|
<div className="flex-1 min-w-0">
|
|
<p className="text-xs font-medium mb-1">
|
|
{intention.status === "accepted"
|
|
? "Resposta do vendedor (Aceita):"
|
|
: intention.status === "rejected"
|
|
? "Resposta do vendedor (Rejeitada):"
|
|
: "Resposta do vendedor:"}
|
|
</p>
|
|
<p className="text-sm">{intention.seller_response}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Timestamps */}
|
|
<div className="flex items-center justify-between text-xs text-muted-foreground pt-2 border-t">
|
|
<div className="flex items-center gap-1">
|
|
<Clock className="h-3 w-3" />
|
|
<span>Criada {formatTimeAgo(intention.created_at)}</span>
|
|
</div>
|
|
{intention.updated_at !== intention.created_at && (
|
|
<span>Atualizada {formatTimeAgo(intention.updated_at)}</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className="flex items-center gap-2 pt-2 flex-wrap">
|
|
{intention.status === "pending" &&
|
|
intention.payment_method_change_count < 1 && (
|
|
<ChangePaymentMethodButton
|
|
intentionId={intention.intention_id}
|
|
currentPaymentMethod={intention.payment_method}
|
|
availableMethods={[
|
|
...(listing.price_pix ? ["pix"] : []),
|
|
...(listing.price_tibia_coins ? ["tibia_coins"] : []),
|
|
...(listing.price_gold_coins ? ["gold_coins"] : []),
|
|
...(listing.trade_item_id ? ["trade"] : []),
|
|
]}
|
|
canChange={true}
|
|
/>
|
|
)}
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => setShowListingModal(true)}
|
|
className="flex-1"
|
|
>
|
|
<ExternalLink className="h-4 w-4 mr-2" />
|
|
Ver Anúncio
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="flex-1"
|
|
onClick={() => setShowChatModal(true)}
|
|
>
|
|
<MessageSquare className="h-4 w-4 mr-2" />
|
|
Abrir Chat
|
|
</Button>
|
|
{intention.status === "accepted" &&
|
|
listing.listing_status === "active" && (
|
|
<Button
|
|
size="sm"
|
|
onClick={() => setShowListingModal(true)}
|
|
className="flex-1"
|
|
>
|
|
<ShoppingCart className="h-4 w-4 mr-2" />
|
|
Comprar Agora
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Dialog open={showListingModal} onOpenChange={setShowListingModal}>
|
|
<DialogContent className="max-w-2xl">
|
|
<DialogHeader>
|
|
<DialogTitle>{listing.item_name}</DialogTitle>
|
|
<DialogDescription>
|
|
Detalhes do anúncio selecionado
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-[220px,1fr] gap-4">
|
|
<div className="relative w-full h-52 rounded-lg bg-muted overflow-hidden flex items-center justify-center">
|
|
{itemImageUrl ? (
|
|
<Image
|
|
src={itemImageUrl}
|
|
alt={listing.item_name}
|
|
fill
|
|
className="object-contain p-4"
|
|
/>
|
|
) : (
|
|
<Package className="h-12 w-12 text-muted-foreground" />
|
|
)}
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<div>
|
|
<h3 className="text-lg font-semibold">{listing.item_name}</h3>
|
|
<p className="text-sm text-muted-foreground mt-1">
|
|
{listing.description ??
|
|
"Sem descrição fornecida para este anúncio."}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-2 text-sm">
|
|
<div className="flex items-center gap-2 text-muted-foreground">
|
|
<MapPin className="h-4 w-4" />
|
|
<span>
|
|
Servidor:{" "}
|
|
<span className="font-medium text-foreground">
|
|
{listing.server_name}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-muted-foreground">
|
|
<Package className="h-4 w-4" />
|
|
<span>
|
|
Quantidade:{" "}
|
|
<span className="font-medium text-foreground">
|
|
{listing.quantity}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-muted-foreground">
|
|
<User className="h-4 w-4" />
|
|
<span>
|
|
Vendedor:{" "}
|
|
<span className="font-medium text-foreground">
|
|
{listing.seller_character_name ||
|
|
listing.seller_username ||
|
|
"Desconhecido"}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h4 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
|
|
Condições de pagamento
|
|
</h4>
|
|
<div className="flex flex-wrap gap-2">
|
|
{listing.price_pix && (
|
|
<Badge variant="secondary" className="gap-1">
|
|
<DollarSign className="h-3 w-3" />
|
|
{formatPrice(listing.price_pix, "pix")}
|
|
</Badge>
|
|
)}
|
|
{listing.price_tibia_coins && (
|
|
<Badge variant="secondary" className="gap-1">
|
|
<Coins className="h-3 w-3" />
|
|
{formatPrice(listing.price_tibia_coins, "tibia_coins")}
|
|
</Badge>
|
|
)}
|
|
{listing.price_gold_coins && (
|
|
<Badge variant="secondary" className="gap-1">
|
|
<Coins className="h-3 w-3" />
|
|
{formatPrice(listing.price_gold_coins, "gold_coins")}
|
|
</Badge>
|
|
)}
|
|
{listing.trade_item_id &&
|
|
listing.trade_item_name &&
|
|
listing.trade_item_quantity && (
|
|
<Badge variant="secondary" className="gap-1">
|
|
<RefreshCw className="h-3 w-3" />
|
|
{listing.trade_item_quantity}x {listing.trade_item_name}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button variant="outline" asChild>
|
|
<Link
|
|
href={`/${locale}/market?listing=${listing.listing_id}`}
|
|
target="_blank"
|
|
>
|
|
Abrir no marketplace
|
|
</Link>
|
|
</Button>
|
|
<Button
|
|
variant="default"
|
|
onClick={() => setShowChatModal(true)}
|
|
>
|
|
<MessageSquare className="h-4 w-4 mr-2" />
|
|
Continuar conversa
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
{listing && (
|
|
<ChatModal
|
|
open={showChatModal}
|
|
onOpenChange={setShowChatModal}
|
|
listingId={listing.listing_id}
|
|
chatId={chatId || undefined}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
interface MyPurchaseIntentionsPanelProps {
|
|
locale?: string;
|
|
}
|
|
|
|
export function MyPurchaseIntentionsPanel({
|
|
locale = "pt",
|
|
}: MyPurchaseIntentionsPanelProps) {
|
|
const { user } = useSession();
|
|
const [filter, setFilter] = useState<PurchaseIntentionStatus | "all">("all");
|
|
const { intentions, isLoading } = useMyPurchaseIntentions();
|
|
|
|
// Contar por status
|
|
const pendingCount = intentions.filter((i) => i.status === "pending").length;
|
|
const acceptedCount = intentions.filter(
|
|
(i) => i.status === "accepted",
|
|
).length;
|
|
const rejectedCount = intentions.filter(
|
|
(i) => i.status === "rejected",
|
|
).length;
|
|
const expiredCount = intentions.filter((i) => i.status === "expired").length;
|
|
const completedCount = intentions.filter(
|
|
(i) => i.status === "completed",
|
|
).length;
|
|
const filteredIntentions =
|
|
filter === "all"
|
|
? intentions
|
|
: intentions.filter((intention) => intention.status === filter);
|
|
|
|
if (!user) {
|
|
return (
|
|
<div className="text-center py-12">
|
|
<p className="text-muted-foreground">
|
|
Faça login para ver suas intenções de compra
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h2 className="text-2xl font-bold mb-2">Minhas Intenções de Compra</h2>
|
|
<p className="text-muted-foreground">
|
|
Acompanhe suas intenções de compra e respostas dos vendedores
|
|
</p>
|
|
</div>
|
|
|
|
{/* Filtros */}
|
|
<div className="flex items-center gap-2 flex-wrap">
|
|
<Button
|
|
variant={filter === "all" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("all")}
|
|
>
|
|
Todas ({intentions.length})
|
|
</Button>
|
|
<Button
|
|
variant={filter === "pending" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("pending")}
|
|
>
|
|
Pendentes ({pendingCount})
|
|
</Button>
|
|
<Button
|
|
variant={filter === "accepted" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("accepted")}
|
|
>
|
|
Aceitas ({acceptedCount})
|
|
</Button>
|
|
<Button
|
|
variant={filter === "rejected" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("rejected")}
|
|
>
|
|
Rejeitadas ({rejectedCount})
|
|
</Button>
|
|
{expiredCount > 0 && (
|
|
<Button
|
|
variant={filter === "expired" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("expired")}
|
|
>
|
|
Expiradas ({expiredCount})
|
|
</Button>
|
|
)}
|
|
{completedCount > 0 && (
|
|
<Button
|
|
variant={filter === "completed" ? "default" : "outline"}
|
|
size="sm"
|
|
onClick={() => setFilter("completed")}
|
|
>
|
|
Concluídas ({completedCount})
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
{/* Lista de intenções */}
|
|
{isLoading ? (
|
|
<div className="space-y-4">
|
|
{Array.from({ length: 3 }).map((_, i) => (
|
|
<Skeleton key={i} className="h-48 w-full" />
|
|
))}
|
|
</div>
|
|
) : filteredIntentions.length === 0 ? (
|
|
<div className="text-center py-12 border rounded-lg">
|
|
<ShoppingCart className="h-12 w-12 mx-auto mb-4 text-muted-foreground opacity-50" />
|
|
<p className="text-lg font-medium mb-2">
|
|
Nenhuma intenção de compra encontrada
|
|
</p>
|
|
<p className="text-sm text-muted-foreground mb-4">
|
|
{filter === "all"
|
|
? "Quando você manifestar interesse em comprar um item, ele aparecerá aqui."
|
|
: `Não há intenções com status "${filter}" no momento.`}
|
|
</p>
|
|
<Button asChild variant="outline">
|
|
<Link href={`/${locale}/market`}>Explorar Marketplace</Link>
|
|
</Button>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{filteredIntentions.map((intention) => (
|
|
<IntentionCard
|
|
key={intention.intention_id}
|
|
intention={intention}
|
|
locale={locale}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|