Files
memegoat/frontend/src/components/view-counter.tsx
Mathis HERRIOT 29b1db4aed feat: add ViewCounter enhancements and file upload progress tracking
- Improved `ViewCounter` with visibility-based view increment using `IntersectionObserver` and 50% video progress tracking.
- Added real-time file upload progress updates via Socket.io, including status and percentage feedback.
- Integrated `ViewCounter` dynamically into `ContentCard` and removed redundant instances from static pages.
- Updated backend upload logic to emit progress updates at different stages via the `EventsGateway`.
2026-01-29 14:57:44 +01:00

75 lines
1.9 KiB
TypeScript

"use client";
import { type RefObject, useEffect, useRef } from "react";
import { ContentService } from "@/services/content.service";
interface ViewCounterProps {
contentId: string;
videoRef?: RefObject<HTMLVideoElement | null>;
}
export function ViewCounter({ contentId, videoRef }: ViewCounterProps) {
const hasIncremented = useRef(false);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const increment = () => {
if (!hasIncremented.current) {
ContentService.incrementViews(contentId).catch((err) => {
console.error("Failed to increment views:", err);
});
hasIncremented.current = true;
}
};
// 1. Observer pour la visibilité (IntersectionObserver)
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[0];
if (entry.isIntersecting) {
// Si c'est une image (pas de videoRef), on attend 3 secondes
if (!videoRef) {
const timer = setTimeout(() => {
increment();
}, 3000);
return () => clearTimeout(timer);
}
}
},
{ threshold: 0.5 },
);
if (containerRef.current) {
observer.observe(containerRef.current);
}
// 2. Logique pour la vidéo (> 50%)
let videoElement: HTMLVideoElement | null = null;
const handleTimeUpdate = () => {
if (videoElement && videoElement.duration > 0) {
const progress = videoElement.currentTime / videoElement.duration;
if (progress >= 0.5) {
increment();
videoElement.removeEventListener("timeupdate", handleTimeUpdate);
}
}
};
if (videoRef?.current) {
videoElement = videoRef.current;
videoElement.addEventListener("timeupdate", handleTimeUpdate);
}
return () => {
observer.disconnect();
if (videoElement) {
videoElement.removeEventListener("timeupdate", handleTimeUpdate);
}
};
}, [contentId, videoRef]);
return (
<div ref={containerRef} className="absolute inset-0 pointer-events-none" />
);
}