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

@@ -35,6 +35,9 @@ interface PurchaseIntention {
buyer_message: string | null;
seller_response: string | null;
created_at: string;
custom_offer_amount: number | null;
custom_offer_currency: string | null;
custom_offer_created_at: string | null;
buyer?: {
user_id: number;
username: string;
@@ -93,6 +96,40 @@ function getStatusBadge(status: string) {
}
}
function formatCustomOffer(intention: PurchaseIntention): { value: string; date: string | null } | null {
if (
intention.custom_offer_amount === null ||
intention.custom_offer_amount === undefined ||
!intention.custom_offer_currency
) {
return null;
}
const amount = intention.custom_offer_amount;
let value: string;
switch (intention.custom_offer_currency) {
case "pix":
value = `R$ ${amount.toFixed(2)}`;
break;
case "tibia_coins":
value = `${Math.round(amount).toLocaleString("pt-BR")} TC`;
break;
case "gold_coins":
value = `${Math.round(amount).toLocaleString("pt-BR")} GP`;
break;
default:
value = amount.toLocaleString("pt-BR");
}
return {
value,
date: intention.custom_offer_created_at
? new Date(intention.custom_offer_created_at).toLocaleString("pt-BR")
: null,
};
}
export function IntentionDetailModal({
open,
onOpenChange,
@@ -126,6 +163,13 @@ export function IntentionDetailModal({
const isOwner = user && listing && user.userId === listing.seller_id;
const canMarkAsSold = isOwner && listing && (listing.listing_status === "active" || listing.listing_status === "in_escrow");
const canAcceptOrReject = intention.status === "pending";
const customOffer = formatCustomOffer(intention);
useEffect(() => {
if (open) {
setSellerResponse(intention.seller_response ?? "");
}
}, [open, intention.intention_id, intention.seller_response]);
const handleAccept = async () => {
setLoading(true);
@@ -279,6 +323,18 @@ export function IntentionDetailModal({
</div>
</div>
{customOffer && (
<div className="bg-primary/5 border border-primary/20 rounded-lg p-3 space-y-1">
<Label className="text-xs text-primary uppercase tracking-wide">
Oferta do Comprador
</Label>
<div className="text-base font-semibold text-primary">{customOffer.value}</div>
{customOffer.date && (
<p className="text-[11px] text-primary/70">Enviada em {customOffer.date}</p>
)}
</div>
)}
{/* Mensagem do comprador */}
{intention.buyer_message && (
<div>