diff --git a/data/mundo/live/c7dkx155e626t.json b/data/mundo/live/c7dkx155e626t.json index 0f3d2dd9080..272e33c5fde 100644 --- a/data/mundo/live/c7dkx155e626t.json +++ b/data/mundo/live/c7dkx155e626t.json @@ -74,7 +74,15 @@ "serviceId": null, "authToken": null, "status": "LIVE", - "warnings": null + "warnings": { + "warning_text": "Contains some upsetting scenes.", + "warning": [ + { + "warning_code": "D1", + "short_description": "Some upsetting scenes" + } + ] + } }, "leadMedia": true } diff --git a/src/app/components/LiveMediaStream/index.styles.tsx b/src/app/components/LiveMediaStream/index.styles.tsx index 530e8c943ea..659b33563b2 100644 --- a/src/app/components/LiveMediaStream/index.styles.tsx +++ b/src/app/components/LiveMediaStream/index.styles.tsx @@ -1,8 +1,7 @@ import { css, Theme } from '@emotion/react'; -import PlayButton from '../MediaLoader/Placeholder/PlayButton'; export default { - liveMediaStreamContainer: ({ palette, spacings, mq }: Theme) => + liveMediaStreamContainer: ({ spacings }: Theme) => css({ // backgroundColor: `${palette.BLACK}`, margin: `0 ${spacings.FULL}rem`, @@ -23,7 +22,7 @@ export default { width: '100%', }, }), - playButtonText: ({ spacings, palette, mq }: Theme) => + playButtonText: ({ palette }: Theme) => css({ color: palette.WHITE, }), @@ -46,8 +45,16 @@ export default { display: 'block', width: '100%', }), - mediaLoaderContainer: ({ palette, spacings, mq }: Theme) => + mediaLoaderContainer: ({ palette }: Theme) => css({ backgroundColor: `${palette.POSTBOX}`, }), + showContent: () => + css({ + display: 'unset', + }), + hideContent: () => + css({ + display: 'none', + }), }; diff --git a/src/app/components/LiveMediaStream/index.tsx b/src/app/components/LiveMediaStream/index.tsx index e614bd03573..3e93c00aae5 100644 --- a/src/app/components/LiveMediaStream/index.tsx +++ b/src/app/components/LiveMediaStream/index.tsx @@ -1,9 +1,13 @@ /** @jsx jsx */ +/* @jsxFrag React.Fragment */ import { jsx } from '@emotion/react'; -import { useContext, useState } from 'react'; +import React, { FC, useContext, useEffect, useState } from 'react'; import Text from '#app/components/Text'; import { MediaCollection } from '#app/components/MediaLoader/types'; -import MediaLoader, { BumpLoader } from '#app/components/MediaLoader'; +import MediaLoader, { + BumpLoader, + ManualControlProps, +} from '#app/components/MediaLoader'; import filterForBlockType from '#app/lib/utilities/blockHandlers'; import { ServiceContext } from '#app/contexts/ServiceContext'; import mediaIcons from '#psammead/psammead-assets/src/svgs/mediaIcons'; @@ -34,46 +38,76 @@ const LiveMediaStream = ({ mediaCollection }: Props) => { }, } = mediaItem; - const handleClick = () => { - setShowMedia(!showMedia); - }; + const ManualControls = ({ + mediaControls, + mediaContainer, + }: ManualControlProps) => { + const handleClick = () => { + setShowMedia(previousState => !previousState); + }; - return ( -
- - {short} - {!showMedia && ( + useEffect(() => { + if (showMedia) { + mediaControls?.play(); + } else { + mediaControls?.stop(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [mediaControls, showMedia]); + + return ( + <> +
+ {`${title} - ${networkName}`} + +
- )} - {showMedia && ( -
-
- {`${title} - ${networkName}`} - -
- +
+ {mediaContainer}
- )} + + ); + }; + + return ( +
+ + {short} +
+ +
); }; diff --git a/src/app/components/MediaLoader/configs/liveMedia.ts b/src/app/components/MediaLoader/configs/liveMedia.ts index ca5636dcca7..a5186cea2f8 100644 --- a/src/app/components/MediaLoader/configs/liveMedia.ts +++ b/src/app/components/MediaLoader/configs/liveMedia.ts @@ -33,7 +33,7 @@ export default ({ return { playerConfig: { ...basePlayerConfig, - autoplay: true, + autoplay: false, statsObject: { ...basePlayerConfig.statsObject, episodePID: liveMediaBlock.id, diff --git a/src/app/components/MediaLoader/index.tsx b/src/app/components/MediaLoader/index.tsx index 2e4a92a0548..ca315c0459c 100644 --- a/src/app/components/MediaLoader/index.tsx +++ b/src/app/components/MediaLoader/index.tsx @@ -1,8 +1,14 @@ /** @jsx jsx */ /* @jsxFrag React.Fragment */ - import { jsx } from '@emotion/react'; -import React, { useContext, useEffect, useRef, useState } from 'react'; +import React, { + FC, + ReactHTMLElement, + useContext, + useEffect, + useRef, + useState, +} from 'react'; import { Helmet } from 'react-helmet'; import { RequestContext } from '#contexts/RequestContext'; import { MEDIA_PLAYER_STATUS } from '#app/lib/logger.const'; @@ -16,7 +22,7 @@ import { import filterForBlockType from '#lib/utilities/blockHandlers'; import { PageTypes } from '#app/models/types/global'; import { EventTrackingContext } from '#app/contexts/EventTrackingContext'; -import { BumpType, MediaBlock, PlayerConfig } from './types'; +import { BumpType, MediaBlock, Player, PlayerConfig } from './types'; import Caption from '../Caption'; import nodeLogger from '../../lib/logger.node'; import buildConfig from './utils/buildSettings'; @@ -93,13 +99,24 @@ const AdvertTagLoader = () => { ); }; +export type ManualControlProps = { + mediaControls?: Player; + mediaContainer: ReactHTMLElement; +}; + type MediaContainerProps = { playerConfig: PlayerConfig; showAds: boolean; + ManualControls?: FC; }; -const MediaContainer = ({ playerConfig, showAds }: MediaContainerProps) => { +const MediaContainer = ({ + playerConfig, + showAds, + ManualControls, +}: MediaContainerProps) => { const playerElementRef = useRef(null); + const [mediaControls, setMediaControls] = useState(); useEffect(() => { try { @@ -111,6 +128,7 @@ const MediaContainer = ({ playerConfig, showAds }: MediaContainerProps) => { ); mediaPlayer.load(); + setMediaControls(mediaPlayer); if (showAds) { const adTag = await window.dotcom.ads.getAdTag(); @@ -145,7 +163,7 @@ const MediaContainer = ({ playerConfig, showAds }: MediaContainerProps) => { } }, [playerConfig, showAds]); - return ( + const container = (
{ } /> ); + + return ( + <> + {ManualControls ? ( + + ) : ( + container + )} + + ); }; type Props = { blocks: MediaBlock[]; className?: string; embedded?: boolean; + placeholderOverride?: boolean; + ManualControls?: FC; }; -const MediaLoader = ({ blocks, className, embedded }: Props) => { +const MediaLoader = ({ + blocks, + className, + embedded, + placeholderOverride = true, + ManualControls, +}: Props) => { const { lang, translations } = useContext(ServiceContext); const { pageIdentifier } = useContext(EventTrackingContext); const { enabled: adsEnabled } = useToggle('ads'); @@ -225,7 +264,9 @@ const MediaLoader = ({ blocks, className, embedded }: Props) => { mediaInfo, } = placeholderConfig ?? {}; - const hasPlaceholder = Boolean(showPlaceholder && placeholderSrc); + const hasPlaceholder = Boolean( + placeholderOverride && showPlaceholder && placeholderSrc, + ); const showPortraitTitle = orientation === 'portrait' && !embedded; @@ -274,7 +315,11 @@ const MediaLoader = ({ blocks, className, embedded }: Props) => { onClick={() => setShowPlaceholder(false)} /> ) : ( - + )} )} diff --git a/src/app/components/MediaLoader/types.ts b/src/app/components/MediaLoader/types.ts index af18d67edac..69588e34048 100644 --- a/src/app/components/MediaLoader/types.ts +++ b/src/app/components/MediaLoader/types.ts @@ -114,6 +114,9 @@ export type Player = { parameters: { updatedAdTag: string }, ): void; load: () => void; + play: () => void; + pause: () => void; + stop: () => void; bind: (event: string, callback: () => void) => void; loadPlugin: ( pluginName: { [key: string]: string }, diff --git a/src/app/models/types/translations.ts b/src/app/models/types/translations.ts index 29277854c94..6dd5734a914 100644 --- a/src/app/models/types/translations.ts +++ b/src/app/models/types/translations.ts @@ -173,7 +173,7 @@ export interface Translations { recentEpisodes?: string; podcastExternalLinks?: string; download?: string; - watchNow: string; + watchNow?: string; }; socialEmbed: { caption?: { diff --git a/ws-nextjs-app/pages/[service]/live/[id]/Header/index.tsx b/ws-nextjs-app/pages/[service]/live/[id]/Header/index.tsx index 7057263cf46..5cae4153cbe 100644 --- a/ws-nextjs-app/pages/[service]/live/[id]/Header/index.tsx +++ b/ws-nextjs-app/pages/[service]/live/[id]/Header/index.tsx @@ -3,12 +3,8 @@ import { jsx } from '@emotion/react'; import Heading from '#app/components/Heading'; import Text from '#app/components/Text'; import MaskedImage from '#app/components/MaskedImage'; -import MediaLoader, { BumpLoader } from '#app/components/MediaLoader'; -import { MediaBlock, MediaCollection } from '#app/components/MediaLoader/types'; -import { useContext, useState } from 'react'; -import mediaIcons from '#psammead/psammead-assets/src/svgs/mediaIcons'; -import Helmet from 'react-helmet'; -import { ServiceContext } from '#app/contexts/ServiceContext'; +import { MediaCollection } from '#app/components/MediaLoader/types'; +import LiveMediaStream from '#app/components/LiveMediaStream'; import LiveLabelHeader from './LiveLabelHeader'; import styles from './styles'; @@ -29,7 +25,6 @@ const Header = ({ imageWidth?: number; mediaCollections?: MediaCollection[] | null; }) => { - const { translations } = useContext(ServiceContext); const isHeaderImage = !!imageUrl && !!imageUrlTemplate && !!imageWidth; const Title = ( @@ -40,20 +35,8 @@ const Header = ({ ); - const [showMedia, setShowMedia] = useState(false); - - const handleClick = () => { - setShowMedia(!showMedia); - }; - return (
- -