Small fixes & fmt

This commit is contained in:
Andras Schmelczer 2026-03-19 21:51:07 +00:00
parent 6b12e21d50
commit f32a552f46
23 changed files with 347 additions and 99 deletions

View file

@ -1,4 +1,4 @@
import { useState, useCallback, useMemo, useRef } from 'react';
import { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import type { FeatureMeta, FeatureFilters } from '../types';
import { trackEvent } from '../lib/analytics';
@ -15,6 +15,7 @@ export function useFilters({ initialFilters, features }: UseFiltersOptions) {
const pendingDragRef = useRef<string | null>(null);
const dragActiveRef = useRef<string | null>(null);
const dragValueRef = useRef<[number, number] | null>(null);
const undoStackRef = useRef<FeatureFilters[]>([]);
const enabledFeatures = useMemo(() => new Set(Object.keys(filters)), [filters]);
@ -34,17 +35,41 @@ export function useFilters({ initialFilters, features }: UseFiltersOptions) {
const meta = features.find((f) => f.name === name);
if (!meta) return;
trackEvent('Filter Add', { feature: name });
if (meta.type === 'enum' && meta.values) {
setFilters((prev) => ({ ...prev, [name]: [...meta.values!] }));
} else if (meta.type === 'numeric' && meta.histogram) {
setFilters((prev) => ({ ...prev, [name]: [meta.histogram!.min, meta.histogram!.max] }));
} else if (meta.min != null && meta.max != null) {
setFilters((prev) => ({ ...prev, [name]: [meta.min!, meta.max!] }));
}
setFilters((prev) => {
undoStackRef.current.push(prev);
if (undoStackRef.current.length > 50) undoStackRef.current.shift();
if (meta.type === 'enum' && meta.values) {
return { ...prev, [name]: [...meta.values!] };
} else if (meta.type === 'numeric' && meta.histogram) {
return { ...prev, [name]: [meta.histogram!.min, meta.histogram!.max] };
} else if (meta.min != null && meta.max != null) {
return { ...prev, [name]: [meta.min!, meta.max!] };
}
return prev;
});
},
[features]
);
const handleUndo = useCallback(() => {
const prev = undoStackRef.current.pop();
if (prev) setFilters(prev);
}, []);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'z' && !e.shiftKey) {
const target = e.target as HTMLElement;
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable)
return;
e.preventDefault();
handleUndo();
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [handleUndo]);
const handleFilterChange = useCallback((name: string, value: [number, number] | string[]) => {
setFilters((prev) => ({ ...prev, [name]: value }));
}, []);

View file

@ -167,6 +167,15 @@ export function useSavedSearches(userId: string | null) {
}
}, []);
const updateSearchName = useCallback(async (id: string, name: string) => {
try {
await pb.collection('saved_searches').update(id, { name });
setSearches((prev) => prev.map((s) => (s.id === id ? { ...s, name } : s)));
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to update name');
}
}, []);
return {
searches,
loading,
@ -176,5 +185,6 @@ export function useSavedSearches(userId: string | null) {
saveSearch,
deleteSearch,
updateSearchNotes,
updateSearchName,
};
}

View file

@ -30,8 +30,12 @@ export function useTravelDestinations(mode: TransportMode) {
return res.json();
})
.then((data: { destinations: Destination[] }) => {
cacheRef.current[mode] = data.destinations;
setDestinations(data.destinations);
const normalized = data.destinations.map((d) => ({
...d,
city: d.city === 'City of London' ? 'London' : d.city,
}));
cacheRef.current[mode] = normalized;
setDestinations(normalized);
})
.catch((err) => logNonAbortError('travel destinations', err))
.finally(() => setLoading(false));