More fixes

This commit is contained in:
Andras Schmelczer 2026-03-18 22:46:08 +00:00
parent 15fa09430b
commit 6b12e21d50
54 changed files with 1665 additions and 630 deletions

View file

@ -17,6 +17,8 @@ export interface AiFiltersResult {
notes: string;
/** Human-readable summary of what was set */
summary: string;
/** The listing mode used (historical/buy/rent) */
listingType: string;
}
export type AiFilterErrorType = 'auth' | 'limit' | 'error';
@ -28,7 +30,11 @@ export interface AiFiltersContext {
}
interface UseAiFiltersResult {
fetchAiFilters: (query: string, context?: AiFiltersContext) => Promise<AiFiltersResult | null>;
fetchAiFilters: (
query: string,
context?: AiFiltersContext,
listingType?: string
) => Promise<AiFiltersResult | null>;
loading: boolean;
error: string | null;
errorType: AiFilterErrorType | null;
@ -41,6 +47,8 @@ function buildSummary(filters: FeatureFilters, travelTimeFilters: AiTravelTimeFi
const parts: string[] = [];
for (const [name, value] of Object.entries(filters)) {
// Skip Listing status — shown via the mode selector UI
if (name === 'Listing status') continue;
if (Array.isArray(value) && value.length === 2 && typeof value[0] === 'number') {
parts.push(name);
} else if (Array.isArray(value)) {
@ -67,7 +75,11 @@ export function useAiFilters(): UseAiFiltersResult {
const abortRef = useRef<AbortController | null>(null);
const fetchAiFilters = useCallback(
async (query: string, context?: AiFiltersContext): Promise<AiFiltersResult | null> => {
async (
query: string,
context?: AiFiltersContext,
listingType?: string
): Promise<AiFiltersResult | null> => {
abortRef.current?.abort();
const controller = new AbortController();
abortRef.current = controller;
@ -81,6 +93,7 @@ export function useAiFilters(): UseAiFiltersResult {
try {
const url = apiUrl('ai-filters');
const bodyObj: Record<string, unknown> = { query };
if (listingType) bodyObj.listing_type = listingType;
if (context) {
bodyObj.context = {
filters: context.filters,
@ -130,6 +143,7 @@ export function useAiFilters(): UseAiFiltersResult {
travelTimeFilters,
notes: json.notes || '',
summary: summaryText,
listingType: json.listing_type || 'historical',
};
setNotes(result.notes || null);
setSummary(summaryText);

View file

@ -95,7 +95,7 @@ export function useDeckLayers({
useEffect(() => {
if (!hasSelection) return;
setMarchTime(0);
const id = setInterval(() => setMarchTime((t) => t + 0.3), 50);
const id = setInterval(() => setMarchTime((t) => (t + 0.3) % 10000), 50);
return () => clearInterval(id);
}, [hasSelection]);

View file

@ -1,4 +1,6 @@
import { useState, useCallback, useMemo } from 'react';
import type { ComponentType } from 'react';
import { CarIcon, BicycleIcon, WalkingIcon, TransitIcon } from '../components/ui/icons';
export type TransportMode = 'car' | 'bicycle' | 'walking' | 'transit';
@ -18,6 +20,13 @@ export const MODE_DESCRIPTIONS: Record<TransportMode, string> = {
transit: 'Journey time by train, tube, and bus',
};
export const MODE_ICONS: Record<TransportMode, ComponentType<{ className?: string }>> = {
car: CarIcon,
bicycle: BicycleIcon,
walking: WalkingIcon,
transit: TransitIcon,
};
export interface TravelTimeEntry {
mode: TransportMode;
slug: string;

View file

@ -59,13 +59,13 @@ const STEPS: Step[] = [
},
];
export function useTutorial(initialLoading: boolean, isMobile: boolean) {
export function useTutorial(initialLoading: boolean, isMobile: boolean, blocked = false) {
const [run, setRun] = useState(() => {
if (isMobile) return false;
return !localStorage.getItem(STORAGE_KEY);
});
const shouldRun = run && !initialLoading && !isMobile;
const shouldRun = run && !initialLoading && !isMobile && !blocked;
const handleCallback = useCallback((data: CallBackProps) => {
const { status, action, type } = data;