mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 00:11:13 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
184
src-old/components/lists/ListSearch.tsx
Normal file
184
src-old/components/lists/ListSearch.tsx
Normal file
@@ -0,0 +1,184 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { supabase } from "@/lib/supabaseClient";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Search, Plus, X } from "lucide-react";
|
||||
import { useDebounce } from "@/hooks/useDebounce";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface ListSearchProps {
|
||||
listType: string;
|
||||
onSelect: (entityType: string, entityId: string, entityName: string) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface SearchResult {
|
||||
id: string;
|
||||
name: string;
|
||||
type: "park" | "ride" | "company";
|
||||
subtitle?: string;
|
||||
}
|
||||
|
||||
export function ListSearch({ listType, onSelect, onClose }: ListSearchProps) {
|
||||
const [query, setQuery] = useState("");
|
||||
const [results, setResults] = useState<SearchResult[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const debouncedQuery = useDebounce(query, 300);
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedQuery.length >= 2) {
|
||||
searchEntities();
|
||||
} else {
|
||||
setResults([]);
|
||||
}
|
||||
}, [debouncedQuery, listType]);
|
||||
|
||||
const searchEntities = async () => {
|
||||
setLoading(true);
|
||||
const searchResults: SearchResult[] = [];
|
||||
|
||||
// Determine which entity types to search based on list type
|
||||
const shouldSearchParks = listType === "parks" || listType === "mixed";
|
||||
const shouldSearchRides = listType === "rides" || listType === "coasters" || listType === "mixed";
|
||||
const shouldSearchCompanies = listType === "companies" || listType === "mixed";
|
||||
|
||||
// Search parks
|
||||
if (shouldSearchParks) {
|
||||
const { data: parks } = await supabase
|
||||
.from("parks")
|
||||
.select("id, name, park_type, location_id")
|
||||
.ilike("name", `%${debouncedQuery}%`)
|
||||
.limit(10);
|
||||
|
||||
if (parks) {
|
||||
searchResults.push(
|
||||
...parks.map((park) => ({
|
||||
id: park.id,
|
||||
name: park.name,
|
||||
type: "park" as const,
|
||||
subtitle: park.park_type,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Search rides
|
||||
if (shouldSearchRides) {
|
||||
const { data: rides } = await supabase
|
||||
.from("rides")
|
||||
.select("id, name, category, park:parks(name)")
|
||||
.ilike("name", `%${debouncedQuery}%`)
|
||||
.limit(10);
|
||||
|
||||
if (rides) {
|
||||
interface RideSearchResult {
|
||||
id: string;
|
||||
name: string;
|
||||
park?: { name: string } | null;
|
||||
category?: string | null;
|
||||
}
|
||||
|
||||
searchResults.push(
|
||||
...rides.map((ride: RideSearchResult) => ({
|
||||
id: ride.id,
|
||||
name: ride.name,
|
||||
type: "ride" as const,
|
||||
subtitle: ride.park?.name || ride.category || 'Unknown',
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Search companies
|
||||
if (shouldSearchCompanies) {
|
||||
const { data: companies } = await supabase
|
||||
.from("companies")
|
||||
.select("id, name, company_type")
|
||||
.ilike("name", `%${debouncedQuery}%`)
|
||||
.limit(10);
|
||||
|
||||
if (companies) {
|
||||
searchResults.push(
|
||||
...companies.map((company) => ({
|
||||
id: company.id,
|
||||
name: company.name,
|
||||
type: "company" as const,
|
||||
subtitle: company.company_type,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setResults(searchResults);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg p-4 bg-card space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Search for parks, rides, or companies..."
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
<Button variant="ghost" size="icon" onClick={onClose}>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div className="text-center py-4 text-muted-foreground">
|
||||
Searching...
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && results.length === 0 && debouncedQuery.length >= 2 && (
|
||||
<div className="text-center py-4 text-muted-foreground">
|
||||
No results found. Try a different search term.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && results.length > 0 && (
|
||||
<div className="space-y-2 max-h-64 overflow-y-auto">
|
||||
{results.map((result) => (
|
||||
<div
|
||||
key={`${result.type}-${result.id}`}
|
||||
className="flex items-center justify-between p-2 rounded hover:bg-muted transition-colors"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium">{result.name}</p>
|
||||
<div className="flex gap-2 mt-1">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{result.type}
|
||||
</Badge>
|
||||
{result.subtitle && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{result.subtitle}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => onSelect(result.type, result.id, result.name)}
|
||||
>
|
||||
<Plus className="h-4 w-4 mr-1" />
|
||||
Add
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{debouncedQuery.length < 2 && (
|
||||
<div className="text-center py-4 text-muted-foreground text-sm">
|
||||
Type at least 2 characters to search
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user