Implement pagination for candidates and episodes in ShowDetail component: add Pager component for both lists, update state management for page navigation, and ensure safe page handling during filtering and updates.
This commit is contained in:
@@ -8,6 +8,7 @@ import type { MediaAssetDto } from '@/shared/api/types'
|
||||
import { Badge } from '@/shared/ui/badge'
|
||||
import { Button } from '@/shared/ui/button'
|
||||
import { Input } from '@/shared/ui/input'
|
||||
import { Pager } from '@/shared/ui/pager'
|
||||
import { toast } from '@/shared/ui/toast-store'
|
||||
import { listMedia } from '@/features/admin/media/api'
|
||||
import {
|
||||
@@ -23,12 +24,16 @@ import { addEpisode, getShow, removeEpisode } from './api'
|
||||
|
||||
type Candidate = { asset: MediaAssetDto; parsed: ParsedEpisode }
|
||||
|
||||
const PAGE_SIZE = 20
|
||||
|
||||
export function ShowDetail({ showId }: { showId: string }) {
|
||||
const { t } = useTranslation()
|
||||
const queryClient = useQueryClient()
|
||||
const [filter, setFilter] = useState('')
|
||||
const [deselected, setDeselected] = useState<Set<string>>(new Set())
|
||||
const [adding, setAdding] = useState<{ current: number; total: number } | null>(null)
|
||||
const [candPage, setCandPage] = useState(1)
|
||||
const [epPage, setEpPage] = useState(1)
|
||||
|
||||
const { data: show, isLoading } = useQuery({
|
||||
queryKey: ['admin', 'shows', showId],
|
||||
@@ -84,6 +89,16 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
|
||||
const isSingle = show.kind === 'Single'
|
||||
const canAdd = !isSingle || show.episodes.length === 0
|
||||
|
||||
// Постраничный вывод длинных списков (кандидаты на добавление и сами серии). Страницу зажимаем в
|
||||
// допустимый диапазон — чтобы после удаления/фильтрации не застрять на пустой странице.
|
||||
const candTotalPages = Math.max(1, Math.ceil(candidates.length / PAGE_SIZE))
|
||||
const candPageSafe = Math.min(candPage, candTotalPages)
|
||||
const candItems = candidates.slice((candPageSafe - 1) * PAGE_SIZE, candPageSafe * PAGE_SIZE)
|
||||
const epTotalPages = Math.max(1, Math.ceil(show.episodes.length / PAGE_SIZE))
|
||||
const epPageSafe = Math.min(epPage, epTotalPages)
|
||||
const epOffset = (epPageSafe - 1) * PAGE_SIZE
|
||||
const epItems = show.episodes.slice(epOffset, epOffset + PAGE_SIZE)
|
||||
const toggle = (id: string) =>
|
||||
setDeselected((prev) => {
|
||||
const next = new Set(prev)
|
||||
@@ -151,7 +166,10 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
className="max-w-md"
|
||||
placeholder={t('admin.shows.filterAssets')}
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setCandPage(1)
|
||||
setFilter(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<Button size="sm" variant="outline" onClick={() => setDeselected(new Set())}>
|
||||
{t('admin.shows.selectAll')}
|
||||
@@ -175,7 +193,7 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
<p className="px-4 py-3 text-sm text-muted-foreground">{t('admin.shows.noMatches')}</p>
|
||||
) : (
|
||||
<ul className="divide-y divide-border text-sm">
|
||||
{candidates.map(({ asset, parsed }) => {
|
||||
{candItems.map(({ asset, parsed }) => {
|
||||
const label = formatSeasonEpisode(parsed)
|
||||
return (
|
||||
<li key={asset.id}>
|
||||
@@ -194,6 +212,7 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
<Pager page={candPageSafe} totalPages={candTotalPages} onChange={setCandPage} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -209,7 +228,7 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{show.episodes.map((episode, index) => {
|
||||
{epItems.map((episode, index) => {
|
||||
const parsed =
|
||||
episode.season != null && episode.episode != null
|
||||
? { season: episode.season, episode: episode.episode }
|
||||
@@ -217,7 +236,7 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
const label = formatSeasonEpisode(parsed)
|
||||
return (
|
||||
<tr key={episode.id} className="border-b border-border last:border-0">
|
||||
<td className="px-4 py-2 text-muted-foreground">{index + 1}</td>
|
||||
<td className="px-4 py-2 text-muted-foreground">{epOffset + index + 1}</td>
|
||||
<td className="px-4 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{episode.stillImageId && (
|
||||
@@ -270,6 +289,7 @@ export function ShowDetail({ showId }: { showId: string }) {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<Pager page={epPageSafe} totalPages={epTotalPages} onChange={setEpPage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user