From edadb6f0128b794b63dd6fb3519178c34452f919 Mon Sep 17 00:00:00 2001 From: Margarita Date: Wed, 21 Jun 2023 11:44:30 +0300 Subject: [PATCH] feat(in-565): ads on home and match pages --- Makefile | 4 +- package-lock.json | 5 + package.json | 1 + .../Ads/components/AdComponent/hooks.tsx | 156 +++++ .../Ads/components/AdComponent/index.tsx | 85 +++ .../Ads/components/AdComponent/styled.tsx | 109 ++++ .../Ads/components/MobileAd/index.tsx | 71 +++ .../Ads/components/MobileAd/styled.tsx | 112 ++++ .../Ads/helpers/calcMaxDurationAds.tsx | 16 + src/components/Ads/helpers/index.tsx | 1 + src/components/Ads/helpers/isVideo.tsx | 2 + src/components/Ads/hooks.tsx | 65 ++ src/components/Ads/index.tsx | 31 + src/components/Ads/styled.tsx | 16 + src/components/Ads/types.tsx | 57 ++ src/config/index.tsx | 1 + src/config/localStorageKeys.tsx | 1 + src/config/queries.tsx | 1 + src/config/userAgent.tsx | 8 +- .../components/DateFilter/hooks/index.tsx | 19 +- src/features/HomePage/hooks.tsx | 31 +- src/features/HomePage/index.tsx | 18 +- src/features/MatchPage/index.tsx | 36 +- src/features/MatchPage/store/hooks/index.tsx | 12 + .../components/EventsList/index.tsx | 25 +- .../components/MatchPlaylists/index.tsx | 18 +- .../components/TabEvents/index.tsx | 1 + .../components/TabEvents/styled.tsx | 5 +- .../components/TabWatch/index.tsx | 18 +- src/features/MatchSidePlaylists/index.tsx | 26 +- src/features/MatchSidePlaylists/styled.tsx | 15 +- src/features/MatchesGrid/index.tsx | 23 +- src/features/MatchesGrid/styled.tsx | 1 + src/features/StreamPlayer/hooks/index.tsx | 8 + src/features/StreamPlayer/index.tsx | 27 +- src/features/StreamPlayer/styled.tsx | 9 + .../components/TournamentMobile/index.tsx | 43 +- .../components/TournamentMobile/styled.tsx | 7 + .../HighlightsPage/storeHighlightsAtoms.tsx | 7 +- src/requests/getAds/getAds.tsx | 65 ++ src/requests/getAds/index.tsx | 2 + src/requests/getAds/updateAdsView.tsx | 29 + src/requests/index.tsx | 4 + src/utilits/mirage/Mirage.tsx | 31 - src/utilits/mirage/fixtures/getAds.tsx | 592 ++++++++++++++++++ src/utilits/mirage/fixtures/index.tsx | 2 + src/utilits/mirage/models/index.tsx | 8 + src/utilits/mirage/server.ts | 44 ++ 48 files changed, 1797 insertions(+), 71 deletions(-) create mode 100644 src/components/Ads/components/AdComponent/hooks.tsx create mode 100644 src/components/Ads/components/AdComponent/index.tsx create mode 100644 src/components/Ads/components/AdComponent/styled.tsx create mode 100644 src/components/Ads/components/MobileAd/index.tsx create mode 100644 src/components/Ads/components/MobileAd/styled.tsx create mode 100644 src/components/Ads/helpers/calcMaxDurationAds.tsx create mode 100644 src/components/Ads/helpers/index.tsx create mode 100644 src/components/Ads/helpers/isVideo.tsx create mode 100644 src/components/Ads/hooks.tsx create mode 100644 src/components/Ads/index.tsx create mode 100644 src/components/Ads/styled.tsx create mode 100644 src/components/Ads/types.tsx create mode 100644 src/config/localStorageKeys.tsx create mode 100644 src/requests/getAds/getAds.tsx create mode 100644 src/requests/getAds/index.tsx create mode 100644 src/requests/getAds/updateAdsView.tsx delete mode 100644 src/utilits/mirage/Mirage.tsx create mode 100644 src/utilits/mirage/fixtures/getAds.tsx create mode 100644 src/utilits/mirage/fixtures/index.tsx create mode 100644 src/utilits/mirage/models/index.tsx create mode 100644 src/utilits/mirage/server.ts diff --git a/Makefile b/Makefile index ac6e72bc..61a42fb1 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ build-c: clean build-d: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=staging \ - REACT_APP_CLIENT=facr \ + REACT_APP_CLIENT=insports \ REACT_APP_STAGE=test-d \ npm run build @@ -135,7 +135,7 @@ tunisia-build: clean REACT_APP_ENV=staging \ REACT_APP_CLIENT=tunisia \ npm run build - + fqtv-build: clean REACT_APP_TYPE=ott \ REACT_APP_ENV=staging \ diff --git a/package-lock.json b/package-lock.json index a69b3e22..57fa0531 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21000,6 +21000,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "react-ga": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.1.tgz", + "integrity": "sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ==" + }, "react-inspector": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz", diff --git a/package.json b/package.json index 6a0a67bf..7101187a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react": "^17.0.2", "react-datepicker": "^3.1.3", "react-dom": "^17.0.2", + "react-ga": "^3.3.1", "react-query": "^3.39.3", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", diff --git a/src/components/Ads/components/AdComponent/hooks.tsx b/src/components/Ads/components/AdComponent/hooks.tsx new file mode 100644 index 00000000..04386a4d --- /dev/null +++ b/src/components/Ads/components/AdComponent/hooks.tsx @@ -0,0 +1,156 @@ +import { useEffect, useState } from 'react' + +import ReactGA from 'react-ga' + +import { updateAdsView } from 'requests' + +import { useToggle } from 'hooks' + +import { getLocalStorageItem, isMatchPage } from 'helpers' + +import { + device, + COUNTRY, +} from 'config' + +import { useMatchPageStore } from 'features/MatchPage/store' + +import type { AdComponentType } from './index' + +import { checkVideo } from '../../helpers' +import { + adsViews, + EventGA, + ViewsType, +} from '../../types' + +const countryCode = getLocalStorageItem(COUNTRY) + +export const useAd = ({ ad }: AdComponentType) => { + const [isOpenAd, setIsOpenAd] = useState(true) + const [isNeedToShow, setIsNeedToShow] = useState(true) + const [shownTime, setShownTime] = useState(0) + + const { isFullscreen } = useMatchPageStore() + + const views = getLocalStorageItem(adsViews) as ViewsType + const { + duration, + frequency, + id, + media, + name, + time_close, + } = ad + + const { + close, + isOpen: isOpenCloseBtn, + open: showCloseBtn, + } = useToggle() + + const isNeedBanner = Number(views?.HOME) % frequency === 0 + const isVideo = checkVideo(media.url) + const currentAdsTime = duration - shownTime + + useEffect(() => { + if (!isFullscreen) { + if (currentAdsTime === 0) { + setShownTime(0) + } else { + const stopWatch = setInterval(() => { + setShownTime((prev) => prev + 1) + }, 1000) + return () => clearInterval(stopWatch) + } + } + return undefined + }, [ + isFullscreen, + currentAdsTime, + ]) + + const handleClose = async () => { + setIsOpenAd(false) + isMatchPage() && setIsNeedToShow(false) + sendBannerClickEvent(EventGA.CLOSE) + } + + const sendBannerClickEvent = (event: EventGA) => { + ReactGA.initialize('Advertisement') + ReactGA.event({ + action: event, + category: 'Advertisement', + label: `${name}_${countryCode ?? ''}_${device}`, + value: id, + }) + } + + useEffect(() => { + setShownTime(0) + + if (isMatchPage()) { + const interval = setInterval(() => { + setIsNeedToShow(true) + setIsOpenAd(true) + }, frequency * 1000) + + return () => clearInterval(interval) + } + + setIsNeedToShow(isNeedBanner) + return setIsOpenAd(isNeedBanner) + }, [ + frequency, + isNeedToShow, + views?.HOME, + isNeedBanner, + ]) + + useEffect(() => { + if (isFullscreen || !isOpenAd) return undefined + + const timeoutCloseAd = setTimeout(handleClose, currentAdsTime * 1000) + return () => { + clearTimeout(timeoutCloseAd) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + isNeedToShow, + isOpenAd, + isFullscreen, + currentAdsTime, + ]) + + useEffect(() => { + close() + const timeoutCloseBtn = time_close && setTimeout(showCloseBtn, time_close * 1000) + return () => { + time_close && clearTimeout(timeoutCloseBtn) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + isNeedToShow, + isOpenAd, + views?.HOME, + ]) + + useEffect(() => { + if (!isNeedToShow || (!isMatchPage() && !isNeedBanner)) return + + (async () => { + await updateAdsView({ adv_id: id }) + })() + sendBannerClickEvent(EventGA.DISPLAY) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [id, isNeedToShow]) + + return { + handleClose, + isNeedToShow, + isOpenAd, + isOpenCloseBtn, + isVideo, + sendBannerClickEvent, + } +} diff --git a/src/components/Ads/components/AdComponent/index.tsx b/src/components/Ads/components/AdComponent/index.tsx new file mode 100644 index 00000000..d5dfd302 --- /dev/null +++ b/src/components/Ads/components/AdComponent/index.tsx @@ -0,0 +1,85 @@ +import { memo, MouseEvent } from 'react' + +import type { AdType } from 'requests' + +import { useAd } from './hooks' + +import { EventGA } from '../../types' + +import { + AdImg, + AdVideo, + AdWrapper, + LinkWrapper, + AdsCloseButton, +} from './styled' + +export type AdComponentType = { + ad: AdType, +} +export const AdComponent = memo(({ ad }: AdComponentType) => { + const { + link, + media, + position, + } = ad + + const { + handleClose, + isNeedToShow, + isOpenAd, + isOpenCloseBtn, + isVideo, + sendBannerClickEvent, + } = useAd({ ad }) + + const close = (e: MouseEvent) => { + e.stopPropagation() + return handleClose() + } + + const onLinkClick = () => { + link && sendBannerClickEvent(EventGA.CLICK) + } + + return ( + position && isOpenAd && isNeedToShow + ? ( + + {isOpenCloseBtn && ( + + )} + + {isVideo + ? ( + + ) + : ( + + )} + + + ) : null + ) +}) diff --git a/src/components/Ads/components/AdComponent/styled.tsx b/src/components/Ads/components/AdComponent/styled.tsx new file mode 100644 index 00000000..fa310903 --- /dev/null +++ b/src/components/Ads/components/AdComponent/styled.tsx @@ -0,0 +1,109 @@ +import styled, { css } from 'styled-components/macro' + +import includes from 'lodash/includes' + +import { CloseButton } from 'features/PopupComponents' + +import { + MATCH_ADS, + PLAYER_ADS, + VIEW_ADS, +} from '../../types' + +type Props = { + position: number, +} + +const header = [7, 8, 9] + +const chooseStyle = (type: number) => { + switch (true) { + case VIEW_ADS.COLUMN === type: + return 'grid-row: 1 / 3; img {max-height: none;}' + case VIEW_ADS.ROW === type: + return 'grid-column: 1 / 3' + case VIEW_ADS.SQUARE === type: + return 'grid-row: 1 / 3; grid-column: 1 / 3; img {max-height: none;}' + case VIEW_ADS.SECOND_COLUMN === type: + return 'grid-column: 2 / 3; grid-row: 1 / 1' + case VIEW_ADS.SECOND_ROW === type: + return 'grid-column: 1 / 2; grid-row: 2 / 3;' + case MATCH_ADS.PLAYS_TOP === type: + return 'margin-left: 14px; height: 48px' + case MATCH_ADS.PLAYS_BOTTOM === type: + return 'grid-row: 4; margin-bottom: 12px; height: 48px;' + case PLAYER_ADS.LEFT_BOTTOM === type: + return css` + height: auto; + width: 42.4%; + bottom: 100px; + left: 20px; + ` + case PLAYER_ADS.CENTER_BOTTOM === type: + return css` + height: 18.3%; + width: 81.3%; + bottom: 100px; + left: 50%; + transform: translateX(-50%); + ` + case PLAYER_ADS.RIGHT === type: + return css` + height: 87.2%; + width: 18.3%; + bottom: 90px; + right: 18px; + ` + case PLAYER_ADS.FULL_SCREEN === type: + return 'bottom: 0; left: 0;' + default: + return '' + } +} + +export const AdImg = styled.img` + width: 100%; + min-height: ${({ position }) => (!includes(header, position) && '100%')}; + max-height: ${({ position }) => (includes(header, position) ? '13rem' : '100%')}; + cursor: pointer; + border-radius: 3px; +` + +export const AdVideo = styled.video` + object-fit: contain; + width: 100%; + cursor: pointer; + max-height: ${({ position }) => (includes(header, position) ? '283px' : '100%')}; + background-color: black; + border-radius: 3px; +` + +export const AdWrapper = styled.div` + position: ${({ position }) => (includes(PLAYER_ADS, position) ? 'absolute' : 'relative')}; + width: 100%; + height: 100%; + z-index: 1; + + ${({ position }) => chooseStyle(position)}; + + display: ${({ isOpenAd }) => (isOpenAd ? '' : 'none')}; +` + +export const AdsCloseButton = styled(CloseButton)` + position: absolute; + right: ${({ position }) => (position === PLAYER_ADS.FULL_SCREEN ? '10px' : '0')}; + top: ${({ position }) => (position === PLAYER_ADS.FULL_SCREEN ? '10px' : '0')}; + background: none; + border-radius: 0; + z-index: 2; + cursor: pointer; + color: #9B9B9B; + width: 28px; + height: 28px; + + :hover { + background: none; + } +` + +export const LinkWrapper = styled.a`` diff --git a/src/components/Ads/components/MobileAd/index.tsx b/src/components/Ads/components/MobileAd/index.tsx new file mode 100644 index 00000000..72726a35 --- /dev/null +++ b/src/components/Ads/components/MobileAd/index.tsx @@ -0,0 +1,71 @@ +import type { MouseEvent } from 'react' + +import includes from 'lodash/includes' + +import type { AdType } from 'requests' + +import { useAd } from '../AdComponent/hooks' +import { EventGA, PLAYER_MOBILE_FULL_SCREEN } from '../../types' + +import { + AdsCloseButton, + Img, + MobileAdWrapper, + Video, +} from './styled' + +type MobileAdTypes = { + ad: AdType, +} + +export const MobileAd = ({ ad }: MobileAdTypes) => { + const { + link, + media, + position, + } = ad + + const { + handleClose, + isNeedToShow, + isOpenAd, + isOpenCloseBtn, + isVideo, + sendBannerClickEvent, + } = useAd({ ad }) + + const close = (e: MouseEvent) => { + e.stopPropagation() + return handleClose() + } + + const onLinkClick = () => { + if (link) { + sendBannerClickEvent(EventGA.CLICK) + window.open(link, '_blank') + } + } + + return ( + position && isOpenAd && isNeedToShow ? ( + + {isOpenCloseBtn + && ( + + )} + {isVideo + ? + ) : null + ) +} diff --git a/src/components/Ads/components/MobileAd/styled.tsx b/src/components/Ads/components/MobileAd/styled.tsx new file mode 100644 index 00000000..49b5a212 --- /dev/null +++ b/src/components/Ads/components/MobileAd/styled.tsx @@ -0,0 +1,112 @@ +import styled, { css } from 'styled-components/macro' + +import includes from 'lodash/includes' + +import { CloseButton } from 'features/PopupComponents' + +import { + MATCH_ADS, + PLAYER_MOBILE_FULL_SCREEN, + PLAYER_MOBILE_ADS, +} from '../../types' + +type Props = { + position: number, +} + +const matchMobileAds = [16, 17, 22, 23, 24] + +const chooseStyle = (type: number) => { + switch (true) { + case MATCH_ADS.PLAYS_BOTTOM_MOBILE === type: + return css` + grid-row: 4; + margin-bottom: 12px; + height: 48px; + ` + case PLAYER_MOBILE_ADS === type: + return css` + position: absolute; + width: 92%; + bottom: 50px; + left: 15px; + ` + case PLAYER_MOBILE_FULL_SCREEN.VERTICAL_FULL_SCREEN === type: + case PLAYER_MOBILE_FULL_SCREEN.HORIZONTAL_FULL_SCREEN === type: + return css` + position: absolute; + top: 0; + left: 0; + height: 100%; + padding: 5px; + background-color: rgba(0, 0, 0, 0.7); + ` + default: + return '' + } +} + +export const MobileAdWrapper = styled.div` + position: relative; + width: 100%; + z-index: ${({ position }) => (includes(PLAYER_MOBILE_FULL_SCREEN, position) ? '101' : '100')}; + + ${({ position }) => chooseStyle(position)}; +` + +export const AdsCloseButton = styled(CloseButton)` + position: absolute; + right: ${({ position }) => (includes(PLAYER_MOBILE_FULL_SCREEN, position) ? '-5px' : '-10px')}; + top: ${({ position }) => (includes(PLAYER_MOBILE_FULL_SCREEN, position) ? '15px' : '10px')}; + background: none; + border-radius: 0; + transform: translate(-50%, -50%); + z-index: 2; + color: #9B9B9B; +` + +export const Img = styled.img` + border-radius: 2px; + width: 100%; + + object-fit: ${({ position }) => { + switch (true) { + case position === PLAYER_MOBILE_FULL_SCREEN.VERTICAL_FULL_SCREEN: + return 'fill' + case position === MATCH_ADS.PLAYS_TOP_MOBILE: + return 'contain' + default: + return 'cover' + } + }}; + + height: ${({ position }) => { + switch (true) { + case position === 10: + return '50px' + case includes(matchMobileAds, position): + return '100%' + default: + return '75px' + } + }} +` + +export const Video = styled.video` + max-height: 100%; + object-fit: cover; + min-width: 100%; + height: ${({ position }) => (position === 10 ? '50px' : '75px')}; + border-radius: 2px; + + height: ${({ position }) => { + switch (true) { + case position === 10: + return '50px' + case position === MATCH_ADS.PLAYS_TOP_MOBILE: + return '48px' + default: + return '75px' + } + }} +` diff --git a/src/components/Ads/helpers/calcMaxDurationAds.tsx b/src/components/Ads/helpers/calcMaxDurationAds.tsx new file mode 100644 index 00000000..d052d7bb --- /dev/null +++ b/src/components/Ads/helpers/calcMaxDurationAds.tsx @@ -0,0 +1,16 @@ +import type { AdResponse, AdsListType } from 'requests' + +export const calcMaxAdDurationAds = (advertisements: AdResponse) => { + const allAds = Object.values(advertisements) + + const combineAds = allAds.reduce((result, currentAd) => { + result.push(...currentAd) + + return result + }, [] as AdsListType) + + const maxDuration = combineAds + .reduce((result, { duration }) => Math.max(result, duration), 0) + + return maxDuration +} diff --git a/src/components/Ads/helpers/index.tsx b/src/components/Ads/helpers/index.tsx new file mode 100644 index 00000000..6be4e5f8 --- /dev/null +++ b/src/components/Ads/helpers/index.tsx @@ -0,0 +1 @@ +export * from './isVideo' diff --git a/src/components/Ads/helpers/isVideo.tsx b/src/components/Ads/helpers/isVideo.tsx new file mode 100644 index 00000000..cb35abc1 --- /dev/null +++ b/src/components/Ads/helpers/isVideo.tsx @@ -0,0 +1,2 @@ +const regexp = /^https?:\/\/\S+(?:mp4)$/ +export const checkVideo = (url: string) => regexp.test(url) diff --git a/src/components/Ads/hooks.tsx b/src/components/Ads/hooks.tsx new file mode 100644 index 00000000..4ec84537 --- /dev/null +++ b/src/components/Ads/hooks.tsx @@ -0,0 +1,65 @@ +import { useMemo } from 'react' + +import { useQuery } from 'react-query' + +import { useRecoilState } from 'recoil' + +import { isMobileDevice, querieKeys } from 'config' + +import { getAds } from 'requests' + +import { isMatchPage } from 'helpers/isMatchPage' +import { useLang } from 'features/LexicsStore/hooks/useLang' +import { useAuthStore } from 'features/AuthStore' + +import { + DeviceType, + PageType, +} from './types' +import { calcMaxAdDurationAds } from './helpers/calcMaxDurationAds' +import { adsStore } from '../../pages/HighlightsPage/storeHighlightsAtoms' + +type Props = { + matchId?: number, + sportType?: number, + tournamentId?: number, +} + +export const useAds = ({ + matchId, + sportType, + tournamentId, +}: Props) => { + const [ads, setAds] = useRecoilState(adsStore) + const { lang } = useLang() + const { user } = useAuthStore() + + useQuery({ + enabled: isMatchPage() ? (!!user && !!tournamentId) : !!user, + queryFn: async () => { + const adsList = await getAds({ + client_type: isMobileDevice ? DeviceType.MOBILE : DeviceType.WEB, + language: lang, + type_id: isMatchPage() ? PageType.MATCH : PageType.HOME, + ...isMatchPage() && { + matches: [{ + match_id: matchId, + sport_id: sportType, + }], + tournaments: [{ + sport_id: sportType, + tournament_id: tournamentId, + }], + }, + }) + adsList && setAds(adsList) + return adsList + }, + queryKey: [querieKeys.ads, matchId], + staleTime: useMemo(() => Math.max(calcMaxAdDurationAds(ads), 60 * 1000), [ads]), + }) + + return { + ads, + } +} diff --git a/src/components/Ads/index.tsx b/src/components/Ads/index.tsx new file mode 100644 index 00000000..f2064a14 --- /dev/null +++ b/src/components/Ads/index.tsx @@ -0,0 +1,31 @@ +import type { AdType } from 'requests' + +import { isMobileDevice } from 'config' + +import { AdComponent } from './components/AdComponent' +import { AdsPropsType } from './types' +import { MobileAd } from './components/MobileAd' + +import { + HeaderWrapAd, +} from './styled' + +export const HeaderAds = ({ ads }: AdsPropsType) => ( + ads?.length ? ( + + {ads.map((ad: AdType) => ( + !isMobileDevice ? ( + + ) : ( + + ) + ))} + + ) : null +) diff --git a/src/components/Ads/styled.tsx b/src/components/Ads/styled.tsx new file mode 100644 index 00000000..51fda9f1 --- /dev/null +++ b/src/components/Ads/styled.tsx @@ -0,0 +1,16 @@ +import styled, { css } from 'styled-components/macro' + +import { isMobileDevice } from 'config' + +export const HeaderWrapAd = styled.div<{column: number}>` + width: 100%; + margin-bottom: 0.7rem; + display: grid; + grid-column-gap: 0.9rem; + grid-template-columns: ${({ column }) => (column > 1 ? `repeat(${column},${16.3 * 6 / column}%)` : 'repeat(1, 98.7%)')}; + + ${isMobileDevice && css` + padding: 0 0.71rem; + grid-template-columns: none; + `}} +` diff --git a/src/components/Ads/types.tsx b/src/components/Ads/types.tsx new file mode 100644 index 00000000..9f1688eb --- /dev/null +++ b/src/components/Ads/types.tsx @@ -0,0 +1,57 @@ +import { AdsListType } from 'requests' + +export enum PageType { + HOME = 1, + MATCH = 2, +} + +export enum DeviceType { + MOBILE = 'mobile', + WEB = 'web' +} + +export type ViewsType = Partial> + +export enum EventGA { + CLICK = 'banner_click', + CLOSE = 'banner_close', + DISPLAY = 'banner_display' +} + +export enum VIEW_ADS { + ROW = 4, + COLUMN = 5, + SQUARE = 6, + SECOND_COLUMN = 2, + SECOND_ROW = 3, + MOBILE_IN_COLLAPSE_HEADER = 12, + MOBILE_IN_COLLAPSE_FOOTER = 25 +} + +export const HEADER_MOBILE_ADS = [10, 11] + +export enum MATCH_ADS { + WATCH_TOP = 13, + PLAYS_TOP = 14, + PLAYS_BOTTOM = 15, + PLAYS_TOP_MOBILE = 16, + PLAYS_BOTTOM_MOBILE = 17, +} + +export enum PLAYER_ADS { + LEFT_BOTTOM = 18, + CENTER_BOTTOM = 19, + RIGHT = 20, + FULL_SCREEN = 21, +} + +export const PLAYER_MOBILE_ADS = 22 + +export enum PLAYER_MOBILE_FULL_SCREEN { + VERTICAL_FULL_SCREEN = 23, + HORIZONTAL_FULL_SCREEN = 24, +} + +export type AdsPropsType = Record<'ads', AdsListType | undefined> + +export const adsViews = 'adsViews' diff --git a/src/config/index.tsx b/src/config/index.tsx index a5fd70ae..cf9cf018 100644 --- a/src/config/index.tsx +++ b/src/config/index.tsx @@ -12,3 +12,4 @@ export * from './userAgent' export * from './queries' export * from './keyboardKeys' export * from './clients' +export * from './localStorageKeys' diff --git a/src/config/localStorageKeys.tsx b/src/config/localStorageKeys.tsx new file mode 100644 index 00000000..c571f751 --- /dev/null +++ b/src/config/localStorageKeys.tsx @@ -0,0 +1 @@ +export const COUNTRY = 'COUNTRY' diff --git a/src/config/queries.tsx b/src/config/queries.tsx index 79580931..45fbda9d 100644 --- a/src/config/queries.tsx +++ b/src/config/queries.tsx @@ -1,4 +1,5 @@ export const querieKeys = { + ads: 'ads', liveMatchScores: 'liveMatchScores', matchScore: 'matchScore', sportsList: 'sportsList', diff --git a/src/config/userAgent.tsx b/src/config/userAgent.tsx index 15dcc250..f0f11cfb 100644 --- a/src/config/userAgent.tsx +++ b/src/config/userAgent.tsx @@ -1,5 +1,7 @@ -export const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) +export const device = navigator.userAgent -export const isAndroid = /Android/.test(navigator.userAgent) +export const isIOS = /iPad|iPhone|iPod/.test(device) -export const isMobileDevice = /iPhone|Android/.test(navigator.userAgent) +export const isAndroid = /Android/.test(device) + +export const isMobileDevice = /iPhone|Android/.test(device) diff --git a/src/features/HeaderFilters/components/DateFilter/hooks/index.tsx b/src/features/HeaderFilters/components/DateFilter/hooks/index.tsx index 7225e678..7bda0907 100644 --- a/src/features/HeaderFilters/components/DateFilter/hooks/index.tsx +++ b/src/features/HeaderFilters/components/DateFilter/hooks/index.tsx @@ -10,11 +10,15 @@ import { addDays, } from 'date-fns' -import { useToggle } from 'hooks' +import isObject from 'lodash/isObject' + +import { useLocalStore, useToggle } from 'hooks' import { useLexicsStore } from 'features/LexicsStore' import { useHeaderFiltersStore } from 'features/HeaderFilters' +import { ViewsType } from 'components/Ads/types' + import { getDisplayDate, getMonths, @@ -61,6 +65,15 @@ export const useDateFilter = () => { const parseFilters = filters && JSON.parse(filters) const lastDate = parseFilters?.selectedDate const weekName = getWeekName(selectedDate, 'en') + const validator = (value: unknown) => Boolean(value) && isObject(value) + + const [adsViews, setAdsViews] = useLocalStore({ + clearOnUnmount: true, + defaultValue: { HOME: 0 }, + key: 'adsViews', + validator, + }) + useEffect(() => { if (lastDate === selectedDate.getDate() && parseFilters @@ -72,6 +85,10 @@ export const useDateFilter = () => { setIsShowTournament(true) setSelectedFilters([]) setSelectedLeague(['all_competitions']) + setAdsViews({ + ...adsViews, + HOME: (adsViews.HOME ?? 0) + 1, + }) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedDate]) diff --git a/src/features/HomePage/hooks.tsx b/src/features/HomePage/hooks.tsx index 3cfc48f9..4fb99efc 100644 --- a/src/features/HomePage/hooks.tsx +++ b/src/features/HomePage/hooks.tsx @@ -14,10 +14,19 @@ import { ClientNames } from 'config/clients/types' import { useAuthStore } from 'features/AuthStore' import { useHeaderFiltersStore } from 'features/HeaderFilters' -import { getHomeMatches } from 'requests/getMatches' -import { getAgreements, setAgreements } from 'requests/getAgreements' +import { + getHomeMatches, + getAgreements, + setAgreements, + getCountryCode, +} from 'requests' + +import { setLocalStorageItem } from 'helpers' + +import { COUNTRY } from 'config' import { isSportFilterShownAtom } from './Atoms/HomePageAtoms' +import { useAds } from '../../components/Ads/hooks' /** * возвращает смещение в минутах относительно UTC @@ -34,7 +43,7 @@ const getTimezoneOffset = (date: Date) => { const getDate = (date: Date) => format(date, 'yyyy-MM-dd') export const useHomePage = () => { - const { user, userInfo } = useAuthStore() + const { userInfo } = useAuthStore() const { isMonthMode, selectedDate, @@ -44,6 +53,9 @@ export const useHomePage = () => { const [isOpenDownload, setIsOpenDownload] = useState(false) const [isShowConfirmPopup, setIsShowConfirmPopup] = useState(false) const setIsSportFilterShown = useSetRecoilState(isSportFilterShownAtom) + + const { ads } = useAds({}) + const date = isMonthMode ? selectedMonthModeDate : selectedDate const dateTo = isMonthMode ? `${getDate(endOfMonth(selectedMonthModeDate))} 00:00:00` @@ -55,6 +67,13 @@ export const useHomePage = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [setIsShowConfirmPopup, userInfo]) + const countryCode = async () => { + const { country_code } = await getCountryCode() + country_code && setLocalStorageItem(COUNTRY, country_code) + + return country_code + } + useEffect(() => { if (userInfo?.email) { (async () => { @@ -74,7 +93,10 @@ export const useHomePage = () => { ) { setIsOpenDownload(true) } + + countryCode() }, []) + const fetchMatches = useCallback( (limit: number, offset: number) => getHomeMatches({ date: getDate(date), @@ -86,7 +108,7 @@ export const useHomePage = () => { // eslint-disable-next-line react-hooks/exhaustive-deps [ selectedDate, - user, + userInfo?.email, dateTo, date, ], @@ -99,6 +121,7 @@ export const useHomePage = () => { }, [setIsSportFilterShown]) return { + ads, fetchMatches, handleCloseConfirmPopup, isOpenDownload, diff --git a/src/features/HomePage/index.tsx b/src/features/HomePage/index.tsx index f5d94791..74b5f424 100644 --- a/src/features/HomePage/index.tsx +++ b/src/features/HomePage/index.tsx @@ -8,7 +8,6 @@ import { Matches } from 'features/Matches' import { HeaderFiltersStore, } from 'features/HeaderFilters' - import { PageWrapper, Main, @@ -16,6 +15,9 @@ import { } from 'features/PageLayout' import { UserFavorites } from 'features/UserFavorites' +import { HEADER_MOBILE_ADS } from 'components/Ads/types' +import { HeaderAds } from 'components/Ads' + import { useHomePage } from './hooks' import { Header } from './components/Header' import { HeaderMobile } from '../HeaderMobile' @@ -24,6 +26,7 @@ import { HeaderFilters } from './components/HeaderFilters' const Home = () => { usePageLogger(PAGES.home) const { + ads, fetchMatches, handleCloseConfirmPopup, isOpenDownload, @@ -46,8 +49,17 @@ const Home = () => {
- {isMobileDevice ? null : } - {/* {userInfo?.email && } */} + {!isMobileDevice && } + {userInfo?.email + && ads + && ( + HEADER_MOBILE_ADS.includes(position.id)) + : ads?.header + } + /> + )} { @@ -40,6 +50,7 @@ const MatchPageComponent = () => { const { colors } = useTheme() const { + ads, isStarted, profile, user, @@ -54,6 +65,11 @@ const MatchPageComponent = () => { const { isOpen } = useTour() + const { + HORIZONTAL_FULL_SCREEN, + VERTICAL_FULL_SCREEN, + } = PLAYER_MOBILE_FULL_SCREEN + useEffect(() => { let timer = 0 timer = window.setTimeout(() => { @@ -95,11 +111,29 @@ const MatchPageComponent = () => { history.push(`/${sportName}/tournaments/${profile.tournament.id}`) } + const [orientation, setOrientation] = useState(window.orientation) + + useEffect(() => { + const handleOrientationChange = () => setOrientation(window.orientation) + window.addEventListener('orientationchange', handleOrientationChange) + return () => window.removeEventListener('orientationchange', handleOrientationChange) + }, []) + + const currentAds = useMemo(() => ( + window.orientation === 0 + ? find(ads.mobile, (ad) => ad.position.id === VERTICAL_FULL_SCREEN) + : find(ads.mobile, (ad) => ad.position.id === HORIZONTAL_FULL_SCREEN) + // eslint-disable-next-line react-hooks/exhaustive-deps + ), [ads.mobile, orientation]) + return ( + {isMobileDevice + && currentAds + && }
diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 280c4ede..f77da066 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -29,6 +29,8 @@ import { usePageParams, useToggle } from 'hooks' import { redirectToUrl } from 'helpers/redirectToUrl' import { parseDate } from 'helpers/parseDate' +import { useAds } from 'components/Ads/hooks' + import { useTournamentData } from './useTournamentData' import { useMatchData } from './useMatchData' import { useFiltersPopup } from './useFitersPopup' @@ -71,6 +73,7 @@ const ACCESS_TIME = 60 export const useMatchPage = () => { const [matchProfile, setMatchProfile] = useState(null) const [watchAllEpisodesTimer, setWatchAllEpisodesTimer] = useState(false) + const [isFullscreen, setIsFullScreen] = useState(false) const [access, setAccess] = useState(true) const [playingProgress, setPlayingProgress] = useState(0) const [playingData, setPlayingData] = useState(initPlayingData) @@ -87,6 +90,12 @@ export const useMatchPage = () => { const { profileId: matchId, sportType } = usePageParams() + const { ads } = useAds({ + matchId, + sportType, + tournamentId: matchProfile?.tournament?.id, + }) + useEffect(() => { sessionStorage.removeItem('isFromLanding') }, []) @@ -401,6 +410,7 @@ export const useMatchPage = () => { activeFirstTeamPlayers, activeSecondTeamPlayers, activeStatus, + ads, allActionsToggle, allPlayersToggle, applyFilters, @@ -421,6 +431,7 @@ export const useMatchPage = () => { isEmptyFilters, isExpanded, isFirstTeamPlayersChecked, + isFullscreen, isLiveMatch, isOpenFiltersPopup, isPlayFilterEpisodes: isStatsPlaylist ? isStatsPlayFilterEpisodes : isPlayFilterEpisodes, @@ -450,6 +461,7 @@ export const useMatchPage = () => { setCircleAnimation: isStatsPlaylist ? setStatsCircleAnimation : setCircleAnimation, setEpisodeInfo, setFullMatchPlaylistDuration, + setIsFullScreen, setIsPlayingFiltersEpisodes: isStatsPlaylist ? setStatsIsPlayinFiltersEpisodes : setIsPlayersStatsFetching, diff --git a/src/features/MatchSidePlaylists/components/EventsList/index.tsx b/src/features/MatchSidePlaylists/components/EventsList/index.tsx index 6bbbfaca..d7c70c28 100644 --- a/src/features/MatchSidePlaylists/components/EventsList/index.tsx +++ b/src/features/MatchSidePlaylists/components/EventsList/index.tsx @@ -3,9 +3,14 @@ import { useEffect } from 'react' import map from 'lodash/map' import find from 'lodash/find' -import type { Events, MatchInfo } from 'requests' +import type { + Events, + MatchInfo, + AdType, +} from 'requests' import { isLffClient } from 'config/clients' +import { isMobileDevice } from 'config/userAgent' import { T9n } from 'features/T9n' import type { @@ -13,11 +18,14 @@ import type { PlaylistOption, } from 'features/MatchPage/types' import { PlaylistTypes } from 'features/MatchPage/types' - import { useMatchPageStore } from 'features/MatchPage/store' import { useLexicsStore } from 'features/LexicsStore' import { Tabs } from 'features/MatchSidePlaylists/config' +import { AdComponent } from 'components/Ads/components/AdComponent' +import { MobileAd } from 'components/Ads/components/MobileAd' +import { MATCH_ADS } from 'components/Ads/types' + import { isEqual } from '../../helpers' import { EventButton } from '../EventButton' import { @@ -30,6 +38,7 @@ import { type Props = { disablePlayingEpisodes?: () => void, events: Events, + isFirstBlock?: boolean, onSelect: (option: PlaylistOption) => void, profile: MatchInfo, selectedPlaylist?: PlaylistOption, @@ -39,12 +48,14 @@ type Props = { export const EventsList = ({ disablePlayingEpisodes, events, + isFirstBlock, onSelect, profile, selectedPlaylist, setWatchAllEpisodesTimer, }: Props) => { const { + ads, filteredEvents, isPlayingEpisode, selectedTab, @@ -52,6 +63,8 @@ export const EventsList = ({ } = useMatchPageStore() const { suffix, translate } = useLexicsStore() + const { PLAYS_BOTTOM, PLAYS_BOTTOM_MOBILE } = MATCH_ADS + useEffect(() => { if (selectedPlaylist?.tab === Tabs.EVENTS && isPlayingEpisode) { const { @@ -84,6 +97,14 @@ export const EventsList = ({ return ( + {ads + && isFirstBlock + && (isMobileDevice + ? map(ads?.mobile, (ad: AdType) => ad?.position.id === PLAYS_BOTTOM_MOBILE + && ) + : map(ads?.match, (ad: AdType) => ad?.position.id === PLAYS_BOTTOM + && ) + )} {map(events, (event) => { if (!event.t && !event.pl) { return ( diff --git a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx index f9f8766e..10848015 100644 --- a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx @@ -5,6 +5,7 @@ import styled, { css } from 'styled-components/macro' import isEmpty from 'lodash/isEmpty' import map from 'lodash/map' +import some from 'lodash/some' import { isMobileDevice } from 'config' @@ -19,6 +20,8 @@ import { T9n } from 'features/T9n' import { useMatchPageStore } from 'features/MatchPage/store' import { useLexicsStore } from 'features/LexicsStore' +import { MATCH_ADS } from 'components/Ads/types' + import { PlayButton } from '../PlayButton' import { MatchDownloadButton } from '../MatchDownloadButton' @@ -31,8 +34,12 @@ type Props = { selectedMathPlaylist?: PlaylistOption, } -const List = styled.ul` - margin-bottom: ${LIST_INDENT}px; +type ListProps = { + isAdsExist?: boolean, +} + +const List = styled.ul` + margin-bottom: ${({ isAdsExist }) => (isAdsExist ? '15px' : `${LIST_INDENT}px`)}; ` export const Item = styled.li` @@ -62,7 +69,7 @@ export const MatchPlaylists = forwardRef( }: Props, ref: ForwardedRef, ) => { - const { setEpisodeInfo } = useMatchPageStore() + const { ads, setEpisodeInfo } = useMatchPageStore() const { translate } = useLexicsStore() const handleButtonClick = (playlist: MatchPlaylistOption) => { @@ -76,7 +83,10 @@ export const MatchPlaylists = forwardRef( } return ( - + position.id === MATCH_ADS.WATCH_TOP)} + > { map(playlists, (playlist) => ( ) diff --git a/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx b/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx index 552961b3..311908b8 100644 --- a/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx @@ -25,7 +25,10 @@ export const HalfList = styled.ul` export const HalfEvents = styled.li`` -export const List = styled.ul`` +export const List = styled.ul` + display: grid; + grid-template-columns: 100%; +` export const Event = styled.li` width: 100%; diff --git a/src/features/MatchSidePlaylists/components/TabWatch/index.tsx b/src/features/MatchSidePlaylists/components/TabWatch/index.tsx index 8c7ab360..e975abbb 100644 --- a/src/features/MatchSidePlaylists/components/TabWatch/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabWatch/index.tsx @@ -6,13 +6,21 @@ import { import size from 'lodash/size' import filter from 'lodash/filter' +import map from 'lodash/map' + +import { isMobileDevice } from 'config/userAgent' import type { PlaylistOption, Playlists, TournamentData, } from 'features/MatchPage/types' -import type { MatchInfo } from 'requests' +import { useMatchPageStore } from 'features/MatchPage/store' + +import type { MatchInfo, AdType } from 'requests' + +import { AdComponent } from 'components/Ads/components/AdComponent' +import { MATCH_ADS } from 'components/Ads/types' import { DropdownSection } from '../DropdownSection' import { MatchPlaylists, LIST_INDENT } from '../MatchPlaylists' @@ -34,6 +42,8 @@ export const TabWatch = ({ selectedPlaylist, tournamentData, }: Props) => { + const { ads } = useMatchPageStore() + const matchPlaylistsRef = useRef(null) const additionalScrollHeight = (matchPlaylistsRef.current?.clientHeight || 0) + LIST_INDENT @@ -55,6 +65,12 @@ export const TabWatch = ({ onSelect={onSelect} live={profile?.live} /> + {!isMobileDevice + && ads + && ( + map(ads?.match, (ad: AdType) => ad?.position.id === MATCH_ADS.WATCH_TOP + && ) + )} { const { + ads, hideProfileCard, matchPlaylists: playlists, profile, @@ -86,6 +97,8 @@ export const MatchSidePlaylists = ({ const [hasTabPaneScroll, setTabPaneScroll] = useState(false) + const { PLAYS_TOP, PLAYS_TOP_MOBILE } = MATCH_ADS + useEffect(() => { const { clientHeight = 0, @@ -139,6 +152,17 @@ export const MatchSidePlaylists = ({ {showTabs && ( + {selectedTab === Tabs.EVENTS + && ads + && ( + + {isMobileDevice + ? map(ads?.mobile, (ad: AdType) => ad?.position.id === PLAYS_TOP_MOBILE + && ) + : map(ads?.match, (ad: AdType) => ad?.position.id === PLAYS_TOP + && )} + + )} ` padding-right: 14px; - padding-top: 10px; ${({ highlighted }) => (highlighted ? css` @@ -58,6 +57,7 @@ export const TabsGroup = styled.div.attrs({ role: 'tablist' })` display: flex; justify-content: center; gap: ${isMobileDevice ? 30 : 20}px; + padding-top: 10px; ` export const TabTitle = styled(T9n)` @@ -129,7 +129,7 @@ export const Container = styled.div` width: 320px; margin-top: 14px; max-height: calc(100vh - 130px); - overflow-y: ${({ forWatchTab }) => (forWatchTab ? 'hidden' : 'auto')}; + overflow-y: auto; padding-right: ${({ forWatchTab }) => (forWatchTab ? '0' : '')}; padding-left: 14px; padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')}; @@ -253,3 +253,14 @@ export const BlockTitle = styled.span` color: rgba(255, 255, 255, 0.5); text-transform: uppercase; ` + +export const EventsAdsWrapper = styled.div` + width: ${({ hasScroll }) => (hasScroll ? '288px' : '306px')}; + margin-bottom: 0.6rem; + + ${isMobileDevice + ? css` + width: 100%; + ` + : ''}; +` diff --git a/src/features/MatchesGrid/index.tsx b/src/features/MatchesGrid/index.tsx index d2b93089..8b37a1ce 100644 --- a/src/features/MatchesGrid/index.tsx +++ b/src/features/MatchesGrid/index.tsx @@ -1,10 +1,12 @@ import { memo, useEffect } from 'react' + import { useRouteMatch } from 'react-router-dom' + import { useQuery } from 'react-query' -import { PAGES } from 'config/pages' +import { isMobileDevice, PAGES } from 'config' -import type { LiveScore } from 'requests' +import type { AdType, LiveScore } from 'requests' import { getLiveScores } from 'requests' import { MatchCard } from 'features/MatchCard' @@ -12,9 +14,14 @@ import { TournamentList } from 'features/TournamentList' import type { Match } from 'features/Matches' import { useHeaderFiltersStore } from 'features/HeaderFilters' -import { Wrapper } from './styled' +import { readToken } from 'helpers' + import { useMatchSwitchesStore } from '../MatchSwitches' +import { useHomePage } from '../HomePage/hooks' import { querieKeys } from '../../config' +import { AdComponent } from '../../components/Ads/components/AdComponent' + +import { Wrapper } from './styled' type MatchesGridProps = { matches: Array, @@ -24,6 +31,10 @@ export const MatchesGrid = memo(({ matches }: MatchesGridProps) => { const isHomePage = useRouteMatch(PAGES.home)?.isExact const { isScoreHidden } = useMatchSwitchesStore() + const { ads } = useHomePage() + + const currentAds = ads?.match_cell?.length ? ads?.match_cell : ads?.block + const { compareSport, isShowTournament, @@ -76,6 +87,12 @@ export const MatchesGrid = memo(({ matches }: MatchesGridProps) => { return ( + {!isMobileDevice + && readToken() + && currentAds + && ( + currentAds?.map((ad: AdType) => ) + )} {isHomePage && isShowTournament ? ( ) : ( diff --git a/src/features/MatchesGrid/styled.tsx b/src/features/MatchesGrid/styled.tsx index 7bcbc34d..18382782 100644 --- a/src/features/MatchesGrid/styled.tsx +++ b/src/features/MatchesGrid/styled.tsx @@ -6,6 +6,7 @@ export const Wrapper = styled.ul` display: grid; grid-gap: 0.9rem; grid-template-columns: repeat(6, 15.7%); + ${isMobileDevice ? css` display: flex; diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index 787875a7..e3a764ca 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -118,6 +118,7 @@ export const useVideoPlayer = ({ playNextEpisode, selectedPlaylist, setCircleAnimation, + setIsFullScreen, setPlayingProgress, } = useMatchPageStore() @@ -673,6 +674,13 @@ export const useVideoPlayer = ({ profileId, ]) + useEffect(() => { + setIsFullScreen(isFullscreen) + }, [ + isFullscreen, + setIsFullScreen, + ]) + return { activeChapterIndex, allPlayedProgress: playedProgress + getActiveChapter().startMs, diff --git a/src/features/StreamPlayer/index.tsx b/src/features/StreamPlayer/index.tsx index e81c6261..e431e5ad 100644 --- a/src/features/StreamPlayer/index.tsx +++ b/src/features/StreamPlayer/index.tsx @@ -1,5 +1,7 @@ import { Fragment } from 'react' +import includes from 'lodash/includes' + import { isMobileDevice } from 'config' import { Loader } from 'features/Loader' @@ -10,8 +12,15 @@ import { FiltersPopup } from 'features/MatchSidePlaylists/components/FiltersPopu import { WaterMark } from 'components/WaterMark' import { AccessTimer } from 'components/AccessTimer' +import { PLAYER_ADS, PLAYER_MOBILE_ADS } from 'components/Ads/types' +import { HeaderAds } from 'components/Ads' import { REWIND_SECONDS } from './config' +import type { Props } from './hooks' +import { useVideoPlayer } from './hooks' +import { useAuthStore } from '../AuthStore' +import { Controls } from './components/Controls' +import RewindMobile from './components/RewindMobile' import { PlayerWrapper, @@ -27,12 +36,8 @@ import { EpisodeInfoOrder, EpisodeInfoDivider, CloseButton, + PlayerAdsWrapper, } from './styled' -import type { Props } from './hooks' -import { useVideoPlayer } from './hooks' -import { useAuthStore } from '../AuthStore' -import { Controls } from './components/Controls' -import RewindMobile from './components/RewindMobile' const tournamentsWithWatermark = { 316: 'Tunisia', @@ -44,6 +49,7 @@ const tournamentsWithWatermark = { export const StreamPlayer = (props: Props) => { const { access, + ads, episodeInfo, isOpenFiltersPopup, isPlayingEpisode, @@ -120,6 +126,17 @@ export const StreamPlayer = (props: Props) => { onTouchEnd={onTouchEnd} isPlayingEpisode={isPlayingEpisode} > + {ads + && ( + + position.id === PLAYER_MOBILE_ADS) + : ads?.match?.filter(({ position }) => includes(PLAYER_ADS, position.id)) + } + /> + + )} {isPlayingEpisode && ( diff --git a/src/features/StreamPlayer/styled.tsx b/src/features/StreamPlayer/styled.tsx index 2a183d2c..1cab2be7 100644 --- a/src/features/StreamPlayer/styled.tsx +++ b/src/features/StreamPlayer/styled.tsx @@ -17,6 +17,10 @@ type HoverStylesProps = { visible: boolean, } +type PlayerAdsProps = { + isFullscreen: boolean, +} + export const hoverStyles = css` transition: opacity 0.3s ease-in-out; ${({ visible }) => (visible @@ -485,3 +489,8 @@ export const CloseButton = styled(CloseButtonBase)` height: max(1.2rem, 23px); } ` + +export const PlayerAdsWrapper = styled.div` + opacity: ${({ isFullscreen }) => (isFullscreen ? 0 : 1)}; +` + diff --git a/src/features/TournamentList/components/TournamentMobile/index.tsx b/src/features/TournamentList/components/TournamentMobile/index.tsx index 233eed92..5e08c390 100644 --- a/src/features/TournamentList/components/TournamentMobile/index.tsx +++ b/src/features/TournamentList/components/TournamentMobile/index.tsx @@ -1,9 +1,15 @@ import { Fragment, useState } from 'react' +import { useRecoilValue } from 'recoil' + import { isLffClient } from 'config/clients' -import { URL_AWS } from 'config' +import { + isMobileDevice, + URL_AWS, +} from 'config' + +import { AdType } from 'requests' -import { SportIcon } from 'components/SportIcon/SportIcon' import { T9n } from 'features/T9n' import { Icon } from 'features/Icon' import type { Match } from 'features/Matches' @@ -14,6 +20,11 @@ import { LiveSign, } from 'features/MatchCard/CardFrontside/MatchCardMobile/styled' +import { VIEW_ADS } from 'components/Ads/types' +import { SportIcon } from 'components/SportIcon/SportIcon' + +import { adsStore } from 'pages/HighlightsPage/storeHighlightsAtoms' + import { CardWrapperOuter, CardWrapper, @@ -22,6 +33,7 @@ import { ScFirstInfo, ScMatchesWrapper, ScSecondInfo, + TournamentMobileAd, } from './styled' import { TournamentProps } from '../..' @@ -40,6 +52,8 @@ export const TournamentMobile = ({ const currentColor = open ? '#ffffff' : 'rgba(255, 255, 255, 0.5)' + const ads = useRecoilValue(adsStore) + return ( - {open - && tournamentMatches?.map((match: Match) => ( - - ))} + {open && ( + <> + {isMobileDevice && ads?.mobile?.map((ad: AdType) => ( + ad.position.id === VIEW_ADS.MOBILE_IN_COLLAPSE_HEADER && ( + + )))} + {tournamentMatches?.map((match: Match) => ( + + ))} + {isMobileDevice && ads?.mobile?.map((ad: AdType) => ( + ad.position.id === VIEW_ADS.MOBILE_IN_COLLAPSE_FOOTER && ( + + )))} + + )} ) diff --git a/src/features/TournamentList/components/TournamentMobile/styled.tsx b/src/features/TournamentList/components/TournamentMobile/styled.tsx index 3a103dc1..1b4bbd7f 100644 --- a/src/features/TournamentList/components/TournamentMobile/styled.tsx +++ b/src/features/TournamentList/components/TournamentMobile/styled.tsx @@ -1,7 +1,10 @@ import styled, { css } from 'styled-components/macro' + import { Name } from 'features/Name' import { Icon } from 'features/Icon' +import { MobileAd } from 'components/Ads/components/MobileAd' + import { isMobileDevice } from 'config/userAgent' export const CardWrapperOuter = styled.li.attrs({ @@ -82,6 +85,10 @@ export const ScMatchesWrapper = styled.ul` flex-direction: column; ` +export const TournamentMobileAd = styled(MobileAd)` + margin: 6px 0 0; +` + export const ScStar = styled(Icon)` display: flex; justify-content: center; diff --git a/src/pages/HighlightsPage/storeHighlightsAtoms.tsx b/src/pages/HighlightsPage/storeHighlightsAtoms.tsx index 2c0227dd..542aed44 100644 --- a/src/pages/HighlightsPage/storeHighlightsAtoms.tsx +++ b/src/pages/HighlightsPage/storeHighlightsAtoms.tsx @@ -1,6 +1,6 @@ import { atom, selector } from 'recoil' -import type { Match } from 'requests' +import type { AdResponse, Match } from 'requests' export type MatchType = Match & { isChecked: boolean, @@ -43,6 +43,11 @@ export const fetchingMatches = atom({ key: 'fetchingMatches', }) +export const adsStore = atom({ + default: {} as AdResponse, + key: 'adsStore', +}) + export const checkedMatches = selector({ get: ({ get }) => { const matches = get(playerMatchesState) diff --git a/src/requests/getAds/getAds.tsx b/src/requests/getAds/getAds.tsx new file mode 100644 index 00000000..f094ad40 --- /dev/null +++ b/src/requests/getAds/getAds.tsx @@ -0,0 +1,65 @@ +import { callApi } from 'helpers' + +import { ADS_API_URL } from 'config' + +import { DeviceType } from '../../components/Ads/types' + +type MatchesParams = { + match_id?: number, + sport_id?: number, +} + +type TournamentsParams = { + sport_id?: number, + tournament_id?: number, +} + +export type AdsParams = { + client_type: DeviceType, + language: string, + matches?: Array, + tournaments?: Array, + type_id: number, +} + +export type AdType = { + duration: number, + frequency: number, + id: number, + impressions: number, + link: string, + media: { + url: string, + }, + name: string, + position: { + id: number, + name_eng: string, + name_rus: string, + source_type: string, + }, + remaining_views: number, + time_close: number, + type: { + id: number, + name_eng: string, + name_rus: string, + }, +} + +export type PositionName = 'header' | 'block' | 'match_cell' | 'mobile' | 'match' + +export type AdResponse = Record + +export type AdsListType = Array + +export const getAds = (params: AdsParams): Promise => { + const config = { + body: params, + } + + return callApi({ + config, + url: ADS_API_URL, + }) +} diff --git a/src/requests/getAds/index.tsx b/src/requests/getAds/index.tsx new file mode 100644 index 00000000..106b0b5a --- /dev/null +++ b/src/requests/getAds/index.tsx @@ -0,0 +1,2 @@ +export * from './getAds' +export * from './updateAdsView' diff --git a/src/requests/getAds/updateAdsView.tsx b/src/requests/getAds/updateAdsView.tsx new file mode 100644 index 00000000..71f0f86e --- /dev/null +++ b/src/requests/getAds/updateAdsView.tsx @@ -0,0 +1,29 @@ +import { callApi } from 'helpers' + +import { ADS_API_URL } from 'config' + +export type AdsViewParams = { + adv_id: number, +} + +type AdsViewResponse = { + data: string, + message: string, + reason: string, + status: 'failed' | 'success', +} + +export const updateAdsView = ( + { adv_id }: AdsViewParams, +): Promise => { + const config = { + body: { + adv_id, + }, + } + + return callApi({ + config, + url: `${ADS_API_URL}/${adv_id}/view`, + }) +} diff --git a/src/requests/index.tsx b/src/requests/index.tsx index b11eb223..d16ce922 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -36,3 +36,7 @@ export * from './getTokenVirtualUser' export * from './checkDevice' export * from './getPaymentOTTUrl' export * from './getPaymentPayUrl' +export * from './getAds' +export * from './getFavouriteTeam' +export * from './getCountryCode' +export * from './getAgreements' diff --git a/src/utilits/mirage/Mirage.tsx b/src/utilits/mirage/Mirage.tsx deleted file mode 100644 index b685e049..00000000 --- a/src/utilits/mirage/Mirage.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable */ -import { - createServer, - Model, -} from 'miragejs' - -import { ResponseType } from 'requests/getFavouriteTeam' - -import { surveys } from './fixtures/surveys' - -export function makeServer({ environment = 'test' } = {}) { - const server = createServer({ - environment, - factories: {}, - fixtures: { - surveys, - }, - models: { - surveys: Model.extend>({}), - }, - routes() { - this.passthrough('https://api.insports.tv/***') - this.passthrough('https://insports.tv/***') - this.passthrough('https://images.insports.tv/***') - this.passthrough('https://auth.insports.tv/***') - this.passthrough('${URL_AWS}/***') - this.get('https://api.insports.tv/v1/survey/teams/1/131/30', (schema: any) => schema.all('surveys').models[0].attrs) - }, - }) - return server -} diff --git a/src/utilits/mirage/fixtures/getAds.tsx b/src/utilits/mirage/fixtures/getAds.tsx new file mode 100644 index 00000000..b144bd23 --- /dev/null +++ b/src/utilits/mirage/fixtures/getAds.tsx @@ -0,0 +1,592 @@ +/* eslint-disable */ +export const getAds = () => { + return { + "mobile": [ + { + "id": 71, + "name": "Test 2", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 12, + "source_type": "Web", + "name_eng": "Web main ad 2 (1x1)", + "name_rus": "Веб: главная 2 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 2, + "duration": 120, + "time_close": 150, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/71/en/web.png" + }, + "remaining_views": 9 + },{ + "id": 71, + "name": "Test 2", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 25, + "source_type": "Web", + "name_eng": "Web main ad 2 (1x1)", + "name_rus": "Веб: главная 2 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 2, + "duration": 120, + "time_close": 150, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/71/en/web.png" + }, + "remaining_views": 9 + }, + { + "id": 72, + "name": "Best mens boots for sport advertise here", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 11, + "source_type": "Web", + "name_eng": "Web main ad 7 (1x1)", + "name_rus": "Веб: главная 7 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 2, + "frequency": 1, + "duration": 300, + "time_close": 500, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/72/en/web.png" + }, + "remaining_views": 9 + }, + { + "id": 85, + "name": "Test 16", + "type": { + "id": 2, + "name_eng": "Match", + "name_rus": "Матч" + }, + "position": { + "id": 16, + "source_type": "Mobile", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 60, + "frequency": 5, + "duration": 12000, + "time_close": 1, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/85/en/mobile.png" + }, + "remaining_views": 60 + }, + + { + "id": 86, + "name": "Test 17", + "type": { + "id": 2, + "name_eng": "Match", + "name_rus": "Матч" + }, + "position": { + "id": 17, + "source_type": "Mobile", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 5, + "duration": 12000, + "time_close": 1, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/86/en/mobile.png" + }, + "remaining_views": 10 + }, + { + "id": 91, + "name": "Test 22", + "type": { + "id": 3, + "name_eng": "Player", + "name_rus": "Плеер" + }, + "position": { + "id": 22, + "source_type": "Mobile", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 10, + "duration": 12000, + "time_close": 1, + "media": { + "url": "https://i.imgur.com/5Tbygu1.png" + }, + "remaining_views": 10 + }, + { + "id": 92, + "name": "Test 23", + "type": { + "id": 3, + "name_eng": "Player", + "name_rus": "Плеер" + }, + "position": { + "id": 23, + "source_type": "Mobile", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 5, + "duration": 12000, + "time_close": 1, + "media": { + "url": "https://i.imgur.com/PyZwEDq.png" + }, + "remaining_views": 10 + }, + // { + // "id": 93, + // "name": "Test 24", + // "type": { + // "id": 3, + // "name_eng": "Player", + // "name_rus": "Плеер" + // }, + // "position": { + // "id": 24, + // "source_type": "Mobile", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 5, + // "duration": 12000, + // "time_close": 1, + // "media": { + // "url": "https://i.imgur.com/iwihMdx.png" + // }, + // "remaining_views": 10 + // }, + ], + "match_cell": [ + { + "id": 71, + "name": "Test 2", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 1, + "source_type": "Web", + "name_eng": "Web main ad 2 (1x1)", + "name_rus": "Веб: главная 2 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 2, + "duration": 15, + "time_close": 15, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/71/en/web.png" + }, + "remaining_views": 9 + }, + { + "id": 71, + "name": "Test 2", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 2, + "source_type": "Web", + "name_eng": "Web main ad 2 (1x1)", + "name_rus": "Веб: главная 2 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 2, + "duration": 12, + "time_close": 15, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/71/en/web.png" + }, + "remaining_views": 9 + }, + { + "id": 72, + "name": "Test 3", + "type": { + "id": 1, + "name_eng": "Main", + "name_rus": "Главная" + }, + "position": { + "id": 3, + "source_type": "Web", + "name_eng": "Web main ad 7 (1x1)", + "name_rus": "Веб: главная 7 (1x1)" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 3, + "duration": 15, + "time_close": 15, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/72/en/web.png" + }, + "remaining_views": 9 + } + ], + "header": [ + // { + // "id": 77, + // "name": "Test 8", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 8, + // "source_type": "Web", + // "name_eng": "Web main ad 2 (3x1)", + // "name_rus": "Веб: главная 2(3x1)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 2, + // "duration": 120, + // "time_close": 15, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/77/en/web.png" + // }, + // "remaining_views": 10 + // }, + // { + // "id": 78, + // "name": "Test 9", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 9, + // "source_type": "Web", + // "name_eng": "Web main ad (6x1)", + // "name_rus": "Веб: главная (6x1)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 2, + // "duration": 10, + // "time_close": 15, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/78/en/web.png" + // }, + // "remaining_views": 15 + // }, + // { + // "id": 76, + // "name": "Test 7", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 7, + // "source_type": "Web", + // "name_eng": "Web main ad (3x1)", + // "name_rus": "Веб: главная (3x1)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 4, + // "duration": 10, + // "time_close": 15, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/76/en/web.png" + // }, + // "remaining_views": 15 + // } + ], + "block": [ + // { + // "id": 75, + // "name": "Test 6", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 6, + // "source_type": "Web", + // "name_eng": "Web main ad (2x2)", + // "name_rus": "Веб: главная (2x2)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 3, + // "duration": 120, + // "time_close": null, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/75/en/web.png" + // }, + // "remaining_views": 10 + // }, + // { + // "id": 73, + // "name": "Test 4", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 4, + // "source_type": "Web", + // "name_eng": "Web main ad (2x1)", + // "name_rus": "Веб: главная (2x1)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 1, + // "duration": 120, + // "time_close": null, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/73/en/web.png" + // }, + // "remaining_views": 9 + // }, + // { + // "id": 74, + // "name": "Test 5", + // "type": { + // "id": 1, + // "name_eng": "Main", + // "name_rus": "Главная" + // }, + // "position": { + // "id": 5, + // "source_type": "Web", + // "name_eng": "Web main ad (1x2)", + // "name_rus": "Веб: главная (1x2)" + // }, + // "link": null, + // "impressions": 10, + // "frequency": 2, + // "duration": 120000, + // "time_close": 1, + // "media": { + // "url": "https://cf-aws-staging.insports.tv/media/folder/74/en/web.png" + // }, + // "remaining_views": 9 + // } + ], + "match": [ + // { + // "id": 82, + // "name": "Test 13", + // "type": { + // "id": 2, + // "name_eng": "Match", + // "name_rus": "Матч" + // }, + // "position": { + // "id": 13, + // "source_type": "Web", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 10, + // "duration": 10, + // "time_close": 3, + // "media": { + // "url": "https://i.imgur.com/B0odUkf.png" + // }, + // "remaining_views": 10 + // }, + // { + // "id": 83, + // "name": "Test 14", + // "type": { + // "id": 2, + // "name_eng": "Match", + // "name_rus": "Матч" + // }, + // "position": { + // "id": 14, + // "source_type": "Web", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 5, + // "duration": 12000, + // "time_close": 1, + // "media": { + // "url": "https://i.imgur.com/KcJhEcu.jpg" + // }, + // "remaining_views": 10 + // }, + { + "id": 84, + "name": "Test 15", + "type": { + "id": 2, + "name_eng": "Match", + "name_rus": "Матч" + }, + "position": { + "id": 15, + "source_type": "Web", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 10, + "duration": 5, + "time_close": 1, + "media": { + "url": "https://cf-aws-staging.insports.tv/media/folder/84/en/web.png" + }, + "remaining_views": 10 + }, + // { + // "id": 87, + // "name": "Test 18", + // "type": { + // "id": 3, + // "name_eng": "Player", + // "name_rus": "Плеер" + // }, + // "position": { + // "id": 18, + // "source_type": "Web", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 100, + // "duration": 12000, + // "time_close": 1, + // "media": { + // "url": "https://i.imgur.com/xWlogZt.png" + // }, + // "remaining_views": 10 + // }, + // { + // "id": 88, + // "name": "Test 19", + // "type": { + // "id": 3, + // "name_eng": "Player", + // "name_rus": "Плеер" + // }, + // "position": { + // "id": 19, + // "source_type": "Web", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 100, + // "duration": 12000, + // "time_close": 1, + // "media": { + // "url": "https://i.imgur.com/u9cfGGs.png" + // }, + // "remaining_views": 10 + // }, + // { + // "id": 89, + // "name": "Test 20", + // "type": { + // "id": 3, + // "name_eng": "Player", + // "name_rus": "Плеер" + // }, + // "position": { + // "id": 20, + // "source_type": "Web", + // "name_eng": "Web top side ad horizontal", + // "name_rus": "Веб: верхняя, боковая, по горизонтали" + // }, + // "link": "https://www.google.com/", + // "impressions": 10, + // "frequency": 100, + // "duration": 12000, + // "time_close": 1, + // "media": { + // "url": "https://i.imgur.com/XP1ZIQC.png" + // }, + // "remaining_views": 10 + // }, + // + { + "id": 90, + "name": "Test 21", + "type": { + "id": 3, + "name_eng": "Player", + "name_rus": "Плеер" + }, + "position": { + "id": 21, + "source_type": "Web", + "name_eng": "Web top side ad horizontal", + "name_rus": "Веб: верхняя, боковая, по горизонтали" + }, + "link": "https://www.google.com/", + "impressions": 10, + "frequency": 5, + "duration": 10, + "time_close": 3, + "media": { + "url": "https://i.imgur.com/PaiZdTd.png" + }, + "remaining_views": 10 + }, + ], + } +} diff --git a/src/utilits/mirage/fixtures/index.tsx b/src/utilits/mirage/fixtures/index.tsx new file mode 100644 index 00000000..b1fcdff4 --- /dev/null +++ b/src/utilits/mirage/fixtures/index.tsx @@ -0,0 +1,2 @@ +export * from './getAds' +export * from './surveys' diff --git a/src/utilits/mirage/models/index.tsx b/src/utilits/mirage/models/index.tsx new file mode 100644 index 00000000..d4274eff --- /dev/null +++ b/src/utilits/mirage/models/index.tsx @@ -0,0 +1,8 @@ +/* eslint-disable */ +import { Model } from 'miragejs' +import type { ResponseType, AdResponse } from 'requests' + +export const models = { + ads: Model.extend>({}), + surveys: Model.extend>({}), +} diff --git a/src/utilits/mirage/server.ts b/src/utilits/mirage/server.ts new file mode 100644 index 00000000..ed3b2b49 --- /dev/null +++ b/src/utilits/mirage/server.ts @@ -0,0 +1,44 @@ +/* eslint-disable */ +import { + createServer, +} from 'miragejs' + +import { + ADS_API_URL, + APIS, + AUTH_SERVICE, + STATS_API_URL, + URL_AWS, + VIEWS_API, +} from 'config' +import { API_ROOT } from 'features/AuthServiceApp/config/routes' + +import { surveys, getAds } from './fixtures' +import { models } from './models' + + +const mainDomain = 'insports.tv' +export function makeServer({ environment = 'test' } = {}) { + const server = createServer({ + environment, + fixtures: { + surveys, + ads: getAds(), + }, + models: models, + routes() { + this.passthrough(`${API_ROOT}/***`) + this.passthrough(`${VIEWS_API}/***`) + this.passthrough(`${STATS_API_URL}/***`) + this.passthrough(`${APIS.production.api}/***`) + this.passthrough(`${APIS.staging.api}/***`) + this.passthrough(`${AUTH_SERVICE}/***`) + this.passthrough(`https://${mainDomain}/***`) + this.passthrough(`https://images.${mainDomain}/***`) + this.passthrough(`${URL_AWS}/***`) + this.post(`${ADS_API_URL}`, getAds) + this.logging = true; + }, + }) + return server +}