diff --git a/src/components/CastDetailView.tsx b/src/components/CastDetailView.tsx index 22fb726..e55533a 100644 --- a/src/components/CastDetailView.tsx +++ b/src/components/CastDetailView.tsx @@ -1,9 +1,10 @@ import { Staff, Media } from '@/types'; import { useNavigate } from 'react-router-dom'; import { motion } from 'motion/react'; -import { ArrowLeft, Calendar, MapPin, Briefcase, Film, User, Ruler, Palette, Eye } from 'lucide-react'; +import { ArrowLeft, Calendar, MapPin, Briefcase, Film, User, Ruler, Palette, Eye, ChevronDown, ListFilter } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; +import { useState } from 'react'; interface CastDetailViewProps { person: Staff; @@ -12,10 +13,24 @@ interface CastDetailViewProps { export default function CastDetailView({ person, relatedMedia }: CastDetailViewProps) { const navigate = useNavigate(); + const [sortBy, setSortBy] = useState<'year' | 'title' | 'role'>('role'); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); const handleMediaClick = (mediaId: string) => { navigate(`/media/${mediaId}`); }; + + const sortedFilmography = [...(person.filmography || [])].sort((a, b) => { + let comparison = 0; + if (sortBy === 'year') { + comparison = (a.year || 0) - (b.year || 0); + } else if (sortBy === 'title') { + comparison = (a.title || '').localeCompare(b.title || ''); + } else if (sortBy === 'role') { + comparison = (a.role || '').localeCompare(b.role || ''); + } + return sortOrder === 'asc' ? comparison : -comparison; + }); return (
{/* Hero Section */} @@ -33,7 +48,7 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP ))} + {person.filmography && person.filmography.length > 0 && ( + + {person.filmography.length} Role{person.filmography.length !== 1 ? 's' : ''} + + )}
@@ -279,12 +299,33 @@ export default function CastDetailView({ person, relatedMedia }: CastDetailViewP {person.filmography && person.filmography.length > 0 && (
-

- - Filmography -

+
+

+ + Filmography +

+
+ + +
+
- {person.filmography.map(item => ( + {sortedFilmography.map(item => (
handleMediaClick(item.id.toString())} diff --git a/src/components/CastView.tsx b/src/components/CastView.tsx index 6c1062f..d762aed 100644 --- a/src/components/CastView.tsx +++ b/src/components/CastView.tsx @@ -22,11 +22,11 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag const [searchQuery, setSearchQuery] = useState(() => { return localStorage.getItem('castSearchQuery') || ''; }); - const [sortBy, setSortBy] = useState<'name' | 'role' | 'birthDate' | 'height'>(() => { - return (localStorage.getItem('castSortBy') as 'name' | 'role' | 'birthDate' | 'height') || 'name'; + const [sortBy, setSortBy] = useState<'name' | 'role' | 'birthDate' | 'height' | 'roleCount'>(() => { + return (localStorage.getItem('castSortBy') as 'name' | 'role' | 'birthDate' | 'height' | 'roleCount') || 'roleCount'; }); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>(() => { - return (localStorage.getItem('castSortOrder') as 'asc' | 'desc') || 'asc'; + return (localStorage.getItem('castSortOrder') as 'asc' | 'desc') || 'desc'; }); const [filterOccupation, setFilterOccupation] = useState(() => { return localStorage.getItem('castFilterOccupation') || ''; @@ -68,13 +68,13 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag const handleResetFilters = () => { setSearchQuery(''); - setSortBy('name'); - setSortOrder('asc'); + setSortBy('roleCount'); + setSortOrder('desc'); setFilterOccupation(''); setFilterMediaType(''); }; - const hasActiveFilters = searchQuery || filterOccupation || filterMediaType || sortBy !== 'name' || sortOrder !== 'asc'; + const hasActiveFilters = searchQuery || filterOccupation || filterMediaType || sortBy !== 'roleCount' || sortOrder !== 'desc'; useEffect(() => { const loadCast = async () => { @@ -137,6 +137,10 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag const heightA = a.height || 0; const heightB = b.height || 0; comparison = heightA - heightB; + } else if (sortBy === 'roleCount') { + const roleCountA = a.filmography?.length || 0; + const roleCountB = b.filmography?.length || 0; + comparison = roleCountA - roleCountB; } return sortOrder === 'desc' ? -comparison : comparison; @@ -247,6 +251,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag +
@@ -345,7 +350,7 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag referrerPolicy="no-referrer" />
-
+

{person.name}

@@ -353,6 +358,11 @@ export default function CastView({ onPersonClick, enabledCategories, itemsPerPag {person.role}

+ {person.filmography && person.filmography.length > 0 && ( + + {person.filmography.length} + + )}
{person.filmography && person.filmography.length > 0 && (