kreativortex/app/[locale]/(app)/dashboard/videos/[id]/page.tsx
Jessica Rekcah 4253483f44 jalan
2025-12-02 00:22:34 +07:00

193 lines
6.6 KiB
TypeScript

/**
* File: page.tsx
* Created by: AI Assistant
* Date: 2025-11-29
* Purpose: Video player page for kreatiVortex platform
* Part of: kreatiVortex - Platform Pembelajaran Tari Online
*/
'use client';
import { useState } from 'react';
import Link from 'next/link';
import { useParams } from 'next/navigation';
import ActionButton from '@/components/ActionButton';
import { useFetch } from '@/hooks/useFetch';
import { getYouTubeId } from '@/lib/utils';
interface VideoDetail {
id: string;
title: string;
description: string;
videoUrl: string;
viewCount: number;
createdAt: string;
uploader: {
user: {
name: string;
};
};
comments: Comment[];
}
interface Comment {
id: string;
content: string;
createdAt: string;
author: {
user: {
name: string;
};
};
}
export default function VideoDetailPage() {
const params = useParams();
const id = params?.id as string;
const { data: video, loading, refetch } = useFetch<VideoDetail>(`/api/videos/${id}`);
const [commentText, setCommentText] = useState('');
const [submittingComment, setSubmittingComment] = useState(false);
const handleSubmitComment = async () => {
if (!commentText.trim()) return;
setSubmittingComment(true);
try {
const response = await fetch('/api/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: commentText,
videoId: id,
}),
});
if (response.ok) {
setCommentText('');
refetch(); // Refresh comments
} else {
console.error('Failed to post comment');
}
} catch (error) {
console.error('Error posting comment:', error);
} finally {
setSubmittingComment(false);
}
};
const youtubeId = video?.videoUrl ? getYouTubeId(video.videoUrl) : null;
const embedUrl = youtubeId ? `https://www.youtube.com/embed/${youtubeId}` : video?.videoUrl;
if (loading) {
return <div className="text-center text-gray-400 py-12">Loading...</div>;
}
if (!video) {
return <div className="text-center text-gray-400 py-12">Video not found</div>;
}
return (
<div className="max-w-4xl mx-auto space-y-6">
<div className="flex justify-between items-center">
<Link href="/dashboard/videos" className="text-gray-400 hover:text-white flex items-center">
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Kembali ke Daftar Video
</Link>
<Link href={`/dashboard/videos/${id}/edit`}>
<ActionButton variant="outline" size="sm">
Edit Video
</ActionButton>
</Link>
</div>
{/* Video Player */}
<div className="aspect-video bg-black rounded-xl overflow-hidden border border-white/10 shadow-2xl">
{youtubeId ? (
<iframe
src={embedUrl}
title={video.title}
className="w-full h-full"
allowFullScreen
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
></iframe>
) : (
<div className="flex items-center justify-center h-full text-gray-500">
Video format not supported or invalid URL
</div>
)}
</div>
{/* Video Info */}
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-6 border border-white/20">
<div className="flex justify-between items-start mb-4">
<div>
<h1 className="text-2xl font-bold text-white mb-2">{video.title}</h1>
<div className="flex items-center text-sm text-gray-400 space-x-4">
<span>Diunggah oleh <span className="text-gold-400">{video.uploader.user.name}</span></span>
<span></span>
<span>{new Date(video.createdAt).toLocaleDateString()}</span>
<span></span>
<span>{video.viewCount} kali ditonton</span>
</div>
</div>
</div>
<div className="prose prose-invert max-w-none">
<div className="text-gray-300 leading-relaxed" dangerouslySetInnerHTML={{ __html: video.description.replace(/\n/g, '<br/>') }}>
</div>
</div>
</div>
{/* Comments Section */}
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-6 border border-white/20">
<h3 className="text-lg font-semibold text-white mb-4">Komentar</h3>
<div className="space-y-4">
{video.comments?.map((comment) => (
<div key={comment.id} className="flex space-x-4">
<div className="w-10 h-10 bg-gold-400 rounded-full flex items-center justify-center flex-shrink-0">
<span className="text-navy-900 font-bold">{comment.author.user.name.charAt(0)}</span>
</div>
<div className="flex-1">
<div className="bg-white/5 rounded-lg p-3">
<div className="flex justify-between items-start mb-1">
<span className="font-medium text-white">{comment.author.user.name}</span>
<span className="text-xs text-gray-500">{new Date(comment.createdAt).toLocaleDateString()}</span>
</div>
<p className="text-gray-300 text-sm">{comment.content}</p>
</div>
</div>
</div>
))}
{(!video.comments || video.comments.length === 0) && (
<p className="text-gray-400 text-sm">Belum ada komentar.</p>
)}
{/* Comment Form */}
<div className="mt-6 flex space-x-4">
<div className="w-10 h-10 bg-gray-600 rounded-full flex items-center justify-center flex-shrink-0">
<span className="text-white font-bold">ME</span>
</div>
<div className="flex-1">
<textarea
rows={2}
value={commentText}
onChange={(e) => setCommentText(e.target.value)}
className="w-full px-4 py-2 border rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-gold-400 placeholder-gray-500"
placeholder="Tulis komentar..."
></textarea>
<div className="mt-2 flex justify-end">
<ActionButton size="sm" onClick={handleSubmitComment} loading={submittingComment} disabled={!commentText.trim()}>
Kirim
</ActionButton>
</div>
</div>
</div>
</div>
</div>
</div>
);
}