mirror of
https://github.com/ceratic/MediaCollectorLibaryFrontend.git
synced 2026-05-13 23:56:45 +02:00
152 lines
5.7 KiB
TypeScript
152 lines
5.7 KiB
TypeScript
import React, { useState, useContext } from 'react'
|
|
import { motion } from 'framer-motion'
|
|
import MovieCard from '../components/MovieCard'
|
|
import { MovieCardSkeleton } from '../components/LoadingSkeleton'
|
|
import { useMovies } from '../hooks/useApi'
|
|
import { ViewContext } from '../components/Layout'
|
|
import { FilmIcon } from '@heroicons/react/24/outline'
|
|
|
|
// Import from components
|
|
import { MediaListView } from '../components/MediaListView'
|
|
import { MediaDetailView } from '../components/MediaDetailView'
|
|
|
|
export default function Movies() {
|
|
const viewContext = useContext(ViewContext)
|
|
const viewMode = viewContext?.viewMode || 'grid'
|
|
const gridColumns = viewContext?.gridColumns || 5
|
|
const coverSize = viewContext?.coverSize || 200
|
|
const PaginationComp = viewContext?.PaginationComponent
|
|
|
|
const getGridClass = (columns: number) => {
|
|
const columnClasses = {
|
|
2: 'grid-cols-1 md:grid-cols-2',
|
|
3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
|
4: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
|
5: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5',
|
|
6: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6',
|
|
7: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-7',
|
|
8: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-8'
|
|
}
|
|
return columnClasses[columns as keyof typeof columnClasses] || columnClasses[5]
|
|
}
|
|
|
|
const [currentPage, setCurrentPage] = useState(1)
|
|
const [pageSize, setPageSize] = useState(24)
|
|
const { data: moviesData, isLoading } = useMovies({
|
|
page: currentPage,
|
|
per_page: pageSize
|
|
})
|
|
|
|
const movies = moviesData?.items || []
|
|
const pagination = moviesData?.pagination
|
|
|
|
// Convert movies to MediaItem format for MediaListView
|
|
const mediaItems = movies.map(movie => ({
|
|
id: movie.id.toString(),
|
|
title: movie.title || 'Untitled Movie',
|
|
type: 'movie' as const,
|
|
coverUrl: movie.poster_url || movie.cover_url || '',
|
|
rating: Number(movie.rating) || 0,
|
|
status: 'completed' as const, // Default status
|
|
releaseYear: movie.release_year || movie.year || new Date().getFullYear(),
|
|
addedAt: movie.created_at || new Date().toISOString(),
|
|
favorite: movie.favorite || false,
|
|
platform: movie.source_name || 'Unknown',
|
|
description: movie.description || '',
|
|
genres: movie.genres || []
|
|
}))
|
|
|
|
// State for MediaListView
|
|
const [selectedId, setSelectedId] = useState<string | null>(null)
|
|
const [multiSelectedIds, setMultiSelectedIds] = useState<Set<string>>(new Set())
|
|
const [detailItem, setDetailItem] = useState<any>(null)
|
|
|
|
const handleSelect = (item: any) => {
|
|
setSelectedId(item.id)
|
|
setDetailItem(item)
|
|
}
|
|
|
|
const handleToggleSelect = (id: string) => {
|
|
const newSelected = new Set(multiSelectedIds)
|
|
if (newSelected.has(id)) {
|
|
newSelected.delete(id)
|
|
} else {
|
|
newSelected.add(id)
|
|
}
|
|
setMultiSelectedIds(newSelected)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="mx-auto">
|
|
{isLoading ? (
|
|
<div className={`grid gap-6 ${getGridClass(gridColumns)}`}>
|
|
{Array.from({ length: pageSize }, (_, i) => (
|
|
<MovieCardSkeleton key={i} />
|
|
))}
|
|
</div>
|
|
) : viewMode === 'list' ? (
|
|
// Use MediaListView for list mode with sideview
|
|
<div className="flex w-full h-full">
|
|
<div className={`${detailItem ? 'w-1/2 hidden md:flex' : 'w-full'} h-full flex flex-col transition-all duration-500`}>
|
|
<div className="h-[600px] border border-slate-200 dark:border-slate-700 rounded-lg overflow-hidden">
|
|
<MediaListView
|
|
items={mediaItems}
|
|
onSelect={handleSelect}
|
|
selectedId={selectedId}
|
|
onToggleSelect={handleToggleSelect}
|
|
multiSelectedIds={multiSelectedIds}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{detailItem && (
|
|
<div className="w-full md:w-1/2 h-full border-l border-white/5 relative overflow-hidden animate-in slide-in-from-right duration-300">
|
|
<MediaDetailView
|
|
item={detailItem}
|
|
allMedia={mediaItems}
|
|
onBack={() => setDetailItem(null)}
|
|
onEdit={(item) => console.log('Edit item:', item)}
|
|
onToggleFavorite={(id, isFav) => console.log('Toggle favorite:', id, isFav)}
|
|
onSelectRelated={(item) => setDetailItem(item)}
|
|
onSelectPerson={(name, id) => console.log('Select person:', name, id)}
|
|
onViewAll={(type, id) => console.log('View all:', type, id)}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
) : (
|
|
// Grid view with MovieCard
|
|
<motion.div
|
|
className={`grid gap-6 ${getGridClass(gridColumns)}`}
|
|
>
|
|
{movies.map((movie, index) => (
|
|
<motion.div
|
|
key={movie.id}
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
transition={{ delay: index * 0.03 }}
|
|
>
|
|
<MovieCard movie={movie} viewMode={viewMode} coverSize={coverSize} />
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
)}
|
|
|
|
{!isLoading && pagination && pagination.last_page > 1 && PaginationComp && (
|
|
<div className="mt-8">
|
|
<PaginationComp
|
|
currentPage={currentPage}
|
|
lastPage={pagination.last_page}
|
|
total={pagination.total}
|
|
onPageChange={setCurrentPage}
|
|
itemsPerPage={pageSize}
|
|
onItemsPerPageChange={setPageSize}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
)
|
|
}
|