diff --git a/api/botDetection/heuristics.ts b/api/botDetection/heuristics.ts index 90e578fc..1a8be0c6 100644 --- a/api/botDetection/heuristics.ts +++ b/api/botDetection/heuristics.ts @@ -66,7 +66,7 @@ export function analyzeHeuristics(userAgent: string, headers: Record VercelResponse; - json: (data: any) => VercelResponse; + json: (data: unknown) => VercelResponse; send: (body: string) => VercelResponse; }; @@ -66,7 +66,7 @@ async function getPageData(pathname: string, fullUrl: string): Promise } // Individual ride page: /parks/{park-slug}/rides/{ride-slug} - if (normalizedPath.match(/^\/parks\/[^\/]+\/rides\/[^\/]+$/)) { + if (normalizedPath.match(/^\/parks\/[^/]+\/rides\/[^/]+$/)) { const parts = normalizedPath.split('/'); const rideSlug = parts[4]; @@ -178,7 +178,7 @@ function injectOGTags(html: string, ogTags: string): string { return html; } -export default async function handler(req: VercelRequest, res: VercelResponse) { +export default async function handler(req: VercelRequest, res: VercelResponse): Promise { try { const userAgent = req.headers['user-agent'] || ''; const fullUrl = `https://${req.headers.host}${req.url}`; @@ -239,7 +239,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const html = readFileSync(htmlPath, 'utf-8'); res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.status(200).send(html); - } catch (fallbackError) { + } catch { res.status(500).send('Internal Server Error'); } } diff --git a/src/App.tsx b/src/App.tsx index df1b84bc..8f1751fe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -79,7 +79,7 @@ const queryClient = new QueryClient({ }, }); -function AppContent() { +function AppContent(): React.JSX.Element { return ( @@ -154,7 +154,7 @@ function AppContent() { ); } -const App = () => ( +const App = (): React.JSX.Element => ( diff --git a/src/components/admin/AdminPageLayout.tsx b/src/components/admin/AdminPageLayout.tsx index c683ea03..6f3a01fc 100644 --- a/src/components/admin/AdminPageLayout.tsx +++ b/src/components/admin/AdminPageLayout.tsx @@ -66,8 +66,8 @@ export function AdminPageLayout({ getAdminPanelPollInterval, } = useAdminSettings(); - const refreshMode = getAdminPanelRefreshMode(); - const pollInterval = getAdminPanelPollInterval(); + const refreshMode = getAdminPanelRefreshMode() as 'auto' | 'manual'; + const pollInterval = getAdminPanelPollInterval() as number; const { lastUpdated } = useModerationStats({ enabled: isAuthorized && showRefreshControls, @@ -84,9 +84,9 @@ export function AdminPageLayout({ return (
@@ -117,9 +117,9 @@ export function AdminPageLayout({ return (
diff --git a/src/components/admin/DesignerForm.tsx b/src/components/admin/DesignerForm.tsx index d3c1dab7..96107f62 100644 --- a/src/components/admin/DesignerForm.tsx +++ b/src/components/admin/DesignerForm.tsx @@ -1,9 +1,7 @@ -import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { entitySchemas } from '@/lib/entityValidationSchemas'; -import { getErrorMessage } from '@/lib/errorHandler'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; @@ -15,36 +13,12 @@ import { SlugField } from '@/components/ui/slug-field'; import { Ruler, Save, X } from 'lucide-react'; import { useUserRole } from '@/hooks/useUserRole'; import { HeadquartersLocationInput } from './HeadquartersLocationInput'; -import { EntityMultiImageUploader, ImageAssignments } from '@/components/upload/EntityMultiImageUploader'; -import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-date-input'; -import { submitDesignerCreation, submitDesignerUpdate } from '@/lib/entitySubmissionHelpers'; +import { EntityMultiImageUploader } from '@/components/upload/EntityMultiImageUploader'; import { useAuth } from '@/hooks/useAuth'; import { toast } from 'sonner'; import { handleError } from '@/lib/errorHandler'; -import { useNavigate } from 'react-router-dom'; import type { UploadedImage } from '@/types/company'; -// Raw form input state (before Zod transformation) -interface DesignerFormInput { - name: string; - slug: string; - company_type: 'designer' | 'manufacturer' | 'operator' | 'property_owner'; - description?: string; - person_type: 'company' | 'individual' | 'firm' | 'organization'; - founded_year?: string; - founded_date?: string; - founded_date_precision?: 'day' | 'month' | 'year'; - headquarters_location?: string; - website_url?: string; - source_url?: string; - submission_notes?: string; - images?: { - uploaded: UploadedImage[]; - banner_assignment?: number | null; - card_assignment?: number | null; - }; -} - // Zod output type (after transformation) type DesignerFormData = z.infer; @@ -58,10 +32,9 @@ interface DesignerFormProps { }>; } -export function DesignerForm({ onSubmit, onCancel, initialData }: DesignerFormProps) { +export function DesignerForm({ onSubmit, onCancel, initialData }: DesignerFormProps): React.JSX.Element { const { isModerator } = useUserRole(); const { user } = useAuth(); - const navigate = useNavigate(); const { register, diff --git a/src/components/admin/HeadquartersLocationInput.tsx b/src/components/admin/HeadquartersLocationInput.tsx index 4bf4193c..b93f49d3 100644 --- a/src/components/admin/HeadquartersLocationInput.tsx +++ b/src/components/admin/HeadquartersLocationInput.tsx @@ -29,7 +29,7 @@ export function HeadquartersLocationInput({ onChange, disabled = false, className -}: HeadquartersLocationInputProps) { +}: HeadquartersLocationInputProps): React.JSX.Element { const [mode, setMode] = useState<'search' | 'manual'>('search'); const [searchQuery, setSearchQuery] = useState(''); const [results, setResults] = useState([]); @@ -44,7 +44,7 @@ export function HeadquartersLocationInput({ return; } - const timeoutId = setTimeout(async () => { + const timeoutId = setTimeout(async (): Promise => { setIsSearching(true); try { const response = await fetch( @@ -59,7 +59,7 @@ export function HeadquartersLocationInput({ ); if (response.ok) { - const data = await response.json(); + const data = await response.json() as LocationResult[]; setResults(data); setShowResults(true); } @@ -87,7 +87,7 @@ export function HeadquartersLocationInput({ return result.display_name; }; - const handleSelectLocation = (result: LocationResult) => { + const handleSelectLocation = (result: LocationResult): void => { const formatted = formatLocation(result); onChange(formatted); setSearchQuery(''); @@ -95,7 +95,7 @@ export function HeadquartersLocationInput({ setResults([]); }; - const handleClear = () => { + const handleClear = (): void => { onChange(''); setSearchQuery(''); setResults([]); diff --git a/src/components/admin/LocationSearch.tsx b/src/components/admin/LocationSearch.tsx index c6afb2e4..c13a3652 100644 --- a/src/components/admin/LocationSearch.tsx +++ b/src/components/admin/LocationSearch.tsx @@ -41,7 +41,7 @@ interface LocationSearchProps { className?: string; } -export function LocationSearch({ onLocationSelect, initialLocationId, className }: LocationSearchProps) { +export function LocationSearch({ onLocationSelect, initialLocationId, className }: LocationSearchProps): React.JSX.Element { const [searchQuery, setSearchQuery] = useState(''); const [results, setResults] = useState([]); const [isSearching, setIsSearching] = useState(false); @@ -54,11 +54,11 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className // Load initial location if editing useEffect(() => { if (initialLocationId) { - loadInitialLocation(initialLocationId); + void loadInitialLocation(initialLocationId); } }, [initialLocationId]); - const loadInitialLocation = async (locationId: string) => { + const loadInitialLocation = async (locationId: string): Promise => { const { data, error } = await supabase .from('locations') .select('id, name, city, state_province, country, postal_code, latitude, longitude, timezone') @@ -119,11 +119,11 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className return; } - const data = await response.json(); + const data = await response.json() as LocationResult[]; setResults(data); setShowResults(true); setSearchError(null); - } catch (error: unknown) { + } catch { logger.error('Location search failed', { query: searchQuery }); setSearchError('Failed to search locations. Please check your connection.'); setResults([]); @@ -135,14 +135,15 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className useEffect(() => { if (debouncedSearch) { - searchLocations(debouncedSearch); + void searchLocations(debouncedSearch); } else { setResults([]); setShowResults(false); } - }, [debouncedSearch, searchLocations]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedSearch]); - const handleSelectResult = async (result: LocationResult) => { + const handleSelectResult = (result: LocationResult): void => { const latitude = parseFloat(result.lat); const longitude = parseFloat(result.lon); @@ -176,7 +177,7 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className onLocationSelect(locationData); }; - const handleClear = () => { + const handleClear = (): void => { setSelectedLocation(null); setSearchQuery(''); setResults([]); @@ -214,7 +215,7 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className