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>
78 lines
2.2 KiB
TypeScript
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();
|
|
}
|