import { useCallback, useEffect, useMemo, useState } from 'react'; import { api } from '../api/api'; import { ApiError } from '../api/http'; import type { City, WorldEvent } from '../api/types'; import { useAuth } from '../auth/AuthContext'; import { useToast } from '../components/Toast'; import { formatMoney, riskLabel } from '../shared/format'; /** Sagoma stilizzata dell'Italia (coordinate 0-100, stesse di City.mapX/mapY). */ const ITALY_MAINLAND = 'M12,18 L18,11 L30,9 L44,8 L50,13 L54,20 L60,28 L70,40 L82,46 L91,52 L88,57 L79,58 ' + 'L71,63 L65,71 L63,79 L58,76 L57,67 L52,58 L45,46 L37,34 L25,27 L15,24 Z'; const ITALY_SICILY = 'M44,83 L54,81 L62,84 L58,91 L48,93 L43,88 Z'; const ITALY_SARDINIA = 'M13,55 L21,56 L22,66 L19,74 L12,72 L11,62 Z'; const RISK_COLORS: Record = { basso: '#4caf6e', medio: '#d4a017', alto: '#d9534f', }; export function TravelScreen() { const { player, setPlayer } = useAuth(); const { toast } = useToast(); const [cities, setCities] = useState([]); const [events, setEvents] = useState([]); const [selected, setSelected] = useState(null); const [busy, setBusy] = useState(false); const reload = useCallback(async () => { const [c, e] = await Promise.all([api.cities(), api.events()]); setCities(c.cities); setEvents(e.events); }, []); useEffect(() => { void reload(); }, [reload]); const eventsByCity = useMemo(() => { const map = new Map(); for (const event of events) { const key = event.city?.id ?? 'global'; map.set(key, [...(map.get(key) ?? []), event]); } return map; }, [events]); const cityEvents = (cityId: string): WorldEvent[] => [ ...(eventsByCity.get(cityId) ?? []), ...(eventsByCity.get('global') ?? []), ]; async function travelTo(city: City) { setBusy(true); try { const res = await api.travel(city.id); setPlayer(res.player); toast(`Benvenuto a ${res.cityName} (−${formatMoney(res.cost)})`, 'success'); setSelected(null); } catch (err) { toast(err instanceof ApiError ? err.message : 'Errore imprevisto', 'error'); } finally { setBusy(false); } } return (

Mappa

{cities.map((city) => { const isCurrent = player?.currentCityId === city.id; const hasEvent = (eventsByCity.get(city.id) ?? []).length > 0; const color = RISK_COLORS[riskLabel(city.riskLevel)] ?? '#d4a017'; return ( setSelected(city)} transform={`translate(${city.mapX}, ${city.mapY})`} > {isCurrent && } {hasEvent && ( )} {city.name} ); })}

● colore = rischio (verde basso, oro medio, rosso alto) · ⚡ evento in corso · tocca una città per viaggiare

    {cities.map((city) => { const isCurrent = player?.currentCityId === city.id; return (
  • setSelected(city)} >
    {city.name} {isCurrent && sei qui} {(eventsByCity.get(city.id) ?? []).length > 0 && }
    {isCurrent ? '—' : formatMoney(city.travelCost)}
  • ); })}
{selected && (
setSelected(null)}>
e.stopPropagation()}>

{selected.name}

rischio {riskLabel(selected.riskLevel)} · economia ×{selected.economyModifier} · polizia ×{selected.policePressure}

{cityEvents(selected.id).length > 0 && (
{cityEvents(selected.id).map((event) => ( ⚡ {event.title} {!event.city && ' (globale)'} ))}
)} {player?.currentCityId === selected.id ? (

Ti trovi già in questa città.

) : ( )}
)}
); }