'use client'; import { useState, useEffect, useRef } from 'react'; import { useAuth } from '@/lib/auth'; import { apiRequest } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Textarea } from '@/components/ui/textarea'; import { Input } from '@/components/ui/input'; // Import Input component import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog'; import { Checkbox } from '@/components/ui/checkbox'; import { Label } from '@/components/ui/label'; import {APPROVE_REASONS, REJECT_REASONS} from '@/lib/reasons'; const VotingPage = () => { const [video, setVideo] = useState(null); const [videoUrl, setVideoUrl] = useState(null); const [message, setMessage] = useState(''); const [error, setError] = useState(''); const [showModal, setShowModal] = useState(false); const [currentDecision, setCurrentDecision] = useState<'approve' | 'reject' | null>(null); const [selectedReasons, setSelectedReasons] = useState([]); const [otherReason, setOtherReason] = useState(''); const [videoTimestamp, setVideoTimestamp] = useState(0); const [recommendedGameInput, setRecommendedGameInput] = useState(''); // State for editable game name const videoRef = useRef(null); const auth = useAuth(); // Effect to fetch video metadata and blob URL useEffect(() => { if (!video) { return; } let objectUrl: string; const fetchVideoBlob = async () => { try { const response = await apiRequest(`/videos/${video.id}/stream`, { token: auth.token, wantsJson: false }); const blob = await response.blob(); objectUrl = URL.createObjectURL(blob); setVideoUrl(objectUrl); } catch (err: any) { setError(`Failed to load video: ${err.message}`); } }; fetchVideoBlob(); // Initialize recommendedGameInput with the current video's game setRecommendedGameInput(video.game || ''); return () => { if (objectUrl) { URL.revokeObjectURL(objectUrl); } }; }, [video, auth.token]); // Effect to handle video time updates useEffect(() => { const videoElement = videoRef.current; if (videoElement) { const handleTimeUpdate = () => { setVideoTimestamp(videoElement.currentTime); }; videoElement.addEventListener('timeupdate', handleTimeUpdate); return () => { videoElement.removeEventListener('timeupdate', handleTimeUpdate); }; } }, [videoUrl]); const fetchNextVideo = async () => { setError(''); setMessage(''); setVideo(null); setVideoUrl(null); setSelectedReasons([]); setOtherReason(''); setCurrentDecision(null); setShowModal(false); setVideoTimestamp(0); setRecommendedGameInput(''); // Reset recommended game input try { const data = await apiRequest('/videos/vote-next', { token: auth.token }); setVideo(data); } catch (err: any) { setError(err.message); } }; const handleVoteButtonClick = (decision: 'approve' | 'reject') => { setCurrentDecision(decision); setSelectedReasons([]); setOtherReason(''); setShowModal(true); }; const handleReasonChange = (reasonOption: string) => { setSelectedReasons(prev => prev.includes(reasonOption) ? prev.filter(r => r !== reasonOption) : [...prev, reasonOption] ); }; const handleSubmitVote = async () => { if (!video || !currentDecision) return; setError(''); setMessage(''); const finalReasons = [...selectedReasons]; if (otherReason.trim()) { finalReasons.push(otherReason.trim()); } // Prepare the body for the API request const body: { decision: string; reason: string[] | string; recommended_game?: string; timestamp: number } = { decision: currentDecision, reason: finalReasons, // Send reasons as an array timestamp: videoTimestamp }; // Add recommended_game only if it has been changed from the original if (recommendedGameInput.trim() !== (video.game || '').trim()) { body.recommended_game = recommendedGameInput.trim(); } try { await apiRequest(`/videos/${video.id}/vote`, { method: 'POST', body, token: auth.token }); setMessage(`Vote '${currentDecision}' submitted successfully!`); setShowModal(false); fetchNextVideo(); } catch (err: any) { setError(err.message); } }; const reasonsToDisplay = currentDecision === 'approve' ? APPROVE_REASONS : REJECT_REASONS; return (
Vote on a Video {!video && (
)} {error &&

{error}

} {message &&

{message}

} {video && videoUrl && (

Person: {video.person}

Game: setRecommendedGameInput(e.target.value)} placeholder="Enter recommended game" className="flex-1 border-none focus:ring-0 focus:outline-none bg-transparent p-0 h-auto text-sm" />

Current Timestamp: {videoTimestamp.toFixed(2)} seconds

)}
{/* Voting Reasons Modal */} Select Reasons for {currentDecision === 'approve' ? 'Approval' : 'Rejection'}
{reasonsToDisplay.map((option) => (
handleReasonChange(option)} className="border-gray-300 text-blue-600 focus:ring-blue-500" />
))}