Enhance country data retrieval and error handling in WatchedMap component
- Improved country code extraction logic to handle null values and prevent rendering errors. - Added error handling for API responses to ensure graceful degradation in case of failures. - Updated the logic for determining country codes from GeoJSON features to account for missing values. - Set default values for watched items and summary to avoid application crashes during data fetch failures.
This commit is contained in:
@@ -218,7 +218,22 @@ async def get_musicbrainz_artist_country(mbid: str) -> Optional[str]:
|
|||||||
)
|
)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
# Check area relations for country
|
|
||||||
|
# First, check direct country field
|
||||||
|
if "country" in data and data["country"]:
|
||||||
|
country = data["country"]
|
||||||
|
if isinstance(country, str) and len(country) == 2:
|
||||||
|
return country.upper()
|
||||||
|
|
||||||
|
# Second, check area.iso-3166-1-codes
|
||||||
|
if "area" in data and data["area"]:
|
||||||
|
area = data["area"]
|
||||||
|
if "iso-3166-1-codes" in area and area["iso-3166-1-codes"]:
|
||||||
|
codes = area["iso-3166-1-codes"]
|
||||||
|
if isinstance(codes, list) and len(codes) > 0:
|
||||||
|
return codes[0].upper()
|
||||||
|
|
||||||
|
# Third, check area relations for country
|
||||||
if "relations" in data:
|
if "relations" in data:
|
||||||
for relation in data["relations"]:
|
for relation in data["relations"]:
|
||||||
if relation.get("type") == "origin" and "area" in relation:
|
if relation.get("type") == "origin" and "area" in relation:
|
||||||
|
|||||||
@@ -59,11 +59,25 @@ export default function WatchedMap() {
|
|||||||
fetch('/api/watched/summary'),
|
fetch('/api/watched/summary'),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if (!watchedRes.ok) {
|
||||||
|
throw new Error(`Watched API error: ${watchedRes.status}`)
|
||||||
|
}
|
||||||
|
if (!pinsRes.ok) {
|
||||||
|
throw new Error(`Pins API error: ${pinsRes.status}`)
|
||||||
|
}
|
||||||
|
if (!summaryRes.ok) {
|
||||||
|
throw new Error(`Summary API error: ${summaryRes.status}`)
|
||||||
|
}
|
||||||
|
|
||||||
setWatchedItems(await watchedRes.json())
|
setWatchedItems(await watchedRes.json())
|
||||||
setPins(await pinsRes.json())
|
setPins(await pinsRes.json())
|
||||||
setSummary(await summaryRes.json())
|
setSummary(await summaryRes.json())
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch data:', error)
|
console.error('Failed to fetch data:', error)
|
||||||
|
// Set empty defaults to prevent rendering errors
|
||||||
|
setWatchedItems([])
|
||||||
|
setPins([])
|
||||||
|
setSummary({})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +137,8 @@ export default function WatchedMap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCountryCount = (countryCode: string): number => {
|
const getCountryCount = (countryCode: string | null): number => {
|
||||||
|
if (!countryCode) return 0
|
||||||
const data = summary[countryCode] || {}
|
const data = summary[countryCode] || {}
|
||||||
return (data.movie || 0) + (data.show || 0)
|
return (data.movie || 0) + (data.show || 0)
|
||||||
}
|
}
|
||||||
@@ -133,7 +148,8 @@ export default function WatchedMap() {
|
|||||||
return Math.max(...counts, 1)
|
return Math.max(...counts, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCountryColor = (countryCode: string): string => {
|
const getCountryColor = (countryCode: string | null): string => {
|
||||||
|
if (!countryCode) return '#e0e0e0'
|
||||||
const count = getCountryCount(countryCode)
|
const count = getCountryCount(countryCode)
|
||||||
const maxCount = getMaxCount()
|
const maxCount = getMaxCount()
|
||||||
if (count === 0) return '#e0e0e0'
|
if (count === 0) return '#e0e0e0'
|
||||||
@@ -228,21 +244,27 @@ export default function WatchedMap() {
|
|||||||
<GeoJSON
|
<GeoJSON
|
||||||
data={worldGeoJson}
|
data={worldGeoJson}
|
||||||
style={(feature) => {
|
style={(feature) => {
|
||||||
const code = feature?.properties?.ISO_A2 || feature?.properties?.ISO_A3?.substring(0, 2)
|
const isoA2 = feature?.properties?.ISO_A2
|
||||||
|
const isoA3 = feature?.properties?.ISO_A3
|
||||||
|
const code = isoA2 || (isoA3 && typeof isoA3 === 'string' ? isoA3.substring(0, 2) : null) || null
|
||||||
return {
|
return {
|
||||||
fillColor: getCountryColor(code),
|
fillColor: getCountryColor(code || ''),
|
||||||
fillOpacity: 0.7,
|
fillOpacity: 0.7,
|
||||||
color: '#666',
|
color: '#666',
|
||||||
weight: 1,
|
weight: 1,
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onEachFeature={(feature, layer) => {
|
onEachFeature={(feature, layer) => {
|
||||||
const code = feature?.properties?.ISO_A2 || feature?.properties?.ISO_A3?.substring(0, 2)
|
const isoA2 = feature?.properties?.ISO_A2
|
||||||
|
const isoA3 = feature?.properties?.ISO_A3
|
||||||
|
const code = isoA2 || (isoA3 && typeof isoA3 === 'string' ? isoA3.substring(0, 2) : null) || null
|
||||||
|
if (!code) return
|
||||||
|
|
||||||
const count = getCountryCount(code)
|
const count = getCountryCount(code)
|
||||||
const data = summary[code] || {}
|
const data = summary[code] || {}
|
||||||
|
|
||||||
layer.bindPopup(`
|
layer.bindPopup(`
|
||||||
<strong>${feature.properties.NAME || code}</strong><br/>
|
<strong>${feature.properties?.NAME || code}</strong><br/>
|
||||||
Watched: ${count}<br/>
|
Watched: ${count}<br/>
|
||||||
${data.movie ? `Movies: ${data.movie}<br/>` : ''}
|
${data.movie ? `Movies: ${data.movie}<br/>` : ''}
|
||||||
${data.show ? `Shows: ${data.show}` : ''}
|
${data.show ? `Shows: ${data.show}` : ''}
|
||||||
|
|||||||
Reference in New Issue
Block a user