mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 17:31:14 -05:00
Approve database migration
This commit is contained in:
@@ -9,7 +9,9 @@ import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { AddRideCreditDialog } from './AddRideCreditDialog';
|
||||
import { RideCreditCard } from './RideCreditCard';
|
||||
import { SortableRideCreditCard } from './SortableRideCreditCard';
|
||||
import { RideCreditFilters } from './RideCreditFilters';
|
||||
import { UserRideCredit } from '@/types/database';
|
||||
import { useRideCreditFilters } from '@/hooks/useRideCreditFilters';
|
||||
import {
|
||||
DndContext,
|
||||
DragEndEvent,
|
||||
@@ -33,10 +35,18 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
|
||||
const [sortBy, setSortBy] = useState<'date' | 'count' | 'name' | 'custom'>('custom');
|
||||
const [filterCategory, setFilterCategory] = useState<string>('all');
|
||||
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
// Use the filter hook
|
||||
const {
|
||||
filters,
|
||||
updateFilter,
|
||||
clearFilters,
|
||||
filteredCredits,
|
||||
activeFilterCount,
|
||||
} = useRideCreditFilters(credits);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: {
|
||||
@@ -47,25 +57,13 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
|
||||
useEffect(() => {
|
||||
fetchCredits();
|
||||
}, [userId, sortBy, filterCategory]);
|
||||
}, [userId, sortBy]);
|
||||
|
||||
const fetchCredits = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// First, get ride IDs that match the category filter (if any)
|
||||
let rideIdsToFilter: string[] | null = null;
|
||||
if (filterCategory !== 'all') {
|
||||
const { data: filteredRides, error: rideError } = await supabase
|
||||
.from('rides')
|
||||
.select('id')
|
||||
.eq('category', filterCategory);
|
||||
|
||||
if (rideError) throw rideError;
|
||||
rideIdsToFilter = filteredRides.map(r => r.id);
|
||||
}
|
||||
|
||||
// Build main query
|
||||
// Build main query with enhanced data
|
||||
let query = supabase
|
||||
.from('user_ride_credits')
|
||||
.select(`
|
||||
@@ -75,36 +73,46 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
name,
|
||||
slug,
|
||||
category,
|
||||
status,
|
||||
coaster_type,
|
||||
seating_type,
|
||||
intensity_level,
|
||||
max_speed_kmh,
|
||||
max_height_meters,
|
||||
length_meters,
|
||||
inversions,
|
||||
card_image_url,
|
||||
parks:park_id (
|
||||
id,
|
||||
name,
|
||||
slug
|
||||
slug,
|
||||
park_type,
|
||||
locations:location_id (
|
||||
country,
|
||||
state_province,
|
||||
city
|
||||
)
|
||||
),
|
||||
manufacturer:manufacturer_id (
|
||||
id,
|
||||
name
|
||||
),
|
||||
designer:designer_id (
|
||||
id,
|
||||
name
|
||||
)
|
||||
)
|
||||
`)
|
||||
.eq('user_id', userId);
|
||||
|
||||
// Apply ride ID filter if category filter is active
|
||||
if (rideIdsToFilter && rideIdsToFilter.length > 0) {
|
||||
query = query.in('ride_id', rideIdsToFilter);
|
||||
} else if (rideIdsToFilter && rideIdsToFilter.length === 0) {
|
||||
// No rides match the category - return empty
|
||||
setCredits([]);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply sorting - default to sort_order when available
|
||||
if (sortBy === 'date') {
|
||||
query = query.order('first_ride_date', { ascending: false, nullsFirst: false });
|
||||
} else if (sortBy === 'count') {
|
||||
query = query.order('ride_count', { ascending: false });
|
||||
} else if (sortBy === 'name') {
|
||||
// Note: Can't order by joined table - we'll sort client-side
|
||||
query = query.order('created_at', { ascending: false });
|
||||
} else {
|
||||
// Default to custom sort order
|
||||
query = query.order('sort_order', { ascending: true, nullsFirst: false });
|
||||
}
|
||||
|
||||
@@ -206,6 +214,9 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
coasters: credits.filter(c => c.rides?.category === 'roller_coaster').length
|
||||
};
|
||||
|
||||
// Use filtered credits for display
|
||||
const displayCredits = filteredCredits;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
@@ -250,6 +261,21 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<RideCreditFilters
|
||||
filters={filters}
|
||||
onFilterChange={updateFilter}
|
||||
onClearFilters={clearFilters}
|
||||
credits={credits}
|
||||
activeFilterCount={activeFilterCount}
|
||||
resultCount={displayCredits.length}
|
||||
totalCount={credits.length}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="flex flex-wrap gap-4 items-center justify-between">
|
||||
<div className="flex gap-2">
|
||||
@@ -268,19 +294,6 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Select value={filterCategory} onValueChange={setFilterCategory}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Filter by type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Rides</SelectItem>
|
||||
<SelectItem value="roller_coaster">Roller Coasters</SelectItem>
|
||||
<SelectItem value="flat_ride">Flat Rides</SelectItem>
|
||||
<SelectItem value="water_ride">Water Rides</SelectItem>
|
||||
<SelectItem value="dark_ride">Dark Rides</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<Select value={sortBy} onValueChange={(value) => setSortBy(value as typeof sortBy)}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Sort by" />
|
||||
@@ -313,18 +326,32 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
</div>
|
||||
|
||||
{/* Credits Display */}
|
||||
{credits.length === 0 ? (
|
||||
{displayCredits.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="py-12">
|
||||
<div className="text-center">
|
||||
<h3 className="text-xl font-semibold mb-2">No Ride Credits Yet</h3>
|
||||
<p className="text-muted-foreground mb-4">
|
||||
Start tracking your ride experiences
|
||||
</p>
|
||||
<Button onClick={() => setIsAddDialogOpen(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Your First Credit
|
||||
</Button>
|
||||
{credits.length === 0 ? (
|
||||
<>
|
||||
<h3 className="text-xl font-semibold mb-2">No Ride Credits Yet</h3>
|
||||
<p className="text-muted-foreground mb-4">
|
||||
Start tracking your ride experiences
|
||||
</p>
|
||||
<Button onClick={() => setIsAddDialogOpen(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Your First Credit
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h3 className="text-xl font-semibold mb-2">No Results Found</h3>
|
||||
<p className="text-muted-foreground mb-4">
|
||||
Try adjusting your filters
|
||||
</p>
|
||||
<Button onClick={clearFilters} variant="outline">
|
||||
Clear Filters
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -335,19 +362,19 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={credits.map(c => c.id)}
|
||||
items={displayCredits.map(c => c.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<div className={viewMode === 'grid'
|
||||
? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4'
|
||||
: 'space-y-4'
|
||||
}>
|
||||
{credits.map((credit, index) => (
|
||||
{displayCredits.map((credit, index) => (
|
||||
<SortableRideCreditCard
|
||||
key={credit.id}
|
||||
credit={credit}
|
||||
position={index + 1}
|
||||
maxPosition={credits.length}
|
||||
maxPosition={displayCredits.length}
|
||||
viewMode={viewMode}
|
||||
onUpdate={handleCreditUpdated}
|
||||
onDelete={() => handleCreditDeleted(credit.id)}
|
||||
@@ -362,7 +389,7 @@ export function RideCreditsManager({ userId }: RideCreditsManagerProps) {
|
||||
? 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4'
|
||||
: 'space-y-4'
|
||||
}>
|
||||
{credits.map((credit, index) => (
|
||||
{displayCredits.map((credit, index) => (
|
||||
<RideCreditCard
|
||||
key={credit.id}
|
||||
credit={credit}
|
||||
|
||||
Reference in New Issue
Block a user