kreativortex/app/[locale]/(app)/dashboard/videos/page.tsx
Jessica Rekcah 3a14660c6d update
2025-12-06 10:05:58 +07:00

139 lines
3.9 KiB
TypeScript

/**
* File: page.tsx
* Created by: AI Assistant
* Date: 2025-11-29
* Purpose: Video list page for kreatiVortex platform
* Part of: kreatiVortex - Platform Pembelajaran Tari Online
*/
'use client';
import { Link } from '@/i18n/routing';
import ActionButton from '@/components/ActionButton';
import VideoCard from '@/components/VideoCard';
import { useFetch } from '@/hooks/useFetch';
import { useTranslations } from 'next-intl';
import { Video } from 'lucide-react';
import { useState, useEffect } from 'react';
import { canUploadVideos } from '@/lib/admin';
interface VideoData extends Record<string, unknown> {
id: string;
title: string;
description: string;
videoType: 'YOUTUBE' | 'LOCAL';
videoUrl: string;
viewCount: number;
createdAt: string;
isPublic: boolean;
uploaderId: string;
uploader: {
user: {
name: string;
};
};
}
export default function VideosPage() {
const t = useTranslations('Videos');
const { data: videos, loading, refetch } = useFetch<VideoData[]>('/api/videos');
const [userProfile, setUserProfile] = useState<any>(null);
useEffect(() => {
// Fetch user profile to check permissions
const fetchProfile = async () => {
try {
const response = await fetch('/api/user/profile', {
credentials: 'include'
});
if (response.ok) {
const data = await response.json();
setUserProfile(data.data);
}
} catch (error) {
console.error('Error fetching user profile:', error);
}
};
fetchProfile();
}, []);
const handleDelete = async (videoId: string) => {
if (!confirm(t('confirmDelete'))) {
return;
}
try {
const response = await fetch(`/api/videos/${videoId}`, {
method: 'DELETE',
credentials: 'include'
});
if (response.ok) {
// Refresh videos list using refetch instead of window.reload
await refetch();
} else {
alert(t('errorOccurred'));
}
} catch (error) {
console.error('Error deleting video:', error);
alert(t('errorOccurred'));
}
};
return (
<div className="space-y-6">
{/* Header */}
<div className="flex justify-between items-center">
<div>
<h1 className="text-2xl font-bold text-white">{t('title')}</h1>
<p className="text-gray-400">{t('subtitle')}</p>
</div>
{canUploadVideos(userProfile) && (
<Link href="/dashboard/videos/new">
<ActionButton>
{t('uploadButton')}
</ActionButton>
</Link>
)}
</div>
{/* Loading State */}
{loading ? (
<div className="text-center text-gray-400 py-12">
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-gold-400"></div>
<p className="mt-4">{t('loading')}</p>
</div>
) : videos && videos.length > 0 ? (
/* Video Grid */
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 sm:gap-6">
{videos.map((video) => (
<VideoCard
key={video.id}
video={video}
userProfile={userProfile}
onDelete={handleDelete}
/>
))}
</div>
) : (
/* Empty State */
<div className="text-center py-12">
<div className="text-gray-400 mb-4">
<Video className="w-16 h-16 mx-auto mb-4 text-gray-500" />
<h3 className="text-xl font-semibold text-white mb-2">{t('noVideos')}</h3>
<p className="text-gray-400 mb-6">{t('noVideosDesc')}</p>
{canUploadVideos(userProfile) && (
<Link href="/dashboard/videos/new">
<ActionButton>
{t('uploadFirst')}
</ActionButton>
</Link>
)}
</div>
</div>
)}
</div>
);
}