This commit is contained in:
Andras Schmelczer 2026-02-15 22:39:49 +00:00
parent 03445188ea
commit 524580eb25
102 changed files with 36625 additions and 1295 deletions

View file

@ -12,71 +12,73 @@ export const MODE_LABELS: Record<TransportMode, string> = {
};
export interface TravelTimeEntry {
destination: [number, number] | null; // [lat, lon]
destinationLabel: string;
mode: TransportMode;
slug: string;
label: string;
timeRange: [number, number] | null;
}
export type TravelTimeEntries = Partial<Record<TransportMode, TravelTimeEntry>>;
/** Unique key for a travel time entry */
export function travelEntryKey(entry: TravelTimeEntry): string {
return `${entry.mode}:${entry.slug}`;
}
/** Field key matching the backend response: tt_{mode}_{slug} */
export function travelFieldKey(entry: TravelTimeEntry): string {
return `tt_${entry.mode}_${entry.slug}`;
}
export interface TravelTimeInitial {
entries?: TravelTimeEntries;
entries?: TravelTimeEntry[];
}
export function useTravelTime(initial?: TravelTimeInitial) {
const [entries, setEntries] = useState<TravelTimeEntries>(initial?.entries ?? {});
const [entries, setEntries] = useState<TravelTimeEntry[]>(initial?.entries ?? []);
const activeModes = useMemo(
() => TRANSPORT_MODES.filter((m) => m in entries),
[entries]
);
const modesWithDestination = useMemo(
() => TRANSPORT_MODES.filter((m) => entries[m]?.destination != null),
[entries]
);
const handleEnableMode = useCallback((mode: TransportMode) => {
setEntries((prev) => ({
const handleAddEntry = useCallback((mode: TransportMode) => {
setEntries((prev) => [
...prev,
[mode]: { destination: null, destinationLabel: '', timeRange: null },
}));
{ mode, slug: '', label: '', timeRange: null },
]);
}, []);
const handleDisableMode = useCallback((mode: TransportMode) => {
setEntries((prev) => {
const next = { ...prev };
delete next[mode];
return next;
});
const handleRemoveEntry = useCallback((index: number) => {
setEntries((prev) => prev.filter((_, i) => i !== index));
}, []);
const handleSetDestination = useCallback(
(mode: TransportMode, lat: number, lon: number, label: string) => {
setEntries((prev) => ({
...prev,
[mode]: { ...prev[mode], destination: [lat, lon] as [number, number], destinationLabel: label },
}));
(index: number, slug: string, label: string) => {
setEntries((prev) =>
prev.map((entry, i) =>
i === index ? { ...entry, slug, label, timeRange: null } : entry
)
);
},
[]
);
const handleTimeRangeChange = useCallback(
(mode: TransportMode, range: [number, number]) => {
setEntries((prev) => ({
...prev,
[mode]: { ...prev[mode], timeRange: range },
}));
(index: number, range: [number, number]) => {
setEntries((prev) =>
prev.map((entry, i) =>
i === index ? { ...entry, timeRange: range } : entry
)
);
},
[]
);
/** Entries that have a destination selected (slug is set) */
const activeEntries = useMemo(
() => entries.filter((e) => e.slug !== ''),
[entries]
);
return {
entries,
activeModes,
modesWithDestination,
handleEnableMode,
handleDisableMode,
activeEntries,
handleAddEntry,
handleRemoveEntry,
handleSetDestination,
handleTimeRangeChange,
};