diff --git a/frontend/src/components/map/AiFilterInput.tsx b/frontend/src/components/map/AiFilterInput.tsx index 937f6de..e7e5c55 100644 --- a/frontend/src/components/map/AiFilterInput.tsx +++ b/frontend/src/components/map/AiFilterInput.tsx @@ -1,15 +1,27 @@ import { memo, useState, useCallback } from 'react'; import { SpinnerIcon } from '../ui/icons/SpinnerIcon'; import { SparklesIcon } from '../ui/icons/SparklesIcon'; +import type { AiFilterErrorType } from '../../hooks/useAiFilters'; interface AiFilterInputProps { loading: boolean; error: string | null; + errorType: AiFilterErrorType | null; notes: string | null; onSubmit: (query: string) => void; + isLoggedIn: boolean; + onLoginRequired: () => void; } -export default memo(function AiFilterInput({ loading, error, notes, onSubmit }: AiFilterInputProps) { +export default memo(function AiFilterInput({ + loading, + error, + errorType, + notes, + onSubmit, + isLoggedIn, + onLoginRequired, +}: AiFilterInputProps) { const [query, setQuery] = useState(''); const handleSubmit = useCallback( @@ -17,9 +29,13 @@ export default memo(function AiFilterInput({ loading, error, notes, onSubmit }: e.preventDefault(); const trimmed = query.trim(); if (!trimmed || loading) return; + if (!isLoggedIn) { + onLoginRequired(); + return; + } onSubmit(trimmed); }, - [query, loading, onSubmit] + [query, loading, isLoggedIn, onLoginRequired, onSubmit] ); const hasContent = query.trim().length > 0; @@ -52,7 +68,17 @@ export default memo(function AiFilterInput({ loading, error, notes, onSubmit }: )} - {error && ( + {error && errorType === 'verification' && ( +
+ Please verify your email address to use AI-powered search. Check your inbox for a verification link. +
+ )} + {error && errorType === 'limit' && ( ++ You've reached the weekly AI usage limit. It will reset automatically next week. +
+ )} + {error && errorType === 'error' && ({error}
diff --git a/frontend/src/components/map/Filters.tsx b/frontend/src/components/map/Filters.tsx index 5b00bee..280148b 100644 --- a/frontend/src/components/map/Filters.tsx +++ b/frontend/src/components/map/Filters.tsx @@ -15,6 +15,7 @@ import { FeatureInfoPopup } from '../ui/FeatureInfoPopup'; import { FeatureActions } from '../ui/FeatureIcons'; import { FeatureLabel } from '../ui/FeatureLabel'; import AiFilterInput from './AiFilterInput'; +import type { AiFilterErrorType } from '../../hooks/useAiFilters'; import FeatureBrowser from './FeatureBrowser'; import { TravelTimeCard } from './TravelTimeCard'; import { @@ -89,8 +90,11 @@ interface FiltersProps { onTravelTimeToggleBest: (index: number) => void; aiFilterLoading: boolean; aiFilterError: string | null; + aiFilterErrorType: AiFilterErrorType | null; aiFilterNotes: string | null; onAiFilterSubmit: (query: string) => void; + isLoggedIn: boolean; + onLoginRequired: () => void; isLicensed: boolean; onUpgradeClick?: () => void; onResetTutorial?: () => void; @@ -121,8 +125,11 @@ export default memo(function Filters({ onTravelTimeToggleBest, aiFilterLoading, aiFilterError, + aiFilterErrorType, aiFilterNotes, onAiFilterSubmit, + isLoggedIn, + onLoginRequired, isLicensed, onUpgradeClick, onResetTutorial, @@ -278,7 +285,7 @@ export default memo(function Filters({