import { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { Play, Plus } from 'lucide-react' import { Breadcrumbs } from '../components/Breadcrumbs' import { ListEmptyState } from '../components/EmptyState' import { PageTitle } from '../components/PageTitle' import { VideoCard } from '../components/VideoCard' import { VideoCommentsModal } from '../components/VideoCommentsModal' import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal' import { Pagination } from '../components/Pagination' import { useToast } from '../context/ToastContext' import { useT } from '../i18n/useT' import { useLocale } from '@meshkee/dashboard-ui' import { ApiError } from '../lib/api' import { VIDEOS_PER_PAGE, deleteVideo, listVideos, resolveVideoTitle, } from '../services/videoService' import type { Video } from '../types/video' import pageStyles from '../components/PageContent.module.css' import styles from './BlogPage.module.css' export function VideoListPage() { const navigate = useNavigate() const { showToast } = useToast() const t = useT() const { locale } = useLocale() const [videos, setVideos] = useState([]) const [totalVideos, setTotalVideos] = useState(0) const [currentPage, setCurrentPage] = useState(1) const [isLoading, setIsLoading] = useState(true) const [isDeleting, setIsDeleting] = useState(false) const [error, setError] = useState('') const [commentCounts, setCommentCounts] = useState>({}) const [deleteTarget, setDeleteTarget] = useState<{ id: string; title: string } | null>(null) const [commentsTarget, setCommentsTarget] = useState<{ id: string; title: string } | null>(null) const totalPages = Math.max(1, Math.ceil(totalVideos / VIDEOS_PER_PAGE)) useEffect(() => { const controller = new AbortController() void loadVideos(currentPage, controller.signal) return () => controller.abort() }, [currentPage]) async function loadVideos(page: number, signal?: AbortSignal) { setIsLoading(true) setError('') try { const data = await listVideos(page, VIDEOS_PER_PAGE, signal) setVideos(data.items) setTotalVideos(data.total) setCommentCounts( Object.fromEntries(data.items.map((video) => [video.id, video.commentCount ?? 0])), ) } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') return if (err instanceof ApiError) { setError(err.message) } else { setError(t('video.list.errorLoad')) } } finally { setIsLoading(false) } } function handleEdit(id: string) { navigate(`/videos/edit/${id}`) } function handleComments(id: string) { const video = videos.find((item) => item.id === id) if (video) { setCommentsTarget({ id, title: resolveVideoTitle(video, locale === 'fa' ? 'fa' : 'en'), }) } } function handleRemoveRequest(id: string) { const video = videos.find((item) => item.id === id) if (video) { setDeleteTarget({ id, title: resolveVideoTitle(video, locale === 'fa' ? 'fa' : 'en'), }) } } async function confirmDelete() { if (!deleteTarget) return setIsDeleting(true) setError('') try { await deleteVideo(deleteTarget.id) showToast(t('video.list.toast.removed'), 'success') const nextTotal = totalVideos - 1 const nextTotalPages = Math.max(1, Math.ceil(nextTotal / VIDEOS_PER_PAGE)) const nextPage = currentPage > nextTotalPages ? nextTotalPages : currentPage setDeleteTarget(null) setCurrentPage(nextPage) await loadVideos(nextPage) } catch (err) { if (err instanceof ApiError) { setError(err.message) } else { setError(t('video.list.errorDelete')) } } finally { setIsDeleting(false) } } function handlePageChange(page: number) { setCurrentPage(page) window.scrollTo({ top: 0, behavior: 'smooth' }) } function handleCommentCountChange(count: number) { if (!commentsTarget) return setCommentCounts((prev) => ({ ...prev, [commentsTarget.id]: count, })) } return (
{t('title.myVideos')}

{t('video.list.subtitle', { count: totalVideos })}

{error && (
{error}
)} {isLoading ? (

{t('video.list.loading')}

) : videos.length === 0 ? ( ) : ( <>
{videos.map((video) => ( ))}
)} !isDeleting && setDeleteTarget(null)} /> {commentsTarget && ( setCommentsTarget(null)} onCountChange={handleCommentCountChange} /> )}
) }