import { LIVE_ACTIVITIES_SLIDE_INTERVAL_MS } from '@/lib/live-activities' import { cn } from '@/lib/utils' import { useLiveActivitiesOptional } from '@/providers/LiveActivitiesProvider' import { useUserPreferencesOptional } from '@/providers/UserPreferencesProvider' import storage from '@/services/local-storage.service' import { ExternalLink } from 'lucide-react' import { useEffect, useLayoutEffect, useState } from 'react' import { useTranslation } from 'react-i18next' type TPlacement = 'sidebar' | 'mobile' export default function LiveActivitiesStrip({ placement }: { placement: TPlacement }) { const { t } = useTranslation() const userPrefs = useUserPreferencesOptional() const showLiveActivitiesBanner = userPrefs?.showLiveActivitiesBanner ?? storage.getShowLiveActivitiesBanner() const live = useLiveActivitiesOptional() const items = live?.items ?? [] const [reduceMotion, setReduceMotion] = useState(false) useEffect(() => { const mq = window.matchMedia('(prefers-reduced-motion: reduce)') const apply = () => setReduceMotion(mq.matches) apply() mq.addEventListener('change', apply) return () => mq.removeEventListener('change', apply) }, []) const [slide, setSlide] = useState(0) useEffect(() => { setSlide(0) }, [items]) useEffect(() => { if (items.length <= 1 || reduceMotion) return const id = window.setInterval(() => { setSlide((s) => (s + 1) % items.length) }, LIVE_ACTIVITIES_SLIDE_INTERVAL_MS) return () => window.clearInterval(id) }, [items.length, reduceMotion]) useLayoutEffect(() => { if (items.length === 0) return setSlide((s) => Math.min(s, items.length - 1)) }, [items.length]) if (!showLiveActivitiesBanner || items.length === 0) { return null } // `items` can shrink without a new array identity; `slide` may then be out of range until effects run. const displayIndex = Math.min(slide, items.length - 1) const current = items[displayIndex] if (!current) { return null } return (
{current.summary}
) : null} {current.fromFollowedHost ? ({t('liveActivities.fromFollow')}
) : null}