Spaces:
Running
Running
import React, { useState, useEffect } from 'react'; | |
import PageHeader from '../components/PageHeader'; | |
import ContentGrid, { ContentItem } from '../components/ContentGrid'; | |
import { Button } from '@/components/ui/button'; | |
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; | |
import { useToast } from '@/hooks/use-toast'; | |
import { Trash2, DownloadCloud, Upload } from 'lucide-react'; | |
import { getAllFromMyList } from '../lib/storage'; | |
interface WatchHistoryItem { | |
type: 'movie' | 'tvshow'; | |
title: string; | |
lastWatched: string; | |
progress: number; | |
completed: boolean; | |
} | |
const ProfilePage = () => { | |
const [watchHistory, setWatchHistory] = useState<WatchHistoryItem[]>([]); | |
const [myListItems, setMyListItems] = useState<ContentItem[]>([]); | |
const [activeTab, setActiveTab] = useState('history'); | |
const { toast } = useToast(); | |
// Load watch history from localStorage | |
useEffect(() => { | |
const loadWatchHistory = () => { | |
try { | |
const history: WatchHistoryItem[] = []; | |
// Scan localStorage for movie progress | |
for (let i = 0; i < localStorage.length; i++) { | |
const key = localStorage.key(i); | |
if (key?.startsWith('movie-progress-')) { | |
const title = key.replace('movie-progress-', ''); | |
const data = JSON.parse(localStorage.getItem(key) || '{}'); | |
if (data && data.lastPlayed) { | |
history.push({ | |
type: 'movie', | |
title, | |
lastWatched: data.lastPlayed, | |
progress: Math.round((data.currentTime / data.duration) * 100) || 0, | |
completed: data.completed || false | |
}); | |
} | |
} | |
// Scan for TV show progress | |
if (key?.startsWith('playback-')) { | |
const showTitle = key.replace('playback-', ''); | |
const showData = JSON.parse(localStorage.getItem(key) || '{}'); | |
let lastEpisodeDate = ''; | |
let lastEpisodeProgress = 0; | |
let anyEpisodeCompleted = false; | |
// Find the most recently watched episode | |
Object.entries(showData).forEach(([_, value]) => { | |
const episodeData = value as { | |
lastPlayed: string; | |
currentTime: number; | |
duration: number; | |
completed: boolean; | |
}; | |
if (!lastEpisodeDate || new Date(episodeData.lastPlayed) > new Date(lastEpisodeDate)) { | |
lastEpisodeDate = episodeData.lastPlayed; | |
lastEpisodeProgress = Math.round((episodeData.currentTime / episodeData.duration) * 100) || 0; | |
if (episodeData.completed) anyEpisodeCompleted = true; | |
} | |
}); | |
if (lastEpisodeDate) { | |
history.push({ | |
type: 'tvshow', | |
title: showTitle, | |
lastWatched: lastEpisodeDate, | |
progress: lastEpisodeProgress, | |
completed: anyEpisodeCompleted | |
}); | |
} | |
} | |
} | |
// Sort by most recently watched | |
history.sort((a, b) => | |
new Date(b.lastWatched).getTime() - new Date(a.lastWatched).getTime() | |
); | |
setWatchHistory(history); | |
} catch (error) { | |
console.error('Error loading watch history:', error); | |
} | |
}; | |
loadWatchHistory(); | |
}, []); | |
// Load My List items | |
useEffect(() => { | |
const loadMyList = async () => { | |
try { | |
const items = await getAllFromMyList(); | |
const contentItems: ContentItem[] = items.map(item => ({ | |
type: item.type, | |
title: item.title, | |
image: undefined // ContentCard component will fetch the image | |
})); | |
setMyListItems(contentItems); | |
} catch (error) { | |
console.error('Error loading my list:', error); | |
} | |
}; | |
loadMyList(); | |
}, []); | |
const clearWatchHistory = () => { | |
// Filter localStorage keys related to watch history | |
const keysToRemove: string[] = []; | |
for (let i = 0; i < localStorage.length; i++) { | |
const key = localStorage.key(i); | |
if (key && (key.startsWith('movie-progress-') || key.startsWith('playback-'))) { | |
keysToRemove.push(key); | |
} | |
} | |
// Remove the keys | |
keysToRemove.forEach(key => localStorage.removeItem(key)); | |
// Update state | |
setWatchHistory([]); | |
toast({ | |
title: "Watch History Cleared", | |
description: "Your watch history has been successfully cleared.", | |
}); | |
}; | |
const exportUserData = () => { | |
try { | |
const userData = { | |
watchHistory: {}, | |
myList: {} | |
}; | |
// Export all localStorage data | |
for (let i = 0; i < localStorage.length; i++) { | |
const key = localStorage.key(i); | |
if (!key) continue; | |
if (key.startsWith('movie-progress-') || key.startsWith('playback-')) { | |
userData.watchHistory[key] = JSON.parse(localStorage.getItem(key) || '{}'); | |
} | |
if (key === 'myList') { | |
userData.myList = JSON.parse(localStorage.getItem(key) || '[]'); | |
} | |
} | |
// Create downloadable JSON | |
const dataStr = JSON.stringify(userData, null, 2); | |
const blob = new Blob([dataStr], { type: 'application/json' }); | |
const url = URL.createObjectURL(blob); | |
// Create temporary link and trigger download | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = `streamflix-user-data-${new Date().toISOString().slice(0, 10)}.json`; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
URL.revokeObjectURL(url); | |
toast({ | |
title: "Export Successful", | |
description: "Your data has been exported successfully.", | |
}); | |
} catch (error) { | |
console.error('Error exporting user data:', error); | |
toast({ | |
title: "Export Failed", | |
description: "There was an error exporting your data.", | |
variant: "destructive" | |
}); | |
} | |
}; | |
const renderWatchHistoryItems = (): ContentItem[] => { | |
return watchHistory.map(item => ({ | |
type: item.type, | |
title: item.title, | |
image: undefined // ContentCard will fetch the image | |
})); | |
}; | |
return ( | |
<div className="container mx-auto px-4 py-8"> | |
<PageHeader title="Your Profile" subtitle="Manage your preferences and data" /> | |
<div className="mt-8"> | |
<Tabs defaultValue={activeTab} onValueChange={setActiveTab}> | |
<TabsList> | |
<TabsTrigger value="history">Watch History</TabsTrigger> | |
<TabsTrigger value="mylist">My List</TabsTrigger> | |
<TabsTrigger value="settings">Settings</TabsTrigger> | |
</TabsList> | |
<TabsContent value="history" className="pt-6"> | |
<div className="flex justify-between items-center mb-6"> | |
<h2 className="text-xl font-bold">Watch History</h2> | |
{watchHistory.length > 0 && ( | |
<Button | |
variant="destructive" | |
onClick={clearWatchHistory} | |
className="flex items-center gap-2" | |
> | |
<Trash2 size={16} /> | |
<span>Clear History</span> | |
</Button> | |
)} | |
</div> | |
{watchHistory.length === 0 ? ( | |
<div className="text-center py-12"> | |
<p className="text-gray-400">You have no watch history yet.</p> | |
<p className="text-sm text-gray-500 mt-2">Start watching movies and shows to build your history.</p> | |
</div> | |
) : ( | |
<ContentGrid items={renderWatchHistoryItems()} /> | |
)} | |
</TabsContent> | |
<TabsContent value="mylist" className="pt-6"> | |
<div className="flex justify-between items-center mb-6"> | |
<h2 className="text-xl font-bold">My List</h2> | |
</div> | |
{myListItems.length === 0 ? ( | |
<div className="text-center py-12"> | |
<p className="text-gray-400">You haven't added anything to your list yet.</p> | |
<p className="text-sm text-gray-500 mt-2">Browse content and click the "+" icon to add titles to your list.</p> | |
</div> | |
) : ( | |
<ContentGrid items={myListItems} /> | |
)} | |
</TabsContent> | |
<TabsContent value="settings" className="pt-6"> | |
<div className="space-y-6"> | |
<div> | |
<h2 className="text-xl font-bold mb-4">Data Management</h2> | |
<div className="grid gap-4 md:grid-cols-2"> | |
<div className="bg-card rounded-lg p-4 border"> | |
<h3 className="text-lg font-medium mb-2">Export Your Data</h3> | |
<p className="text-sm text-gray-400 mb-4">Download your watch history and list data as a JSON file.</p> | |
<Button | |
onClick={exportUserData} | |
className="flex items-center gap-2" | |
> | |
<DownloadCloud size={16} /> | |
<span>Export Data</span> | |
</Button> | |
</div> | |
<div className="bg-card rounded-lg p-4 border"> | |
<h3 className="text-lg font-medium mb-2">Import Your Data</h3> | |
<p className="text-sm text-gray-400 mb-4">Restore previously exported data (coming soon)</p> | |
<Button | |
disabled | |
variant="outline" | |
className="flex items-center gap-2 opacity-50" | |
> | |
<Upload size={16} /> | |
<span>Import Data</span> | |
</Button> | |
</div> | |
</div> | |
</div> | |
<div> | |
<h2 className="text-xl font-bold mb-4">Account Settings</h2> | |
<p className="text-gray-400">Account management features coming soon.</p> | |
</div> | |
</div> | |
</TabsContent> | |
</Tabs> | |
</div> | |
</div> | |
); | |
}; | |
export default ProfilePage; | |