From 1bc512af60816b978a555d5efdbdd9150869c226 Mon Sep 17 00:00:00 2001 From: alma Date: Sun, 4 May 2025 16:58:04 +0200 Subject: [PATCH] observatory --- app/api/news/route.ts | 7 +- components/observatory/observatory-map.tsx | 154 +++++++++++++------- components/observatory/observatory-view.tsx | 33 ++++- 3 files changed, 129 insertions(+), 65 deletions(-) diff --git a/app/api/news/route.ts b/app/api/news/route.ts index 9d123972..44bb2ee3 100644 --- a/app/api/news/route.ts +++ b/app/api/news/route.ts @@ -96,13 +96,16 @@ export async function GET(request: Request) { console.log('Fetching news from FastAPI server...'); - const response = await fetch(`${env.NEWS_API_URL}/news?limit=12`, { + // Get limit from query params or default to 100 + const limit = url.searchParams.get('limit') || '100'; + + const response = await fetch(`${env.NEWS_API_URL}/news?limit=${limit}`, { method: 'GET', headers: { 'Accept': 'application/json', }, // Add timeout to prevent hanging - signal: AbortSignal.timeout(5000) + signal: AbortSignal.timeout(10000) // Extended timeout for larger requests }); if (!response.ok) { diff --git a/components/observatory/observatory-map.tsx b/components/observatory/observatory-map.tsx index d822fffc..0b8f1256 100644 --- a/components/observatory/observatory-map.tsx +++ b/components/observatory/observatory-map.tsx @@ -16,6 +16,71 @@ interface ObservatoryMapProps { selectedCountry: string | null; } +// Simplified map positions for common countries +const COUNTRY_POSITIONS: Record = { + // Africa + 'Sudan': [0.55, 0.45], + 'Egypt': [0.57, 0.40], + 'South Africa': [0.55, 0.65], + 'Nigeria': [0.48, 0.50], + 'Kenya': [0.59, 0.52], + 'Ethiopia': [0.60, 0.47], + 'Morocco': [0.45, 0.38], + 'Algeria': [0.47, 0.40], + 'Tunisia': [0.48, 0.36], + + // Americas + 'USA': [0.25, 0.35], + 'New York': [0.28, 0.32], + 'Canada': [0.22, 0.25], + 'Mexico': [0.20, 0.40], + 'Brazil': [0.35, 0.60], + 'Argentina': [0.32, 0.70], + + // Europe + 'UK': [0.45, 0.25], + 'France': [0.48, 0.30], + 'Germany': [0.50, 0.28], + 'Italy': [0.52, 0.33], + 'Spain': [0.45, 0.33], + 'Ukraine': [0.57, 0.28], + 'Russia': [0.65, 0.20], + 'Poland': [0.53, 0.26], + 'Sweden': [0.52, 0.18], + 'Norway': [0.50, 0.15], + 'Finland': [0.55, 0.15], + 'Greece': [0.55, 0.35], + 'Netherlands': [0.48, 0.25], + 'Belgium': [0.47, 0.27], + 'Portugal': [0.43, 0.35], + 'Switzerland': [0.49, 0.29], + 'Austria': [0.51, 0.29], + + // Asia + 'China': [0.75, 0.35], + 'India': [0.70, 0.40], + 'Japan': [0.85, 0.33], + 'South Korea': [0.83, 0.32], + 'Indonesia': [0.78, 0.55], + 'Thailand': [0.75, 0.45], + 'Vietnam': [0.78, 0.43], + 'Philippines': [0.82, 0.45], + 'Malaysia': [0.76, 0.50], + 'Singapore': [0.76, 0.52], + 'Pakistan': [0.67, 0.38], + 'Iran': [0.62, 0.38], + 'Iraq': [0.60, 0.38], + 'Saudi Arabia': [0.60, 0.42], + 'Turkey': [0.58, 0.35], + 'Israel': [0.58, 0.38], + 'Palestine': [0.58, 0.39], + 'Syria': [0.59, 0.37], + 'Afghanistan': [0.65, 0.38], + + // Oceania + 'Australia': [0.80, 0.65] +}; + export function ObservatoryMap({ countries, onCountrySelect, @@ -70,74 +135,52 @@ export function ObservatoryMap({ ctx.stroke(); } - // Draw country markers at more fixed positions + // Calculate the top countries by news count + const topCountries = [...countries] + .sort((a, b) => b.count - a.count) + .slice(0, 15); + + // Draw country markers for all countries countries.forEach((country) => { // Position based on country name (simplified) let x, y; - // Very simple positioning logic - switch(country.name) { - case 'Sudan': - x = canvas.width * 0.55; - y = canvas.height * 0.45; - break; - case 'Ukraine': - x = canvas.width * 0.65; - y = canvas.height * 0.25; - break; - case 'USA': - case 'New York': - x = canvas.width * 0.25; - y = canvas.height * 0.35; - break; - case 'UK': - x = canvas.width * 0.45; - y = canvas.height * 0.25; - break; - case 'France': - x = canvas.width * 0.48; - y = canvas.height * 0.30; - break; - case 'China': - x = canvas.width * 0.75; - y = canvas.height * 0.35; - break; - case 'Russia': - x = canvas.width * 0.70; - y = canvas.height * 0.20; - break; - case 'India': - x = canvas.width * 0.70; - y = canvas.height * 0.40; - break; - case 'Brazil': - x = canvas.width * 0.35; - y = canvas.height * 0.60; - break; - case 'Australia': - x = canvas.width * 0.80; - y = canvas.height * 0.65; - break; - default: - // Random position for other countries - x = 100 + Math.random() * (canvas.width - 200); - y = 100 + Math.random() * (canvas.height - 200); + // Use predefined positions or random for others + if (COUNTRY_POSITIONS[country.name]) { + const [xRatio, yRatio] = COUNTRY_POSITIONS[country.name]; + x = canvas.width * xRatio; + y = canvas.height * yRatio; + } else { + // Random position for other countries + x = 100 + Math.random() * (canvas.width - 200); + y = 100 + Math.random() * (canvas.height - 200); } + // Size based on count (with limits) + const isTopCountry = topCountries.includes(country); + const size = Math.min(Math.max(3, country.count / 2), 8); + // Draw marker ctx.beginPath(); - ctx.arc(x, y, 6, 0, Math.PI * 2); + ctx.arc(x, y, size, 0, Math.PI * 2); - // Simple color - ctx.fillStyle = country.name === 'Sudan' ? '#f87171' : '#cbd5e1'; + // Color based on count and selection + if (country.name === selectedCountry) { + ctx.fillStyle = '#3b82f6'; // Blue when selected + } else if (isTopCountry) { + ctx.fillStyle = '#f87171'; // Red for top countries + } else { + ctx.fillStyle = '#cbd5e1'; // Gray for others + } ctx.fill(); - // Draw country name if it's Sudan or selected - if (country.name === 'Sudan' || country.name === selectedCountry) { + // Draw country name if it's a top country or selected + if (isTopCountry || country.name === selectedCountry) { ctx.fillStyle = '#374151'; ctx.font = '12px system-ui, sans-serif'; - ctx.fillText(country.name, x + 10, y + 4); + // Show count for top countries + ctx.fillText(`${country.name} (${country.count})`, x + 10, y + 4); } // Store coordinates for click detection @@ -154,11 +197,12 @@ export function ObservatoryMap({ // Check if a country marker was clicked for (const country of countries) { if (country.x && country.y) { + const size = Math.min(Math.max(3, country.count / 2), 8); const distance = Math.sqrt( Math.pow(x - country.x, 2) + Math.pow(y - country.y, 2) ); - if (distance <= 8) { + if (distance <= size + 2) { onCountrySelect(country.name); break; } diff --git a/components/observatory/observatory-view.tsx b/components/observatory/observatory-view.tsx index 82f545a6..acf59b3a 100644 --- a/components/observatory/observatory-view.tsx +++ b/components/observatory/observatory-view.tsx @@ -29,7 +29,7 @@ export function ObservatoryView() { setLoading(true); try { - const response = await fetch('/api/news?limit=50'); + const response = await fetch('/api/news?limit=100'); if (!response.ok) { throw new Error('Failed to fetch news'); } @@ -57,21 +57,38 @@ export function ObservatoryView() { const countries = [ 'France', 'USA', 'Canada', 'UK', 'Germany', 'Japan', 'China', 'India', 'Brazil', 'Australia', 'Russia', 'Italy', 'Spain', - 'Sudan', 'New York', 'United Nations', 'Ukraine' + 'Sudan', 'New York', 'United Nations', 'Ukraine', 'Egypt', + 'Mexico', 'South Africa', 'Nigeria', 'Argentina', 'Pakistan', + 'Indonesia', 'Saudi Arabia', 'Iran', 'Turkey', 'South Korea', + 'Thailand', 'Vietnam', 'Philippines', 'Malaysia', 'Singapore', + 'Israel', 'Palestine', 'Syria', 'Iraq', 'Afghanistan', + 'Morocco', 'Algeria', 'Tunisia', 'Kenya', 'Ethiopia', + 'Greece', 'Poland', 'Sweden', 'Norway', 'Denmark', 'Finland', + 'Netherlands', 'Belgium', 'Portugal', 'Switzerland', 'Austria' ]; + // Sort countries by length (to prioritize longer names) + const sortedCountries = [...countries].sort((a, b) => b.length - a.length); + const result: Record = {}; newsItems.forEach(item => { - countries.forEach(country => { - if ( - (item.title && item.title.includes(country)) || - (item.description && item.description.includes(country)) - ) { + // For title and description + const titleAndDesc = [ + item.title || '', + item.description || '' + ].join(' ').toLowerCase(); + + // Check each country + sortedCountries.forEach(country => { + if (titleAndDesc.includes(country.toLowerCase())) { if (!result[country]) { result[country] = []; } - result[country].push(item); + // Only add once per item + if (!result[country].some(existingItem => existingItem.id === item.id)) { + result[country].push(item); + } } }); });