import { useQuery, useQueryClient } from '@tanstack/react-query'; import React, { useState, useEffect, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import HoverRefWrapper from 'soapbox/components/hover-ref-wrapper'; import { Avatar, Card, HStack, Icon, IconButton, Stack, Text } from 'soapbox/components/ui'; import StatusCard from 'soapbox/features/status/components/card'; import { useInstance } from 'soapbox/hooks'; import type { Ad as AdEntity } from 'soapbox/types/soapbox'; interface IAd { ad: AdEntity, } /** Displays an ad in sponsored post format. */ const Ad: React.FC = ({ ad }) => { const queryClient = useQueryClient(); const instance = useInstance(); const timer = useRef(undefined); const infobox = useRef(null); const [showInfo, setShowInfo] = useState(false); // Fetch the impression URL (if any) upon displaying the ad. // Don't fetch it more than once. useQuery(['ads', 'impression', ad.impression], () => { if (ad.impression) { return fetch(ad.impression); } }, { cacheTime: Infinity, staleTime: Infinity }); /** Invalidate query cache for ads. */ const bustCache = (): void => { queryClient.invalidateQueries(['ads']); }; /** Toggle the info box on click. */ const handleInfoButtonClick: React.MouseEventHandler = () => { setShowInfo(!showInfo); }; /** Hide the info box when clicked outside. */ const handleClickOutside = (event: MouseEvent) => { if (event.target && infobox.current && !infobox.current.contains(event.target as any)) { setShowInfo(false); } }; // Hide the info box when clicked outside. // https://stackoverflow.com/a/42234988 useEffect(() => { document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [infobox]); // Wait until the ad expires, then invalidate cache. useEffect(() => { if (ad.expires_at) { const delta = new Date(ad.expires_at).getTime() - (new Date()).getTime(); timer.current = setTimeout(bustCache, delta); } return () => { if (timer.current) { clearTimeout(timer.current); } }; }, [ad.expires_at]); return (
{ad.account ? ( ) : ( )} {ad.account ? ( ) : ( instance.title )} {}} horizontal /> {showInfo && (
{ad.reason ? ( ad.reason ) : ( )}
)}
); }; export default Ad;