/** * Guided handoff — turns the blank "message the seller" DM into a real * arrangement, WITHOUT the app ever touching an address. Each button opens the * trade chat with a pre-filled template; the actual details stay in the NIP-17 * DM (push already covers it). Also carries the anti-scam guidance. */ import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import ngeohash from 'ngeohash'; import { Package, MapPin, Lock, ShieldCheck } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useSkateSpots } from '@/hooks/useSkateSpots'; import { itemDistanceKm } from '@/lib/sortOptions'; import type { MarketplaceItem } from '@/lib/types'; import { useTranslation } from '@/contexts/language'; export function HandoffHelper({ item }: { item: MarketplaceItem }) { const { t } = useTranslation(); const navigate = useNavigate(); const npub = nip19.npubEncode(item.pubkey); const dm = (message: string) => `/messages/${npub}?message=${encodeURIComponent(message)}`; const ships = item.fulfilment === 'ships' || item.fulfilment === 'both'; const pickup = item.fulfilment === 'pickup' || item.fulfilment === 'both'; // Suggest nearby PUBLIC skate spots as a meetup place. Uses only the listing's // own public geohash + public spot data — never the viewer's live location. const { data: spots = [] } = useSkateSpots(200); const meetSpots = useMemo(() => { if (!pickup || !item.geohash) return []; try { const { latitude, longitude } = ngeohash.decode(item.geohash); if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return []; const origin = { lat: latitude, lng: longitude }; return spots .filter((s) => s.geohash && s.identifier !== item.identifier) .map((s) => ({ spot: s, km: itemDistanceKm(s, origin) ?? Infinity })) .sort((a, b) => a.km - b.km) .slice(0, 3); } catch { return []; } }, [spots, item.geohash, item.identifier, pickup]); if (!ships && !pickup) return null; return (

{t('marketUi.handoff.title')}

{pickup && ( )} {meetSpots.length > 0 && (

{t('marketUi.handoff.orMeetAt')}

{meetSpots.map(({ spot, km }) => ( ))}
)} {ships && ( <> )}

{t('marketUi.handoff.noteBefore')} {t('marketUi.handoff.escrow')}{t('marketUi.handoff.noteMiddle')} {t('marketUi.handoff.neverPay')}{t('marketUi.handoff.noteAfter')}

); }