import React, { useEffect } from 'react'; import { IPrebidAuctionEndEventData, IPrebidAdUnit, IPrebidBidWonEventData, IPrebidAdRenderSucceededEventData, IPrebidDetails, } from '../../../../inject/scripts/prebid'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import BidderStackComponent from './BidderStackComponent'; import BidChipComponent from './BidChipComponent'; import AdUnitChipComponent from './AdUnitChipComponent'; import MediaTypesComponent from './MediaTypesComponent'; import Grid from '@mui/material/Grid'; import Paper from '@mui/material/Paper'; import { useTheme } from '@mui/material'; const AdUnitCard = ({ adUnit, events }: { adUnit: IPrebidAdUnit; events: IPrebidDetails['events'] }): JSX.Element => { const [latestAuctionsWinningBids, setLatestAuctionsWinningBids] = React.useState<IPrebidBidWonEventData[]>([]); const [latestAuctionsBidsReceived, setLatestAuctionBidsReceived] = React.useState<IPrebidBidWonEventData[]>([]); const [latestAuctionsAdsRendered, setLatestAuctionsAdsRendered] = React.useState<IPrebidAdRenderSucceededEventData[]>([]); useEffect(() => { const auctionEndEvents = ((events || []) as IPrebidAuctionEndEventData[]) .filter((event) => event.eventType === 'auctionInit' || event.eventType === 'auctionEnd') .sort((a, b) => a.args.timestamp - b.args.timestamp); const latestAuctionId = auctionEndEvents[0]?.args.auctionId; const latestAuctionsWinningBids = ((events || []) as IPrebidBidWonEventData[]).filter( (event) => event.eventType === 'bidWon' && event.args.auctionId === latestAuctionId ); const latestAuctionsBidsReceived = ((events || []) as IPrebidBidWonEventData[]).filter( (event) => event.eventType === 'bidResponse' && event.args.auctionId === latestAuctionId ); const latestAuctionsAdsRendered = ((events || []) as IPrebidAdRenderSucceededEventData[]).filter( (event) => event.eventType === 'adRenderSucceeded' && event.args.bid.auctionId === latestAuctionId ); setLatestAuctionsWinningBids(latestAuctionsWinningBids); setLatestAuctionBidsReceived(latestAuctionsBidsReceived); setLatestAuctionsAdsRendered(latestAuctionsAdsRendered); }, [events]); return ( <Card sx={{ m: 1 }} variant="outlined"> <CardContent> <Typography variant="h3" sx={{ pt: 1 }}> Code: <Typography variant="body2" component="span"> {adUnit.code} </Typography> </Typography> <Typography variant="h3" sx={{ pt: 1 }}> Media Types: </Typography> <MediaTypesComponent mediaTypes={adUnit.mediaTypes} /> <Typography variant="h3" sx={{ pt: 1 }}> Bidders: </Typography> <BidderStackComponent adUnit={adUnit} latestAuctionsBidsReceived={latestAuctionsBidsReceived} latestAuctionsWinningBids={latestAuctionsWinningBids} latestAuctionsAdsRendered={latestAuctionsAdsRendered} ></BidderStackComponent> </CardContent> </Card> ); }; const Row = ({ adUnit, events }: { adUnit: IPrebidAdUnit; events: IPrebidDetails['events'] }): JSX.Element => { const [winningBids, setWinningBids] = React.useState<IPrebidBidWonEventData[]>([]); const [bidsReceived, setBidsReceived] = React.useState<IPrebidBidWonEventData[]>([]); const [adsRendered, setAdsRendered] = React.useState<IPrebidAdRenderSucceededEventData[]>([]); const theme = useTheme(); useEffect(() => { setWinningBids(((events || []) as IPrebidBidWonEventData[]).filter((event) => event.eventType === 'bidWon')); setBidsReceived(((events || []) as IPrebidBidWonEventData[]).filter((event) => event.eventType === 'bidResponse')); setAdsRendered(((events || []) as IPrebidAdRenderSucceededEventData[]).filter((event) => event.eventType === 'adRenderSucceeded')); }, [events]); return ( <React.Fragment> <Grid item xs={4} sx={{ [theme.breakpoints.down('sm')]: { display: 'none' } }}> <Paper sx={{ height: '100%' }}> <AdUnitChipComponent adUnit={adUnit} /> </Paper> </Grid> <Grid item xs={4} sx={{ [theme.breakpoints.down('sm')]: { display: 'none' } }}> <Paper sx={{ height: '100%' }}> <MediaTypesComponent mediaTypes={adUnit.mediaTypes} /> </Paper> </Grid> <Grid item xs={4} sx={{ [theme.breakpoints.down('sm')]: { display: 'none' } }}> <Paper sx={{ height: '100%' }}> <Stack direction="row" flexWrap={'wrap'} gap={0.5} sx={{ p: 0.5 }}> {adUnit.bids.map((bid, index) => { const bidReceived = bidsReceived.find( (bidReceived) => bidReceived.args?.adUnitCode === adUnit.code && bidReceived.args.bidder === bid.bidder && adUnit.sizes?.map((size) => `${size[0]}x${size[1]}`).includes(bidReceived?.args?.size) ); const isWinner = winningBids.some( (winningBid) => winningBid.args.adUnitCode === adUnit.code && winningBid.args.bidder === bid.bidder && adUnit.sizes?.map((size) => `${size[0]}x${size[1]}`).includes(bidReceived?.args.size) ); const isRendered = adsRendered.some( (renderedAd) => renderedAd.args.bid.adUnitCode === adUnit.code && renderedAd.args.bid.bidder === bid.bidder ); const label = bidReceived?.args.cpm ? `${bid.bidder} (${bidReceived?.args.cpm.toFixed(2)} ${bidReceived?.args.currency})` : `${bid.bidder}`; return <BidChipComponent input={bid} label={label} key={index} isWinner={isWinner} bidReceived={bidReceived} isRendered={isRendered} />; })} </Stack> </Paper> </Grid> </React.Fragment> ); }; const SlotsComponent = ({ adUnits, events }: ISlotsComponentProps): JSX.Element => { const theme = useTheme(); return ( <React.Fragment> <Grid item xs={4}> <Paper> <Typography variant="h3" sx={{ p: 0.5, [theme.breakpoints.down('sm')]: { display: 'none' } }}> Code </Typography> </Paper> </Grid> <Grid item xs={4}> <Paper> <Typography variant="h3" sx={{ p: 0.5, [theme.breakpoints.down('sm')]: { display: 'none' } }}> Media Types </Typography> </Paper> </Grid> <Grid item xs={4}> <Paper> <Typography variant="h3" sx={{ p: 0.5, [theme.breakpoints.down('sm')]: { display: 'none' } }}> Bidders </Typography> </Paper> </Grid> {adUnits.map((adUnit, index) => ( <Row events={events} adUnit={adUnit} key={index} /> ))} <Grid item xs={12}> <Stack sx={{ backgroundColor: 'primary.light', [theme.breakpoints.up('sm')]: { display: 'none', }, }} > {adUnits.map((adUnit, index) => ( <AdUnitCard events={events} adUnit={adUnit} key={index} /> ))} </Stack> </Grid> </React.Fragment> ); }; interface ISlotsComponentProps { events: IPrebidDetails['events']; adUnits: IPrebidAdUnit[]; } export default SlotsComponent;