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:
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>
|
||||
|
||||
Reference in new issue
Block a user