import { useState } from 'react'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { useOfferActions } from '@/hooks/useMarketplaceOffers'; import { useSendDirectMessage } from '@/hooks/useDirectMessages'; import { useToast } from '@/hooks/useToast'; import { Handshake, Loader2 } from 'lucide-react'; import { useTranslation } from '@/contexts/language'; /** Buyer: make a structured offer (amount + note) on a listing. */ export function OfferDialog({ open, onOpenChange, listing, title, sellerName, }: { open: boolean; onOpenChange: (open: boolean) => void; listing: { pubkey: string; identifier: string }; title: string; sellerName: string; }) { const { t } = useTranslation(); const { createOffer } = useOfferActions(); const { mutateAsync: sendDM } = useSendDirectMessage(); const { toast } = useToast(); const [amount, setAmount] = useState(''); const [offerItem, setOfferItem] = useState(''); const [note, setNote] = useState(''); const [busy, setBusy] = useState(false); const submit = async () => { const parsed = amount.trim() ? Number(amount) : undefined; if (parsed !== undefined && (!Number.isFinite(parsed) || parsed <= 0)) { toast({ title: t('marketUi.offer.validAmount'), variant: 'destructive' }); return; } if (!parsed && !offerItem.trim() && !note.trim()) { toast({ title: t('marketUi.offer.describeOffer'), description: t('marketUi.offer.describeOfferBody'), variant: 'destructive' }); return; } setBusy(true); try { await createOffer({ listing, amount: parsed, currency: 'SATS', offerItem, note }); // Best-effort nudge to the seller via NIP-17 DM — never fail the offer. try { const amountLine = parsed ? t('marketUi.offer.dmAmount', { amount: parsed.toLocaleString() }) : ''; const itemLine = offerItem.trim() ? t('marketUi.offer.dmItem', { item: offerItem.trim() }) : ''; const noteLine = note.trim() ? `\n\nā€œ${note.trim()}ā€` : ''; await sendDM({ recipients: listing.pubkey, content: t('marketUi.offer.dmBody', { title, amount: amountLine, item: itemLine, note: noteLine }), }); } catch { /* DM optional (no NIP-44 signer, etc.) */ } toast({ title: t('marketUi.offer.sent'), description: t('marketUi.offer.sentBody', { sellerName }), }); onOpenChange(false); setAmount(''); setOfferItem(''); setNote(''); } catch (e) { toast({ title: t('marketUi.offer.sendFailed'), description: e instanceof Error ? e.message : t('marketUi.offer.somethingWrong'), variant: 'destructive', }); } finally { setBusy(false); } }; return ( {t('marketUi.offer.title')} {t('marketUi.offer.description', { sellerName })}
setAmount(e.target.value)} inputMode="numeric" placeholder={t('marketUi.offer.amountPlaceholder')} className="h-11 border-gray-700 bg-gray-900 text-white" />
setOfferItem(e.target.value)} placeholder={t('marketUi.offer.itemPlaceholder')} className="h-11 border-gray-700 bg-gray-900 text-white" />

{t('marketUi.offer.itemHint')}

{t('marketplaceExtrasUi.offerTemplates')}

{[ t('marketplaceExtrasUi.offerDiscount'), t('marketplaceExtrasUi.offerSwap'), t('marketplaceExtrasUi.offerPickup'), t('marketplaceExtrasUi.offerShipping'), ].map((template) => ( ))}