import { useState } from 'react'; import { ss58ToDuniterKey, SUBSQUID_ENDPOINT } from '../services/adapters/SubsquidAdapter'; import { resolveGeoByKeys } from '../services/adapters/CesiumAdapter'; interface SearchBarProps { /** Appelé quand une ville est trouvée — App bascule en vue flux et met la ville en focus. */ onResult: (city: string) => void; } async function resolveQuery(query: string): Promise<{ name: string; city: string } | null> { const q = query.trim(); if (!q) return null; // Clé SS58 Ğ1v2 : commence par "g1" et fait ~50 caractères const isKey = /^g1[1-9A-HJ-NP-Za-km-z]{40,}$/.test(q); let duniterKey: string; let identityName: string; if (isKey) { duniterKey = ss58ToDuniterKey(q); identityName = q.slice(0, 10) + '…'; } else { const res = await fetch(SUBSQUID_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: ` query($q: String!) { identities(filter: { name: { includesInsensitive: $q } }, first: 1) { nodes { accountId name ownerKeyChange(orderBy: BLOCK_NUMBER_ASC, first: 1) { nodes { previousId } } } } } `, variables: { q }, }), }); if (!res.ok) throw new Error(`Subsquid HTTP ${res.status}`); const data = await res.json(); const node = data?.data?.identities?.nodes?.[0]; if (!node) return null; const genesisKey: string = node.ownerKeyChange.nodes[0]?.previousId ?? node.accountId; duniterKey = ss58ToDuniterKey(genesisKey); identityName = node.name as string; } const geoMap = await resolveGeoByKeys([duniterKey]); const geo = geoMap.get(duniterKey); if (!geo) return null; return { name: identityName, city: geo.city.split(',')[0].trim() }; } export function SearchBar({ onResult }: SearchBarProps) { const [open, setOpen] = useState(false); const [query, setQuery] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [found, setFound] = useState<{ name: string; city: string } | null>(null); const close = () => { setOpen(false); setQuery(''); setError(null); setFound(null); }; const handleSubmit = async () => { if (!query.trim()) return; setLoading(true); setError(null); setFound(null); try { const result = await resolveQuery(query); if (result) setFound(result); else setError('Introuvable dans Cesium+'); } catch { setError('Erreur de connexion'); } finally { setLoading(false); } }; const handleSelect = () => { if (!found) return; onResult(found.city); close(); }; if (!open) { return ( ); } return (
setQuery(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(); if (e.key === 'Escape') close(); }} placeholder="Nom ou clé g1…" className="flex-1 min-w-0 bg-[#0f1016] border border-[#2e2f3a] rounded-lg px-2 py-1.5 text-xs text-white placeholder-[#4b5563] focus:outline-none focus:border-[#d4a843] transition-colors" />
{error && (

{error}

)} {found && ( )}
); }