import React, { useCallback, useEffect, useRef, useState } from 'react'; import { fetchData } from '../../fetching/Fetch.js'; import { SERVER_URL } from '../../constants.js'; function resolveMediaUrl(mediaUrl) { if (!mediaUrl) return null; return mediaUrl.startsWith('http') ? mediaUrl : `${SERVER_URL}${mediaUrl}`; } export default function AdCarousel({ tenantCode }) { const [ads, setAds] = useState([]); const [index, setIndex] = useState(0); const [error, setError] = useState(null); const timerRef = useRef(null); const videoRef = useRef(null); const clearTimer = useCallback(() => { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } }, []); const loadAds = useCallback(async () => { if (!tenantCode) return; try { const response = await fetchData( `${SERVER_URL}/api/v1/ads/${encodeURIComponent(tenantCode)}/active`, 'GET' ); if (!response.success) { setError('Could not load advertisements.'); return; } const next = Array.isArray(response.data) ? response.data : []; setAds(next); setError(null); setIndex((current) => (next.length === 0 ? 0 : current % next.length)); } catch (err) { console.error(err); setError('Could not load advertisements.'); } }, [tenantCode]); useEffect(() => { loadAds(); const interval = setInterval(loadAds, 60 * 1000); return () => clearInterval(interval); }, [loadAds]); const goNext = useCallback(() => { setIndex((current) => { if (ads.length === 0) return 0; return (current + 1) % ads.length; }); }, [ads.length]); const currentAd = ads[index] ?? null; useEffect(() => { clearTimer(); if (!currentAd) return undefined; if (currentAd.mediaType === 'IMAGE') { const durationMs = Math.max(1, Number(currentAd.durationSeconds) || 10) * 1000; timerRef.current = setTimeout(goNext, durationMs); return clearTimer; } // Videos advance on ended; fallback if play fails timerRef.current = setTimeout(goNext, 5 * 60 * 1000); return clearTimer; }, [currentAd, goNext, clearTimer]); useEffect(() => { const video = videoRef.current; if (!video || currentAd?.mediaType !== 'VIDEO') return undefined; let removeUnmuteListener = () => {}; const onEnded = () => goNext(); const scheduleFallbackAdvance = () => { clearTimer(); const durationMs = Math.max(5, Number(currentAd.durationSeconds) || 15) * 1000; timerRef.current = setTimeout(goNext, durationMs); }; video.addEventListener('ended', onEnded); video.muted = false; video.playsInline = true; const playPromise = video.play(); if (playPromise?.catch) { playPromise.catch(() => { // Unmuted autoplay blocked — keep video playing muted, then unmute on gesture. video.muted = true; const mutedPlay = video.play(); if (mutedPlay?.catch) { mutedPlay.catch(scheduleFallbackAdvance); } const unmute = () => { video.muted = false; video.play()?.catch(() => {}); }; window.addEventListener('pointerdown', unmute, { once: true }); removeUnmuteListener = () => window.removeEventListener('pointerdown', unmute); }); } return () => { video.removeEventListener('ended', onEnded); removeUnmuteListener(); }; }, [currentAd, goNext, clearTimer]); if (error) { return (

Pengiklanan

{error}

); } if (ads.length === 0) { return (

Pengiklanan

Tiada pengiklanan aktif.

); } const src = resolveMediaUrl(currentAd.mediaUrl); return (

Pengiklanan

{currentAd.mediaType === 'VIDEO' ? (
{currentAd.title ? (

{currentAd.title}

) : null}
); }