web / frontend /src /pages /ProfilePage.tsx
Chandima Prabhath
Track bun.lockb with Git LFS
cc2caf9
raw
history blame
10.5 kB
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;