Browse Source

Add video title and channel tracking

drawing-pad
Stephanie Gredell 1 month ago
parent
commit
2febb869fe
  1. 15
      frontend/src/components/VideoPlayer/VideoPlayer.tsx
  2. 16
      frontend/src/pages/VideoApp.tsx
  3. 13
      frontend/src/services/apiClient.ts

15
frontend/src/components/VideoPlayer/VideoPlayer.tsx

@ -1,17 +1,23 @@ @@ -1,17 +1,23 @@
import { useEffect, useRef } from 'react';
import { useTimeLimit } from '../../hooks/useTimeLimit';
import { setCurrentVideo } from '../../services/connectionTracker';
interface VideoPlayerProps {
videoId: string;
videoTitle?: string;
channelName?: string;
onClose: () => void;
}
export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) {
export function VideoPlayer({ videoId, videoTitle, channelName, onClose }: VideoPlayerProps) {
const { limitReached, startTracking, stopTracking, remainingTime } = useTimeLimit();
const iframeRef = useRef<HTMLIFrameElement>(null);
const checkLimitIntervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
// Set video info for connection tracking
setCurrentVideo(videoTitle && channelName ? { title: videoTitle, channelName } : null);
// Prevent body scroll
document.body.style.overflow = 'hidden';
@ -19,6 +25,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) { @@ -19,6 +25,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
stopTracking();
setCurrentVideo(null);
onClose();
}
};
@ -37,10 +44,13 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) { @@ -37,10 +44,13 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) {
iframeRef.current.src = iframeRef.current.src.replace('autoplay=1', 'autoplay=0');
}
stopTracking();
setCurrentVideo(null);
}
}, 1000);
return () => {
// Clear video info when player closes
setCurrentVideo(null);
document.body.style.overflow = 'unset';
window.removeEventListener('keydown', handleEscape);
stopTracking();
@ -48,7 +58,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) { @@ -48,7 +58,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) {
clearInterval(checkLimitIntervalRef.current);
}
};
}, [onClose, limitReached, startTracking, stopTracking]);
}, [videoId, videoTitle, channelName, onClose, limitReached, startTracking, stopTracking]);
// Stop video immediately if limit reached
useEffect(() => {
@ -64,6 +74,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) { @@ -64,6 +74,7 @@ export function VideoPlayer({ videoId, onClose }: VideoPlayerProps) {
const handleClose = () => {
stopTracking();
setCurrentVideo(null);
onClose();
};

16
frontend/src/pages/VideoApp.tsx

@ -7,7 +7,7 @@ import { VideoPlayer } from '../components/VideoPlayer/VideoPlayer'; @@ -7,7 +7,7 @@ import { VideoPlayer } from '../components/VideoPlayer/VideoPlayer';
export function VideoApp() {
const [searchParams] = useSearchParams();
const [selectedVideo, setSelectedVideo] = useState<string | null>(null);
const [selectedVideo, setSelectedVideo] = useState<{ id: string; title: string; channelName: string } | null>(null);
const { limitReached } = useTimeLimit();
// Read from URL query params
@ -37,7 +37,15 @@ export function VideoApp() { @@ -37,7 +37,15 @@ export function VideoApp() {
if (limitReached) {
return; // Don't allow video to open if limit reached
}
setSelectedVideo(videoId);
// Find the video to get title and channel name
const video = videos.find(v => v.id === videoId);
if (video) {
setSelectedVideo({
id: videoId,
title: video.title,
channelName: video.channelName
});
}
};
return (
@ -61,7 +69,9 @@ export function VideoApp() { @@ -61,7 +69,9 @@ export function VideoApp() {
{selectedVideo && (
<VideoPlayer
videoId={selectedVideo}
videoId={selectedVideo.id}
videoTitle={selectedVideo.title}
channelName={selectedVideo.channelName}
onClose={() => setSelectedVideo(null)}
/>
)}

13
frontend/src/services/apiClient.ts

@ -71,7 +71,10 @@ api.interceptors.response.use( @@ -71,7 +71,10 @@ api.interceptors.response.use(
} catch (refreshError) {
processQueue(refreshError, null);
localStorage.removeItem('access_token');
window.location.href = '/login';
// Only redirect if we're not already on login page
if (window.location.pathname !== '/login') {
window.location.href = '/login';
}
return Promise.reject(refreshError);
} finally {
isRefreshing = false;
@ -124,7 +127,11 @@ export const settingsApi = { @@ -124,7 +127,11 @@ export const settingsApi = {
getTimeLimit: () => api.get('/settings/time-limit'),
setTimeLimit: (dailyLimit: number) =>
api.put('/settings/time-limit', { dailyLimit })
api.put('/settings/time-limit', { dailyLimit }),
heartbeat: (sessionId: string, route: string, video?: { title: string; channelName: string }, timeLimit?: { timeUsed: number; dailyLimit: number }) => api.post('/settings/heartbeat', { sessionId, route, videoTitle: video?.title, videoChannel: video?.channelName, timeUsed: timeLimit?.timeUsed, dailyLimit: timeLimit?.dailyLimit }),
getConnectionStats: () => api.get('/settings/connection-stats')
};
// Word Groups API
@ -147,5 +154,3 @@ export const wordGroupsApi = { @@ -147,5 +154,3 @@ export const wordGroupsApi = {
api.delete(`/word-groups/words/${wordId}`)
};

Loading…
Cancel
Save