SkateSpots/src/hooks/useBtcMapPlaces.ts
shakespeare.diy e29d35f1e4 fix: restore full skate-spots source tree from misplaced src/src/ copy
The entire skate-spots codebase was accidentally copied into src/src/ and
public/public/ instead of src/ and public/ directly. This left the real
src/ directory as blank MKStack template stubs, explaining why the landing
page showed the default template instead of SkateSpots.

Changes made:
- Copied all files from src/src/ up to src/ (App.tsx, AppRouter.tsx, main.tsx,
  all pages, components, hooks, contexts, lib, i18n, test)
- Copied all files from public/public/ up to public/ (images, manifest, etc.)
- Deleted src/src/ and public/public/ nested directories
- Removed HelloWorld.tsx template stub from pages/
- Retained the previously fixed index.css (Tailwind v3 directives)

Full skate-spots feature set is now active:
- All 30+ routes (map, events, spots, coaches, marketplace, wallet, etc.)
- NWCProvider, LanguageProvider, PWAInstallPrompt, AmberCallbackHandler
- Skate community relays (goskatespots.nostr1.com, wotr.relatr.xyz, etc.)
- Outfit Variable font, Amber pre-check in main.tsx
- All hooks (useSkateSpots, useCoaches, useZaps, etc.)
- i18n support (en/es)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-15 22:18:28 +07:00

78 lines
2.2 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
export interface BtcMapPlace {
id: number;
lat: number;
lon: number;
icon: string;
name: string;
address?: string;
opening_hours?: string;
verified_at?: string;
boosted_until?: string;
website?: string;
phone?: string;
description?: string;
}
interface UseBtcMapPlacesOptions {
lat: number;
lon: number;
radiusKm?: number;
enabled?: boolean;
}
/**
* Fetches Bitcoin-accepting places from BTC Map API within a radius
*/
export function useBtcMapPlaces({ lat, lon, radiusKm = 25, enabled = true }: UseBtcMapPlacesOptions) {
return useQuery({
queryKey: ['btcmap-places', lat.toFixed(2), lon.toFixed(2), radiusKm],
queryFn: async () => {
const fields = 'id,lat,lon,icon,name,address,opening_hours,verified_at,boosted_until,website,phone,description';
const url = `https://api.btcmap.org/v4/places/search?lat=${lat}&lon=${lon}&radius_km=${radiusKm}&fields=${fields}`;
console.log('[useBtcMapPlaces] Fetching:', url);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`BTC Map API error: ${response.status}`);
}
const places: BtcMapPlace[] = await response.json();
console.log('[useBtcMapPlaces] Found', places.length, 'places');
return places;
},
enabled: enabled && lat !== 0 && lon !== 0,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 30 * 60 * 1000, // 30 minutes cache
refetchOnWindowFocus: false,
});
}
/**
* Get Material Icons URL for a BTC Map place icon
*/
export function getBtcMapIconUrl(icon: string): string {
return `https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/${icon}/default/24px.svg`;
}
/**
* Check if a place was recently verified (within last 6 months)
*/
export function isRecentlyVerified(verifiedAt?: string): boolean {
if (!verifiedAt) return false;
const sixMonthsAgo = new Date();
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
return new Date(verifiedAt) > sixMonthsAgo;
}
/**
* Check if a place is currently boosted
*/
export function isBoosted(boostedUntil?: string): boolean {
if (!boostedUntil) return false;
return new Date(boostedUntil) > new Date();
}