feat: enhance purchase intentions with chat integration and offer tracking

- Added MongoDB chat/message integration for seller responses
- Improved seller response validation and default messaging
- Integrated automatic chat creation/update when responding to intentions
- Added highest custom offer fields to listing queries and models
- Enhanced listing data with top offer information for buyers
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-08 11:51:21 -03:00
1 parent d27526e026
commit d8e7d5d7e6
19 files changed
+806 -58

No files matched your search

+54 -9
View File
@@ -68,10 +68,12 @@ interface Listing {
// Campo do vendedor
seller_character_name?: string | null;
has_pending_intention_for_current_user?: boolean;
highest_custom_offer_amount?: number | string | null;
highest_custom_offer_currency?: string | null;
}
interface PriceInfo {
type: "pix" | "tc" | "gp" | "trade";
type: "pix" | "tibia_coins" | "gold_coins" | "trade";
label: string;
value: string;
}
@@ -227,7 +229,7 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
: listing.price_tibia_coins;
if (!isNaN(price)) {
prices.push({
type: "tc",
type: "tibia_coins",
label: "TC",
value: `${price.toLocaleString()} TC`,
});
@@ -241,7 +243,7 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
: listing.price_gold_coins;
if (!isNaN(price)) {
prices.push({
type: "gp",
type: "gold_coins",
label: "GP",
value: `${price.toLocaleString()} GP`,
});
@@ -266,6 +268,35 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
const isSold = listing.listing_status === "sold";
const hasPendingIntention = Boolean(listing.has_pending_intention_for_current_user);
const getHighestOfferLabel = () => {
if (
listing.highest_custom_offer_amount === null ||
listing.highest_custom_offer_amount === undefined ||
!listing.highest_custom_offer_currency
) {
return null;
}
const amount =
typeof listing.highest_custom_offer_amount === "string"
? Number(listing.highest_custom_offer_amount)
: listing.highest_custom_offer_amount;
if (Number.isNaN(amount)) {
return null;
}
switch (listing.highest_custom_offer_currency) {
case "pix":
return `Maior oferta: R$ ${amount.toFixed(2)}`;
case "tibia_coins":
return `Maior oferta: ${Math.round(amount).toLocaleString()} TC`;
case "gold_coins":
return `Maior oferta: ${Math.round(amount).toLocaleString()} GP`;
default:
return `Maior oferta: ${amount}`;
}
};
const highestOfferLabel = getHighestOfferLabel();
// Função para obter URL da imagem do item
const getItemImageUrl = (): string => {
// Prioridade 1: image_url (URL externa) se disponível
@@ -327,9 +358,9 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
switch (type) {
case "pix":
return "bg-green-100 hover:bg-green-200 dark:bg-green-900/30 dark:hover:bg-green-900/50 text-green-700 dark:text-green-300 border-green-300 dark:border-green-700";
case "tc":
case "tibia_coins":
return "bg-blue-100 hover:bg-blue-200 dark:bg-blue-900/30 dark:hover:bg-blue-900/50 text-blue-700 dark:text-blue-300 border-blue-300 dark:border-blue-700";
case "gp":
case "gold_coins":
return "bg-amber-100 hover:bg-amber-200 dark:bg-amber-900/30 dark:hover:bg-amber-900/50 text-amber-700 dark:text-amber-300 border-amber-300 dark:border-amber-700";
case "trade":
return "bg-purple-100 hover:bg-purple-200 dark:bg-purple-900/30 dark:hover:bg-purple-900/50 text-purple-700 dark:text-purple-300 border-purple-300 dark:border-purple-700";
@@ -342,8 +373,8 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
switch (type) {
case "pix":
return <DollarSign className="h-3 w-3" />;
case "tc":
case "gp":
case "tibia_coins":
case "gold_coins":
return <Coins className="h-3 w-3" />;
case "trade":
return <RefreshCw className="h-3 w-3" />;
@@ -554,7 +585,14 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
listing.is_featured && "p-2 rounded-lg border-l-4 bg-yellow-500/5 border-yellow-500",
"overflow-hidden"
)}>
<PriceBadges prices={availablePrices} compact tradeItemImageUrl={tradeItemImageUrl} listing={listing} />
<div className="space-y-1">
<PriceBadges prices={availablePrices} compact tradeItemImageUrl={tradeItemImageUrl} listing={listing} />
{highestOfferLabel && (
<div className="text-xs font-medium text-primary/80">
{highestOfferLabel}
</div>
)}
</div>
</div>
)}
@@ -846,7 +884,14 @@ export function AdCard({ listing, viewMode = "grid" }: AdCardProps) {
listing.is_featured && "p-2 rounded-lg border-l-4 bg-yellow-500/5 border-yellow-500",
"overflow-hidden"
)}>
<PriceBadges prices={availablePrices} tradeItemImageUrl={tradeItemImageUrl} listing={listing} />
<div className="space-y-1">
<PriceBadges prices={availablePrices} tradeItemImageUrl={tradeItemImageUrl} listing={listing} />
{highestOfferLabel && (
<div className="text-xs font-medium text-primary/80">
{highestOfferLabel}
</div>
)}
</div>
</div>
)}