From b388646e65c353b1f8a2df00b9d06c0e2c4c1bc5 Mon Sep 17 00:00:00 2001 From: JSC Date: Thu, 3 Jul 2025 21:50:08 +0200 Subject: [PATCH] feat: enhance ActivityPage with tab navigation for recent activity, user stats, and popular sounds --- src/pages/ActivityPage.tsx | 338 +++++++++++++++++++++++++++++-------- 1 file changed, 267 insertions(+), 71 deletions(-) diff --git a/src/pages/ActivityPage.tsx b/src/pages/ActivityPage.tsx index 5cc9a14..5179ec5 100644 --- a/src/pages/ActivityPage.tsx +++ b/src/pages/ActivityPage.tsx @@ -1,78 +1,274 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { useState, useEffect } from 'react'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Play, Clock, User, TrendingUp } from 'lucide-react'; +import { apiService } from '@/services/api'; + +interface PlayRecord { + id: number; + played_at: string; + user: { + id: number; + name: string; + email: string; + } | null; + sound: { + id: number; + name: string; + filename: string; + type: string; + } | null; +} + +interface UserStats { + total_plays: number; + unique_sounds: number; + favorite_sound: { + sound: any; + play_count: number; + } | null; + first_play: string | null; + last_play: string | null; +} + +interface PopularSound { + sound: any; + play_count: number; + last_played: string | null; +} export function ActivityPage() { + const [recentPlays, setRecentPlays] = useState([]); + const [myStats, setMyStats] = useState(null); + const [popularSounds, setPopularSounds] = useState([]); + const [loading, setLoading] = useState(true); + const [activeTab, setActiveTab] = useState<'recent' | 'mystats' | 'popular'>('recent'); + + useEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + try { + setLoading(true); + await Promise.all([ + fetchRecentPlays(), + fetchMyStats(), + fetchPopularSounds(), + ]); + } catch (err) { + console.error('Error fetching activity data:', err); + } finally { + setLoading(false); + } + }; + + const fetchRecentPlays = async () => { + try { + const response = await apiService.get('/api/soundboard/history?per_page=20'); + const data = await response.json(); + setRecentPlays(data.plays || []); + } catch (err) { + console.error('Error fetching recent plays:', err); + } + }; + + const fetchMyStats = async () => { + try { + const response = await apiService.get('/api/soundboard/my-stats'); + const data = await response.json(); + setMyStats(data); + } catch (err) { + console.error('Error fetching my stats:', err); + } + }; + + const fetchPopularSounds = async () => { + try { + const response = await apiService.get('/api/soundboard/popular?limit=10'); + const data = await response.json(); + setPopularSounds(data.popular_sounds || []); + } catch (err) { + console.error('Error fetching popular sounds:', err); + } + }; + + const formatRelativeTime = (dateString: string) => { + const date = new Date(dateString); + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const minutes = Math.floor(diff / 60000); + const hours = Math.floor(diff / 3600000); + const days = Math.floor(diff / 86400000); + + if (minutes < 1) return 'Just now'; + if (minutes < 60) return `${minutes}m ago`; + if (hours < 24) return `${hours}h ago`; + return `${days}d ago`; + }; + + if (loading) { + return ( +
+
Loading activity...
+
+ ); + } + return (
-
- - - Recent Actions - Your recent activity - - -
-
- Logged in via Google - 2 minutes ago -
-
- Updated profile - 1 hour ago -
-
- Changed settings - 2 hours ago -
-
-
-
- - - - System Events - System-wide activity - - -
-
- New user registered - 15 minutes ago -
-
- Database backup completed - 1 hour ago -
-
- System update applied - 3 hours ago -
-
-
-
- - - - Statistics - Activity overview - - -
-
- Total Sessions - 42 -
-
- This Week - 12 -
-
- Average Duration - 1.5h -
-
-
-
+ {/* Tab Navigation */} +
+ + +
+ + {/* Recent Activity Tab */} + {activeTab === 'recent' && ( + + + + + Recent Activity + + + +
+ {recentPlays.map((play) => ( +
+
+ +
+
+ {play.sound?.name || 'Unknown Sound'} +
+
+ by {play.user?.name || 'Unknown User'} +
+
+
+
+ {formatRelativeTime(play.played_at)} +
+
+ ))} + {recentPlays.length === 0 && ( +
+ No recent activity found. +
+ )} +
+
+
+ )} + + {/* My Statistics Tab */} + {activeTab === 'mystats' && myStats && ( +
+ + + Total Plays + + + +
{myStats.total_plays}
+
+
+ + + + Unique Sounds + + + +
{myStats.unique_sounds}
+
+
+ + {myStats.favorite_sound && ( + + + Favorite Sound + + + +
{myStats.favorite_sound.sound.name}
+
+ {myStats.favorite_sound.play_count} plays +
+
+
+ )} +
+ )} + + {/* Popular Sounds Tab */} + {activeTab === 'popular' && ( + + + + + Popular Sounds + + + +
+ {popularSounds.map((item, index) => ( +
+
+
+ {index + 1} +
+
+
{item.sound.name}
+
+ {item.play_count} plays +
+
+
+ {item.last_played && ( +
+ Last: {formatRelativeTime(item.last_played)} +
+ )} +
+ ))} + {popularSounds.length === 0 && ( +
+ No popular sounds found. +
+ )} +
+
+
+ )}
- ) + ); } \ No newline at end of file