1
0
Fork 0
polaris-task-force/src/components/frontend/market/NpcChat.tsx
Z8MB1E 89b8474e23 feat(market): add trading marketplace with listings, haggling, and NPC vendors
Tarkov-style flea market where users list locker items at a fixed price
and buyers pay through the banking system; items transfer directly
into the buyer's locker.

- market-listings + market-negotiations collections and the market page
  with search/rarity filters and a Countdown timer on each card
- service lib (buyListing with partial-quantity + negotiated-price
  support, clean-stock rule, creditLockerQuantity, auto pricing)
- negotiation flow: make/accept/reject/counter/withdraw, strictly-
  increasing buyer offers, NPC vendor auto-resolution
- NPC vendors: game-npcs attribution, patience meter, dialogue, chat
  bubbles, historical threads dialog
- 30d user / 7d auto listing durations, market-tick bin for expiry +
  vendor restock, SSE notify on tick
- market event types + game-npcs/market target collections in the
  event log; sidebar Market entry under Logistics
- partial-quantity purchases (buyListing/buyMarketListing/makeMarketOffer)
  with full int test coverage (25 tests)
2026-08-10 16:05:57 -04:00

29 lines
1.2 KiB
TypeScript

"use client";
import type { Asset, MarketListing, MarketNegotiation } from "@/payload-types";
import { StoreIcon } from "lucide-react";
import { buildChatBubbles } from "@/lib/market/chatBubbles";
import { ChatBubbleList } from "@/components/frontend/market/ChatBubbleList";
interface NpcChatProps {
listing: MarketListing;
negotiation: MarketNegotiation | null;
currencyLabel: string | null;
}
export function NpcChat({ listing, negotiation, currencyLabel }: NpcChatProps) {
const asset = listing.asset as Asset;
const assetName = typeof asset === "object" && asset ? asset.name : `Asset #${listing.asset}`;
const bubbles = buildChatBubbles(negotiation, listing, currencyLabel);
return (
<div className="flex flex-col gap-2 rounded-md border bg-card">
<div className="flex items-center gap-2 border-b px-3 py-2">
<StoreIcon className="size-4 text-muted-foreground" />
<span className="text-xs font-medium text-muted-foreground">Vendor</span>
<span className="text-xs text-muted-foreground">— {assetName}</span>
</div>
<ChatBubbleList bubbles={bubbles} buyerLabel="You" sellerLabel="Vendor" />
</div>
);
}