diff --git a/src/App.tsx b/src/App.tsx index a2e29c0..e7e4729 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,6 +12,7 @@ export default function App() { const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); + const [lastUpdate, setLastUpdate] = useState(null); const [source, setSource] = useState<'live' | 'mock'>('mock'); useEffect(() => { @@ -26,6 +27,7 @@ export default function App() { setTransactions(transactions); setStats(stats); setSource(source); + setLastUpdate(new Date()); } }) .catch((err) => console.warn('Ğ1Flux refresh error:', err)) @@ -66,7 +68,7 @@ export default function App() { : 'bg-[#0a0b0f]/80 border-[#2e2f3a] text-[#4b5563]' }`}> {source === 'live' - ? <>{refreshing ? : '●'} live Ğ1v2 + ? <>{refreshing ? : '●'} live Ğ1v2{lastUpdate && {lastUpdate.toLocaleTimeString('fr-FR')}} : '○ mock'} diff --git a/src/services/adapters/CesiumAdapter.ts b/src/services/adapters/CesiumAdapter.ts index 822da0b..2e67109 100644 --- a/src/services/adapters/CesiumAdapter.ts +++ b/src/services/adapters/CesiumAdapter.ts @@ -25,16 +25,17 @@ export interface GeoProfile { // Détection de pays par bounding box (pays présents dans la communauté Ğ1) const COUNTRY_BOXES: { code: string; latMin: number; latMax: number; lngMin: number; lngMax: number }[] = [ - { code: 'FR', latMin: 41.3, latMax: 51.1, lngMin: -5.1, lngMax: 9.6 }, + // Petits pays d'abord : leurs bounding boxes chevauchent celle de la France + { code: 'LU', latMin: 49.4, latMax: 50.2, lngMin: 5.7, lngMax: 6.5 }, { code: 'BE', latMin: 49.5, latMax: 51.5, lngMin: 2.5, lngMax: 6.4 }, { code: 'CH', latMin: 45.8, latMax: 47.8, lngMin: 5.9, lngMax: 10.5 }, - { code: 'LU', latMin: 49.4, latMax: 50.2, lngMin: 5.7, lngMax: 6.5 }, + { code: 'NL', latMin: 50.7, latMax: 53.6, lngMin: 3.3, lngMax: 7.2 }, { code: 'DE', latMin: 47.3, latMax: 55.1, lngMin: 6.0, lngMax: 15.0 }, + { code: 'FR', latMin: 41.3, latMax: 51.1, lngMin: -5.1, lngMax: 9.6 }, { code: 'ES', latMin: 35.9, latMax: 43.8, lngMin: -9.3, lngMax: 4.3 }, { code: 'PT', latMin: 36.8, latMax: 42.2, lngMin: -9.5, lngMax: -6.2 }, { code: 'IT', latMin: 36.6, latMax: 47.1, lngMin: 6.6, lngMax: 18.5 }, { code: 'GB', latMin: 49.9, latMax: 60.9, lngMin: -8.2, lngMax: 1.8 }, - { code: 'NL', latMin: 50.7, latMax: 53.6, lngMin: 3.3, lngMax: 7.2 }, { code: 'MA', latMin: 27.6, latMax: 35.9, lngMin: -13.2, lngMax: -1.0 }, { code: 'TN', latMin: 30.2, latMax: 37.5, lngMin: 7.5, lngMax: 11.6 }, { code: 'SN', latMin: 12.3, latMax: 16.7, lngMin: -17.5, lngMax: -11.4 }, @@ -55,6 +56,29 @@ export function cleanCityName(city: string): string { return city.split(',')[0].trim(); } +// Noms de pays en français/anglais → code ISO (Cesium+ utilise le français) +const COUNTRY_NAME_TO_CODE: Record = { + 'france': 'FR', 'belgique': 'BE', 'belgium': 'BE', + 'suisse': 'CH', 'switzerland': 'CH', 'schweiz': 'CH', + 'luxembourg': 'LU', 'allemagne': 'DE', 'germany': 'DE', + 'espagne': 'ES', 'spain': 'ES', 'portugal': 'PT', + 'italie': 'IT', 'italy': 'IT', 'pays-bas': 'NL', + 'netherlands': 'NL', 'royaume-uni': 'GB', 'united kingdom': 'GB', + 'maroc': 'MA', 'morocco': 'MA', 'tunisie': 'TN', 'tunisia': 'TN', + 'sénégal': 'SN', 'senegal': 'SN', 'canada': 'CA', 'brésil': 'BR', 'brazil': 'BR', +}; + +/** Extrait le pays depuis le champ city Cesium+ (ex: "Heusy, 4800, Belgique" → "BE") */ +function countryCodeFromCity(city: string): string { + const parts = city.split(','); + for (let i = parts.length - 1; i >= 0; i--) { + const token = parts[i].trim().toLowerCase(); + const code = COUNTRY_NAME_TO_CODE[token]; + if (code) return code; + } + return ''; +} + // geoPoint accepte n'importe quel type — Cesium+ utilise plusieurs formats ES geo_point const HitSchema = z.object({ _id: z.string(), @@ -127,10 +151,11 @@ export async function resolveGeoByKeys( const src = hit._source; const geo = parseGeoPoint(src.geoPoint); if (!geo) continue; + const city = src.city ?? 'Inconnue'; result.set(hit._id, { name: src.title ?? '', - city: src.city ?? 'Inconnue', - countryCode: latLngToCountryCode(geo.lat, geo.lng), + city, + countryCode: countryCodeFromCity(city) || latLngToCountryCode(geo.lat, geo.lng), lat: geo.lat, lng: geo.lng, }); @@ -186,10 +211,11 @@ export async function resolveGeoByNames( const src = hit._source; const geo = parseGeoPoint(src.geoPoint); if (geo && src.title) { + const city = src.city ?? 'Inconnue'; result.set(src.title.toLowerCase(), { name: src.title, - city: src.city ?? 'Inconnue', - countryCode: latLngToCountryCode(geo.lat, geo.lng), + city, + countryCode: countryCodeFromCity(city) || latLngToCountryCode(geo.lat, geo.lng), lat: geo.lat, lng: geo.lng, });