mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 10:51:13 -05:00
Refactor user lists
This commit is contained in:
154
src/components/lists/ListDisplay.tsx
Normal file
154
src/components/lists/ListDisplay.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { UserTopList, UserTopListItem, Park, Ride, Company } from "@/types/database";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
interface ListDisplayProps {
|
||||
list: UserTopList;
|
||||
}
|
||||
|
||||
interface EnrichedListItem extends UserTopListItem {
|
||||
entity?: Park | Ride | Company;
|
||||
}
|
||||
|
||||
export function ListDisplay({ list }: ListDisplayProps) {
|
||||
const [items, setItems] = useState<EnrichedListItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetchItemsWithEntities();
|
||||
}, [list.id]);
|
||||
|
||||
const fetchItemsWithEntities = async () => {
|
||||
setLoading(true);
|
||||
|
||||
// First, get the list items
|
||||
const { data: itemsData, error: itemsError } = await supabase
|
||||
.from("user_top_list_items")
|
||||
.select("*")
|
||||
.eq("list_id", list.id)
|
||||
.order("position", { ascending: true });
|
||||
|
||||
if (itemsError) {
|
||||
console.error("Error fetching items:", itemsError);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Then, fetch the entities for each item
|
||||
const enrichedItems = await Promise.all(
|
||||
(itemsData as UserTopListItem[]).map(async (item) => {
|
||||
let entity = null;
|
||||
|
||||
if (item.entity_type === "park") {
|
||||
const { data } = await supabase
|
||||
.from("parks")
|
||||
.select("id, name, slug, park_type, location_id")
|
||||
.eq("id", item.entity_id)
|
||||
.single();
|
||||
entity = data;
|
||||
} else if (item.entity_type === "ride") {
|
||||
const { data } = await supabase
|
||||
.from("rides")
|
||||
.select("id, name, slug, category, park_id")
|
||||
.eq("id", item.entity_id)
|
||||
.single();
|
||||
entity = data;
|
||||
} else if (item.entity_type === "company") {
|
||||
const { data } = await supabase
|
||||
.from("companies")
|
||||
.select("id, name, slug, company_type")
|
||||
.eq("id", item.entity_id)
|
||||
.single();
|
||||
entity = data;
|
||||
}
|
||||
|
||||
return { ...item, entity };
|
||||
})
|
||||
);
|
||||
|
||||
setItems(enrichedItems);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const getEntityUrl = (item: EnrichedListItem) => {
|
||||
if (!item.entity) return "#";
|
||||
|
||||
const entity = item.entity as any;
|
||||
|
||||
if (item.entity_type === "park") {
|
||||
return `/parks/${entity.slug}`;
|
||||
} else if (item.entity_type === "ride") {
|
||||
// We need park slug for rides
|
||||
return `/rides/${entity.slug}`;
|
||||
} else if (item.entity_type === "company") {
|
||||
return `/companies/${entity.slug}`;
|
||||
}
|
||||
|
||||
return "#";
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="text-center py-4 text-muted-foreground">Loading...</div>;
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
return (
|
||||
<div className="text-center py-8 text-muted-foreground">
|
||||
This list is empty. Click "Edit" to add items.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ol className="space-y-2">
|
||||
{items.map((item, index) => (
|
||||
<li key={item.id} className="flex items-start gap-3 p-3 rounded-lg hover:bg-muted/50 transition-colors">
|
||||
<span className="font-bold text-lg text-muted-foreground min-w-[2rem]">
|
||||
{index + 1}.
|
||||
</span>
|
||||
<div className="flex-1">
|
||||
{item.entity ? (
|
||||
<Link
|
||||
to={getEntityUrl(item)}
|
||||
className="font-medium hover:underline"
|
||||
>
|
||||
{(item.entity as any).name}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="font-medium text-muted-foreground">
|
||||
[Deleted or unavailable]
|
||||
</span>
|
||||
)}
|
||||
<div className="flex gap-2 mt-1">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{item.entity_type}
|
||||
</Badge>
|
||||
{item.entity && item.entity_type === "park" && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{(item.entity as Park).park_type}
|
||||
</Badge>
|
||||
)}
|
||||
{item.entity && item.entity_type === "ride" && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{(item.entity as Ride).category}
|
||||
</Badge>
|
||||
)}
|
||||
{item.entity && item.entity_type === "company" && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{(item.entity as Company).company_type}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{item.notes && (
|
||||
<p className="text-sm text-muted-foreground mt-2 italic">
|
||||
"{item.notes}"
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user