import { useQuery } from '@tanstack/react-query'; export interface BTCMapMerchant { id: string; name: string; lat: number; lon: number; tags: { name?: string; 'payment:lightning'?: string; 'payment:onchain'?: string; 'payment:lightning_contactless'?: string; amenity?: string; shop?: string; cuisine?: string; opening_hours?: string; website?: string; phone?: string; }; osm_json?: { type: string; id: number; }; } /** * Fetch Bitcoin-accepting merchants from BTCMap API * Uses bounding box to get merchants in the visible map area */ export function useBTCMap(bounds?: { north: number; south: number; east: number; west: number; }, enabled: boolean = false) { return useQuery({ queryKey: ['btcmap', bounds?.north, bounds?.south, bounds?.east, bounds?.west], queryFn: async ({ signal }): Promise => { if (!bounds) return []; // BTCMap API endpoint - get elements in bounding box // Using their public API const url = `https://api.btcmap.org/v2/elements?updated_since=2020-01-01&bounds=${bounds.south},${bounds.west},${bounds.north},${bounds.east}`; const response = await fetch(url, { signal, headers: { 'Accept': 'application/json', } }); if (!response.ok) { throw new Error(`BTCMap API error: ${response.status}`); } const data = await response.json(); // Transform the response to our format const merchants: BTCMapMerchant[] = data .filter((item: { 'osm_json': { lat?: number; lon?: number }; deleted_at?: string }) => item.osm_json?.lat && item.osm_json?.lon && !item.deleted_at ) .map((item: { id: string; 'osm_json': { lat: number; lon: number; tags?: Record; type?: string; id?: number; } }) => ({ id: item.id, name: item.osm_json.tags?.name || 'Bitcoin Merchant', lat: item.osm_json.lat, lon: item.osm_json.lon, tags: item.osm_json.tags || {}, osm_json: { type: item.osm_json.type || 'node', id: item.osm_json.id || 0, } })); return merchants; }, enabled: enabled && !!bounds, staleTime: 5 * 60 * 1000, // 5 minutes gcTime: 30 * 60 * 1000, // 30 minutes }); } /** * Get a human-readable category for the merchant */ export function getMerchantCategory(merchant: BTCMapMerchant): string { const { tags } = merchant; if (tags.amenity === 'cafe' || tags.amenity === 'coffee') return '☕ Café'; if (tags.amenity === 'restaurant') return '🍽️ Restaurant'; if (tags.amenity === 'bar' || tags.amenity === 'pub') return '🍺 Bar'; if (tags.amenity === 'fast_food') return '🍔 Fast Food'; if (tags.shop === 'convenience') return '🏪 Convenience'; if (tags.shop === 'supermarket') return '🛒 Supermarket'; if (tags.shop === 'clothes') return '👕 Clothing'; if (tags.shop === 'sports') return '⚽ Sports'; if (tags.shop === 'electronics') return '📱 Electronics'; if (tags.shop) return '🏬 Shop'; if (tags.amenity === 'atm') return '🏧 ATM'; if (tags.amenity === 'bank') return '🏦 Bank'; return '₿ Bitcoin Accepted'; } /** * Check if merchant accepts Lightning */ export function acceptsLightning(merchant: BTCMapMerchant): boolean { const { tags } = merchant; return tags['payment:lightning'] === 'yes' || tags['payment:lightning_contactless'] === 'yes'; }