|
|
| import React, { useState, useEffect } from 'react'; |
| import { useNavigate } from 'react-router-dom'; |
| import PageHeader from '../components/PageHeader'; |
| import ContentGrid, { ContentItem } from '../components/ContentGrid'; |
| import { getAllFromMyList, removeFromMyList } from '../lib/storage'; |
| import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; |
| import { Plus, TrashIcon } from 'lucide-react'; |
| import { useToast } from '@/hooks/use-toast'; |
|
|
| interface MyListItem { |
| type: 'movie' | 'tvshow'; |
| title: string; |
| addedAt: string; |
| } |
|
|
| const MyListPage = () => { |
| const [myListItems, setMyListItems] = useState<MyListItem[]>([]); |
| const [showRemoveButtons, setShowRemoveButtons] = useState(false); |
| const [activeTab, setActiveTab] = useState('all'); |
| const [isLoading, setIsLoading] = useState(true); |
| const navigate = useNavigate(); |
| const { toast } = useToast(); |
|
|
| useEffect(() => { |
| const fetchMyList = async () => { |
| try { |
| setIsLoading(true); |
| const items = await getAllFromMyList(); |
| |
| items.sort((a, b) => new Date(b.addedAt).getTime() - new Date(a.addedAt).getTime()); |
| setMyListItems(items); |
| } catch (error) { |
| console.error("Error loading My List:", error); |
| } finally { |
| setIsLoading(false); |
| } |
| }; |
|
|
| fetchMyList(); |
| }, []); |
|
|
| const handleRemoveItem = async (title: string, type: 'movie' | 'tvshow') => { |
| try { |
| await removeFromMyList(title, type); |
| setMyListItems(prev => prev.filter(item => !(item.title === title && item.type === type))); |
| toast({ |
| title: "Removed from My List", |
| description: `"${title}" has been removed from your list`, |
| }); |
| } catch (error) { |
| console.error("Error removing item from My List:", error); |
| toast({ |
| title: "Error", |
| description: "Failed to remove item from your list", |
| variant: "destructive" |
| }); |
| } |
| }; |
|
|
| const toggleRemoveButtons = () => { |
| setShowRemoveButtons(!showRemoveButtons); |
| }; |
|
|
| const getFilteredItems = (filter: string): ContentItem[] => { |
| let filtered = myListItems; |
| if (filter === 'movies') { |
| filtered = myListItems.filter(item => item.type === 'movie'); |
| } else if (filter === 'tvshows') { |
| filtered = myListItems.filter(item => item.type === 'tvshow'); |
| } |
| |
| |
| return filtered.map(item => ({ |
| type: item.type, |
| title: item.title, |
| image: undefined |
| })); |
| }; |
|
|
| const allItems = getFilteredItems('all'); |
| const movieItems = getFilteredItems('movies'); |
| const tvShowItems = getFilteredItems('tvshows'); |
|
|
| if (isLoading) { |
| return ( |
| <div className="container mx-auto px-4 py-8 animate-pulse"> |
| <div className="h-8 w-1/3 bg-gray-700 rounded mb-8"></div> |
| <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6"> |
| {[...Array(10)].map((_, i) => ( |
| <div key={i} className="h-32 rounded bg-gray-800"></div> |
| ))} |
| </div> |
| </div> |
| ); |
| } |
|
|
| return ( |
| <div className="container mx-auto px-4 py-8"> |
| <div className="flex justify-between items-center mb-6"> |
| <PageHeader |
| title="My List" |
| subtitle={`${myListItems.length} ${myListItems.length === 1 ? 'title' : 'titles'}`} |
| /> |
| |
| <div className="flex gap-4 items-center"> |
| {myListItems.length > 0 && ( |
| <button |
| onClick={toggleRemoveButtons} |
| className="px-4 py-2 rounded-full bg-theme-card hover:bg-theme-card-hover text-sm flex items-center gap-2" |
| > |
| {showRemoveButtons ? 'Done' : ( |
| <> |
| <TrashIcon size={16} /> |
| <span className="hidden sm:inline">Edit List</span> |
| </> |
| )} |
| </button> |
| )} |
| |
| <button |
| onClick={() => navigate('/browse')} |
| className="px-4 py-2 rounded-full bg-theme-primary hover:bg-theme-primary-hover text-white text-sm flex items-center gap-2" |
| > |
| <Plus size={16} /> |
| <span className="hidden sm:inline">Add Titles</span> |
| </button> |
| </div> |
| </div> |
|
|
| {myListItems.length === 0 ? ( |
| <div className="flex flex-col items-center justify-center py-16 text-center"> |
| <div className="text-5xl mb-4">🎬</div> |
| <h3 className="text-xl font-bold mb-2">Your list is empty</h3> |
| <p className="text-gray-400 mb-6">Start adding movies and shows to create your watchlist.</p> |
| <button |
| onClick={() => navigate('/browse')} |
| className="px-6 py-2 rounded bg-theme-primary hover:bg-theme-primary-hover text-white text-sm font-medium" |
| > |
| Browse Content |
| </button> |
| </div> |
| ) : ( |
| <Tabs defaultValue={activeTab} onValueChange={setActiveTab}> |
| <TabsList className="mb-8"> |
| <TabsTrigger value="all">All ({allItems.length})</TabsTrigger> |
| <TabsTrigger value="movies">Movies ({movieItems.length})</TabsTrigger> |
| <TabsTrigger value="tvshows">TV Shows ({tvShowItems.length})</TabsTrigger> |
| </TabsList> |
| |
| <TabsContent value="all"> |
| <ContentGrid items={allItems} emptyMessage="No items in your list" /> |
| </TabsContent> |
| |
| <TabsContent value="movies"> |
| <ContentGrid items={movieItems} emptyMessage="No movies in your list" /> |
| </TabsContent> |
| |
| <TabsContent value="tvshows"> |
| <ContentGrid items={tvShowItems} emptyMessage="No TV shows in your list" /> |
| </TabsContent> |
| </Tabs> |
| )} |
| </div> |
| ); |
| }; |
|
|
| export default MyListPage; |
|
|