style: clean up code formatting and remove trailing whitespace
refactor: reorganize imports and fix type imports
This commit is contained in:
1 parent
d3704602fd
commit
47c04de6fe
232 files changed
+7140
-4798
No files matched your search
@@ -1,34 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
AlertCircle,
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
Eye,
|
||||
Heart,
|
||||
MapPin,
|
||||
Pause,
|
||||
ShoppingBag,
|
||||
Star,
|
||||
Trash2,
|
||||
TrendingUp,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Eye,
|
||||
Heart,
|
||||
Clock,
|
||||
MapPin,
|
||||
DollarSign,
|
||||
Coins,
|
||||
TrendingUp,
|
||||
Star,
|
||||
Pause,
|
||||
Trash2,
|
||||
X,
|
||||
CheckCircle2,
|
||||
AlertCircle,
|
||||
ShoppingBag,
|
||||
} from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useSession } from "@/lib/hooks/use-session";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
interface Listing {
|
||||
listing_id: number;
|
||||
@@ -76,10 +74,11 @@ interface ListingDetailsModalProps {
|
||||
|
||||
function formatTimeAgo(date: Date | string): string {
|
||||
const dateObj = typeof date === "string" ? new Date(date) : date;
|
||||
const seconds = Math.floor((new Date().getTime() - dateObj.getTime()) / 1000);
|
||||
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"}`;
|
||||
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);
|
||||
@@ -92,14 +91,40 @@ function formatTimeAgo(date: Date | string): string {
|
||||
|
||||
function getStatusBadge(status: string) {
|
||||
const statusConfig = {
|
||||
active: { label: "Ativo", variant: "default" as const, icon: CheckCircle2, className: "bg-green-500 hover:bg-green-600" },
|
||||
sold: { label: "Vendido", variant: "secondary" as const, icon: CheckCircle2, className: "bg-blue-500 hover:bg-blue-600 text-white" },
|
||||
cancelled: { label: "Cancelado", variant: "destructive" as const, icon: X, className: "bg-red-500 hover:bg-red-600 text-white" },
|
||||
in_escrow: { label: "Em Escrow", variant: "default" as const, icon: AlertCircle, className: "bg-yellow-500 hover:bg-yellow-600 text-white" },
|
||||
expired: { label: "Expirado", variant: "secondary" as const, icon: Clock, className: "bg-gray-500 hover:bg-gray-600 text-white" },
|
||||
active: {
|
||||
label: "Ativo",
|
||||
variant: "default" as const,
|
||||
icon: CheckCircle2,
|
||||
className: "bg-green-500 hover:bg-green-600",
|
||||
},
|
||||
sold: {
|
||||
label: "Vendido",
|
||||
variant: "secondary" as const,
|
||||
icon: CheckCircle2,
|
||||
className: "bg-blue-500 hover:bg-blue-600 text-white",
|
||||
},
|
||||
cancelled: {
|
||||
label: "Cancelado",
|
||||
variant: "destructive" as const,
|
||||
icon: X,
|
||||
className: "bg-red-500 hover:bg-red-600 text-white",
|
||||
},
|
||||
in_escrow: {
|
||||
label: "Em Escrow",
|
||||
variant: "default" as const,
|
||||
icon: AlertCircle,
|
||||
className: "bg-yellow-500 hover:bg-yellow-600 text-white",
|
||||
},
|
||||
expired: {
|
||||
label: "Expirado",
|
||||
variant: "secondary" as const,
|
||||
icon: Clock,
|
||||
className: "bg-gray-500 hover:bg-gray-600 text-white",
|
||||
},
|
||||
};
|
||||
|
||||
const config = statusConfig[status as keyof typeof statusConfig] || statusConfig.active;
|
||||
const config =
|
||||
statusConfig[status as keyof typeof statusConfig] || statusConfig.active;
|
||||
const Icon = config.icon;
|
||||
|
||||
return (
|
||||
@@ -123,7 +148,7 @@ export function ListingDetailsModal({
|
||||
const [itemImageUrl, setItemImageUrl] = useState<string>("");
|
||||
const [showMarkSoldDialog, setShowMarkSoldDialog] = useState(false);
|
||||
const [markingSold, setMarkingSold] = useState(false);
|
||||
|
||||
|
||||
// Verificar se o usuário é o dono do anúncio
|
||||
const isOwner = user && user.userId === listing.seller_id;
|
||||
|
||||
@@ -134,13 +159,19 @@ export function ListingDetailsModal({
|
||||
} else if (listing.image_local_path) {
|
||||
const normalizedPath = listing.image_local_path.replace(/\\/g, "/");
|
||||
if (normalizedPath.startsWith("data/")) {
|
||||
setItemImageUrl(`/api/images?path=${encodeURIComponent(normalizedPath)}`);
|
||||
setItemImageUrl(
|
||||
`/api/images?path=${encodeURIComponent(normalizedPath)}`,
|
||||
);
|
||||
} else {
|
||||
const category = listing.item_category || "other";
|
||||
setItemImageUrl(`/api/images?path=${encodeURIComponent(`data/images/${category}/${normalizedPath}`)}`);
|
||||
setItemImageUrl(
|
||||
`/api/images?path=${encodeURIComponent(`data/images/${category}/${normalizedPath}`)}`,
|
||||
);
|
||||
}
|
||||
} else if (listing.item_id_unified) {
|
||||
const params = new URLSearchParams({ item: listing.item_id_unified.toString() });
|
||||
const params = new URLSearchParams({
|
||||
item: listing.item_id_unified.toString(),
|
||||
});
|
||||
if (listing.item_name) {
|
||||
params.set("name", listing.item_name);
|
||||
}
|
||||
@@ -158,27 +189,52 @@ export function ListingDetailsModal({
|
||||
const prices: Array<{ type: string; label: string; value: string }> = [];
|
||||
|
||||
if (listing.price_pix) {
|
||||
const price = typeof listing.price_pix === "string" ? parseFloat(listing.price_pix) : listing.price_pix;
|
||||
if (!isNaN(price)) {
|
||||
prices.push({ type: "pix", label: "PIX", value: `R$ ${price.toFixed(2)}` });
|
||||
const price =
|
||||
typeof listing.price_pix === "string"
|
||||
? parseFloat(listing.price_pix)
|
||||
: listing.price_pix;
|
||||
if (!Number.isNaN(price)) {
|
||||
prices.push({
|
||||
type: "pix",
|
||||
label: "PIX",
|
||||
value: `R$ ${price.toFixed(2)}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (listing.price_tibia_coins) {
|
||||
const price = typeof listing.price_tibia_coins === "string" ? parseInt(listing.price_tibia_coins, 10) : listing.price_tibia_coins;
|
||||
if (!isNaN(price)) {
|
||||
prices.push({ type: "tibia_coins", label: "Tibia Coins", value: `${price.toLocaleString()} TC` });
|
||||
const price =
|
||||
typeof listing.price_tibia_coins === "string"
|
||||
? parseInt(listing.price_tibia_coins, 10)
|
||||
: listing.price_tibia_coins;
|
||||
if (!Number.isNaN(price)) {
|
||||
prices.push({
|
||||
type: "tibia_coins",
|
||||
label: "Tibia Coins",
|
||||
value: `${price.toLocaleString()} TC`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (listing.price_gold_coins) {
|
||||
const price = typeof listing.price_gold_coins === "string" ? parseInt(listing.price_gold_coins, 10) : listing.price_gold_coins;
|
||||
if (!isNaN(price)) {
|
||||
prices.push({ type: "gold_coins", label: "Gold Coins", value: `${price.toLocaleString()} GP` });
|
||||
const price =
|
||||
typeof listing.price_gold_coins === "string"
|
||||
? parseInt(listing.price_gold_coins, 10)
|
||||
: listing.price_gold_coins;
|
||||
if (!Number.isNaN(price)) {
|
||||
prices.push({
|
||||
type: "gold_coins",
|
||||
label: "Gold Coins",
|
||||
value: `${price.toLocaleString()} GP`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (listing.trade_item_id && listing.trade_item_name && listing.trade_item_quantity) {
|
||||
if (
|
||||
listing.trade_item_id &&
|
||||
listing.trade_item_name &&
|
||||
listing.trade_item_quantity
|
||||
) {
|
||||
prices.push({
|
||||
type: "trade",
|
||||
label: "Troca",
|
||||
@@ -220,7 +276,10 @@ export function ListingDetailsModal({
|
||||
const canPause = isOwner && listing.listing_status === "active";
|
||||
const canActivate = isOwner && listing.listing_status === "cancelled";
|
||||
const canCancel = isOwner && listing.listing_status === "active";
|
||||
const canMarkAsSold = isOwner && (listing.listing_status === "active" || listing.listing_status === "in_escrow");
|
||||
const canMarkAsSold =
|
||||
isOwner &&
|
||||
(listing.listing_status === "active" ||
|
||||
listing.listing_status === "in_escrow");
|
||||
|
||||
const handleMarkAsSold = async () => {
|
||||
setMarkingSold(true);
|
||||
@@ -228,7 +287,7 @@ export function ListingDetailsModal({
|
||||
const res = await fetch(`/api/listings/${listing.listing_id}/mark-sold`, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
|
||||
if (!res.ok) {
|
||||
const data = await res.json();
|
||||
throw new Error(data.error || "Erro ao marcar como vendido");
|
||||
@@ -237,12 +296,14 @@ export function ListingDetailsModal({
|
||||
// Invalidar cache para atualizar a lista
|
||||
queryClient.invalidateQueries({ queryKey: ["listings"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["my-listings"] });
|
||||
|
||||
|
||||
setShowMarkSoldDialog(false);
|
||||
onOpenChange(false);
|
||||
} catch (error) {
|
||||
console.error("Erro ao marcar como vendido:", error);
|
||||
alert(error instanceof Error ? error.message : "Erro ao marcar como vendido");
|
||||
alert(
|
||||
error instanceof Error ? error.message : "Erro ao marcar como vendido",
|
||||
);
|
||||
} finally {
|
||||
setMarkingSold(false);
|
||||
}
|
||||
@@ -256,7 +317,9 @@ export function ListingDetailsModal({
|
||||
Detalhes do Anúncio
|
||||
{getStatusBadge(listing.listing_status)}
|
||||
</DialogTitle>
|
||||
<DialogDescription>Informações completas do seu anúncio</DialogDescription>
|
||||
<DialogDescription>
|
||||
Informações completas do seu anúncio
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-6">
|
||||
@@ -294,22 +357,30 @@ export function ListingDetailsModal({
|
||||
<div className="flex items-center gap-2">
|
||||
<Eye className="h-4 w-4 text-muted-foreground" />
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Visualizações</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Visualizações
|
||||
</div>
|
||||
<div className="font-semibold">{listing.views_count}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Heart className="h-4 w-4 text-muted-foreground" />
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Favoritos</div>
|
||||
<div className="font-semibold">{listing.favorites_count || 0}</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Favoritos
|
||||
</div>
|
||||
<div className="font-semibold">
|
||||
{listing.favorites_count || 0}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Clock className="h-4 w-4 text-muted-foreground" />
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground">Criado</div>
|
||||
<div className="font-semibold text-xs">{formatTimeAgo(listing.created_at)}</div>
|
||||
<div className="font-semibold text-xs">
|
||||
{formatTimeAgo(listing.created_at)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -349,7 +420,9 @@ export function ListingDetailsModal({
|
||||
: "bg-purple-500/10 border-purple-500/20"
|
||||
}`}
|
||||
>
|
||||
<div className="text-xs text-muted-foreground mb-1">{price.label}</div>
|
||||
<div className="text-xs text-muted-foreground mb-1">
|
||||
{price.label}
|
||||
</div>
|
||||
<div className="font-semibold">{price.value}</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -370,26 +443,44 @@ export function ListingDetailsModal({
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Lance Atual:</span>
|
||||
<span className="font-semibold text-lg text-primary">
|
||||
R$ {typeof listing.current_bid_amount === "number" ? listing.current_bid_amount.toFixed(2) : parseFloat(String(listing.current_bid_amount)).toFixed(2)}
|
||||
R${" "}
|
||||
{typeof listing.current_bid_amount === "number"
|
||||
? listing.current_bid_amount.toFixed(2)
|
||||
: parseFloat(
|
||||
String(listing.current_bid_amount),
|
||||
).toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
{listing.min_bid_increment && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Incremento Mínimo:</span>
|
||||
<span className="text-muted-foreground">
|
||||
Incremento Mínimo:
|
||||
</span>
|
||||
<span className="font-medium">
|
||||
R$ {typeof listing.min_bid_increment === "number" ? listing.min_bid_increment.toFixed(2) : parseFloat(String(listing.min_bid_increment)).toFixed(2)}
|
||||
R${" "}
|
||||
{typeof listing.min_bid_increment === "number"
|
||||
? listing.min_bid_increment.toFixed(2)
|
||||
: parseFloat(
|
||||
String(listing.min_bid_increment),
|
||||
).toFixed(2)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{listing.auction_ends_at && (
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Termina em:</span>
|
||||
<span className="font-medium">{new Date(listing.auction_ends_at).toLocaleString("pt-BR")}</span>
|
||||
<span className="font-medium">
|
||||
{new Date(listing.auction_ends_at).toLocaleString(
|
||||
"pt-BR",
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center text-muted-foreground py-2">Sem lances ainda</div>
|
||||
<div className="text-center text-muted-foreground py-2">
|
||||
Sem lances ainda
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -398,7 +489,9 @@ export function ListingDetailsModal({
|
||||
{listing.description && (
|
||||
<div className="space-y-2">
|
||||
<h4 className="font-semibold">Descrição</h4>
|
||||
<p className="text-sm text-muted-foreground p-3 bg-muted rounded-lg">{listing.description}</p>
|
||||
<p className="text-sm text-muted-foreground p-3 bg-muted rounded-lg">
|
||||
{listing.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -410,13 +503,19 @@ export function ListingDetailsModal({
|
||||
</div>
|
||||
{listing.item_id_unified && (
|
||||
<div>
|
||||
<span className="text-muted-foreground">ID do Item (Unificado):</span>
|
||||
<span className="ml-2 font-mono">{listing.item_id_unified}</span>
|
||||
<span className="text-muted-foreground">
|
||||
ID do Item (Unificado):
|
||||
</span>
|
||||
<span className="ml-2 font-mono">
|
||||
{listing.item_id_unified}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<span className="text-muted-foreground">Criado em:</span>
|
||||
<span className="ml-2">{new Date(listing.created_at).toLocaleString("pt-BR")}</span>
|
||||
<span className="ml-2">
|
||||
{new Date(listing.created_at).toLocaleString("pt-BR")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -424,9 +523,9 @@ export function ListingDetailsModal({
|
||||
{(canPause || canActivate || canCancel || canMarkAsSold) && (
|
||||
<div className="flex gap-2 pt-4 border-t">
|
||||
{canMarkAsSold && (
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => setShowMarkSoldDialog(true)}
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={() => setShowMarkSoldDialog(true)}
|
||||
className="flex-1 bg-green-600 hover:bg-green-700"
|
||||
>
|
||||
<ShoppingBag className="h-4 w-4 mr-2" />
|
||||
@@ -440,13 +539,21 @@ export function ListingDetailsModal({
|
||||
</Button>
|
||||
)}
|
||||
{canActivate && onActivate && (
|
||||
<Button variant="default" onClick={onActivate} className="flex-1">
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={onActivate}
|
||||
className="flex-1"
|
||||
>
|
||||
<CheckCircle2 className="h-4 w-4 mr-2" />
|
||||
Reativar Anúncio
|
||||
</Button>
|
||||
)}
|
||||
{canCancel && (
|
||||
<Button variant="destructive" onClick={onCancel} className="flex-1">
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={onCancel}
|
||||
className="flex-1"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
Cancelar Anúncio
|
||||
</Button>
|
||||
@@ -462,14 +569,18 @@ export function ListingDetailsModal({
|
||||
<DialogHeader>
|
||||
<DialogTitle>Marcar anúncio como vendido?</DialogTitle>
|
||||
<DialogDescription>
|
||||
Ao marcar este anúncio como vendido, as seguintes ações serão executadas:
|
||||
Ao marcar este anúncio como vendido, as seguintes ações serão
|
||||
executadas:
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-2 pt-2">
|
||||
<ul className="list-disc list-inside space-y-1 text-sm text-muted-foreground">
|
||||
<li>O anúncio será marcado como "Vendido"</li>
|
||||
<li>O anúncio continuará visível na lista por mais 1 hora</li>
|
||||
<li>Após 1 hora, o anúncio sairá automaticamente da lista de anúncios ativos</li>
|
||||
<li>
|
||||
Após 1 hora, o anúncio sairá automaticamente da lista de
|
||||
anúncios ativos
|
||||
</li>
|
||||
<li>Nenhuma interação (comprar, dar lance) será permitida</li>
|
||||
</ul>
|
||||
<p className="pt-2 font-medium text-foreground">
|
||||
@@ -497,4 +608,3 @@ export function ListingDetailsModal({
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user