Preprod (#470)
* feat(ott-1503): connecting events (#464) * feat(ott-1503): connecting events * fix(ott-1503): pr fixes Co-authored-by: boyvanov <boyvanov.sergey@gmail.com> * feat(ott-1293): add matchpage for unauthenticated users (#465) * feat(ott-1293): add matchpage for unauthenticated users * feat(ott-1293): fix pr * Ott 1553 fix loading indicator in payment (#466) * fix(#1553): fix arrow loader in page cards * fix(#1553): delete env file * feat(#1576): added technical support widget (#468) Co-authored-by: boyvanov <50294488+boyvanov@users.noreply.github.com> Co-authored-by: boyvanov <boyvanov.sergey@gmail.com> Co-authored-by: PolyakovaM <55061222+PolyakovaM@users.noreply.github.com> Co-authored-by: Andrei Dekterev <57942757+dekterev@users.noreply.github.com> Co-authored-by: Иван Пиминов <61900450+ivan-piminov@users.noreply.github.com>keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
parent
88cdcb9d58
commit
bb756f4109
|
After Width: | Height: | Size: 343 KiB |
|
After Width: | Height: | Size: 340 KiB |
|
After Width: | Height: | Size: 326 KiB |
@ -0,0 +1,6 @@ |
||||
export const joinMatchLexics = { |
||||
join_instat_tv: 15420, |
||||
join_now: 15422, |
||||
promo_text: 15421, |
||||
watch_live: 15423, |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
import toNumber from 'lodash/toNumber' |
||||
import isUndefined from 'lodash/isUndefined' |
||||
|
||||
export const isMatchPage = () => { |
||||
const splitPath = window.location.pathname.split('/') |
||||
const pageType = splitPath[2] |
||||
const matchId = toNumber(splitPath[3]) |
||||
|
||||
return pageType === 'matches' && !isUndefined(matchId) |
||||
} |
||||
@ -0,0 +1,48 @@ |
||||
import type { FormEvent } from 'react' |
||||
import { |
||||
useEffect, |
||||
useState, |
||||
} from 'react' |
||||
|
||||
import format from 'date-fns/format' |
||||
|
||||
import type { UnauthenticatedMatch } from 'requests' |
||||
import { getUnauthenticatedMatch } from 'requests' |
||||
|
||||
import { usePageParams } from 'hooks/usePageParams' |
||||
|
||||
import { useLexicsStore } from 'features/LexicsStore' |
||||
import { getName } from 'features/Name' |
||||
import { useAuthStore } from 'features/AuthStore' |
||||
|
||||
export const useUnauthenticatedMatch = () => { |
||||
const [ |
||||
matchInfo, setMatchInfo, |
||||
] = useState<UnauthenticatedMatch>(null) |
||||
|
||||
const { suffix } = useLexicsStore() |
||||
const { profileId: matchId, sportType } = usePageParams() |
||||
|
||||
const teamName1 = getName({ nameObj: matchInfo?.team1 || {}, suffix }) |
||||
const teamName2 = getName({ nameObj: matchInfo?.team2 || {}, suffix }) |
||||
|
||||
const date = matchInfo?.date |
||||
const matchDate = (date && format(new Date(date), 'd MMM HH:mm')) || '' |
||||
|
||||
const { login } = useAuthStore() |
||||
const handleSubmit = (event: FormEvent<HTMLFormElement>) => { |
||||
event.preventDefault() |
||||
login() |
||||
} |
||||
|
||||
useEffect(() => { |
||||
getUnauthenticatedMatch(sportType, matchId).then(setMatchInfo) |
||||
}, [sportType, matchId]) |
||||
|
||||
return { |
||||
handleSubmit, |
||||
matchDate, |
||||
teamName1, |
||||
teamName2, |
||||
} |
||||
} |
||||
@ -0,0 +1,90 @@ |
||||
import format from 'date-fns/format' |
||||
|
||||
import { joinMatchLexics } from 'config/lexics/joinMatch' |
||||
|
||||
import { usePageParams } from 'hooks/usePageParams' |
||||
|
||||
import { T9n } from 'features/T9n' |
||||
import { useLexicsConfig } from 'features/LexicsStore' |
||||
|
||||
import { useUnauthenticatedMatch } from './hooks' |
||||
|
||||
import { |
||||
Wrapper, |
||||
MainLogo, |
||||
HeaderWrapper, |
||||
Footer, |
||||
BlockWrapper, |
||||
MatchInfo, |
||||
SportImgWrapper, |
||||
DateInfoWrapper, |
||||
DateInfo, |
||||
WatchLive, |
||||
TeamsNameWrapper, |
||||
MainInfoTitle, |
||||
MainInfoButton, |
||||
MainInfoText, |
||||
EmptySpan, |
||||
WatchLiveCircle, |
||||
WatchLiveText, |
||||
SportImgMobileDevice, |
||||
FooterLogo, |
||||
FooterRights, |
||||
} from './styled' |
||||
|
||||
export const JoinMatchPage = () => { |
||||
useLexicsConfig(joinMatchLexics) |
||||
|
||||
const { sportType } = usePageParams() |
||||
const { |
||||
handleSubmit, |
||||
matchDate, |
||||
teamName1, |
||||
teamName2, |
||||
} = useUnauthenticatedMatch() |
||||
|
||||
const currentYear = format(new Date(), 'Y') |
||||
|
||||
return ( |
||||
<Wrapper> |
||||
<HeaderWrapper> |
||||
<MainLogo /> |
||||
</HeaderWrapper> |
||||
<BlockWrapper> |
||||
<SportImgWrapper sportType={sportType} /> |
||||
<MatchInfo> |
||||
<DateInfoWrapper> |
||||
<DateInfo>{matchDate}</DateInfo> |
||||
<WatchLive> |
||||
<WatchLiveCircle /> |
||||
<WatchLiveText> |
||||
<T9n t='watch_live' /> |
||||
</WatchLiveText> |
||||
</WatchLive> |
||||
</DateInfoWrapper> |
||||
<TeamsNameWrapper> |
||||
<EmptySpan>{teamName1}</EmptySpan> |
||||
<EmptySpan> — </EmptySpan> |
||||
<EmptySpan>{teamName2}</EmptySpan> |
||||
</TeamsNameWrapper> |
||||
<MainInfoTitle> |
||||
<T9n t='join_instat_tv' /> |
||||
</MainInfoTitle> |
||||
<SportImgMobileDevice sportType={sportType} /> |
||||
<MainInfoText> |
||||
<T9n t='promo_text' /> |
||||
</MainInfoText> |
||||
<form onSubmit={handleSubmit}> |
||||
<MainInfoButton type='submit'> |
||||
<T9n t='join_now' /> |
||||
</MainInfoButton> |
||||
</form> |
||||
</MatchInfo> |
||||
</BlockWrapper> |
||||
<Footer> |
||||
<FooterLogo /> |
||||
<FooterRights>©InStat TV {currentYear}</FooterRights> |
||||
</Footer> |
||||
</Wrapper> |
||||
) |
||||
} |
||||
@ -0,0 +1,258 @@ |
||||
import styled, { css } from 'styled-components/macro' |
||||
|
||||
import { devices, SportTypes } from 'config' |
||||
import { isMobileDevice } from 'config/userAgent' |
||||
|
||||
import { ButtonSolid } from 'features/Common' |
||||
import { Logo } from 'features/Logo' |
||||
|
||||
type Props = { |
||||
sportType: SportTypes, |
||||
} |
||||
|
||||
export const Wrapper = styled.div` |
||||
width: 100vw; |
||||
height: 100vh; |
||||
color: white; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: space-between; |
||||
` |
||||
|
||||
export const HeaderWrapper = styled.div` |
||||
background-color: #13151B; |
||||
padding: 20px 0; |
||||
padding-left: 20%; |
||||
width: 100%; |
||||
@media ${devices.laptop} { |
||||
padding-left: 5%; |
||||
} |
||||
${isMobileDevice |
||||
? css` |
||||
display: none; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const MainLogo = styled(Logo)` |
||||
height: 20px; |
||||
width: 80px; |
||||
` |
||||
|
||||
export const BlockWrapper = styled.div` |
||||
height: 100%; |
||||
display: flex; |
||||
align-items: center; |
||||
padding-left: 20%; |
||||
width: 100%; |
||||
@media ${devices.laptop} { |
||||
padding-left: 5%; |
||||
} |
||||
@media ${devices.mobile} { |
||||
padding-left: 5.4rem; |
||||
} |
||||
${isMobileDevice |
||||
? css` |
||||
padding: 5.4rem; |
||||
overflow: scroll; |
||||
@media screen and (orientation: landscape){ |
||||
padding-top: 20px; |
||||
height: auto; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const SportImgWrapper = styled.div<Props>` |
||||
background-image: url(/images/landing_${({ sportType }) => sportType}.png); |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
background-size: contain; |
||||
width: 512px; |
||||
height: 641px; |
||||
margin-right: 5%; |
||||
${isMobileDevice |
||||
? css` |
||||
display: none; |
||||
@media screen and (orientation: landscape){ |
||||
display: block; |
||||
height: 100%; |
||||
width: 70%; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const MatchInfo = styled.div` |
||||
${isMobileDevice |
||||
? css` |
||||
width: 100%; |
||||
height: 100%; |
||||
@media screen and (orientation: landscape){ |
||||
padding-top: 0; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const DateInfoWrapper = styled.div` |
||||
display: flex; |
||||
align-items: center; |
||||
font-size: 15px; |
||||
font-weight: 600; |
||||
${isMobileDevice |
||||
? css` |
||||
justify-content: space-between; |
||||
font-size: 14px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const DateInfo = styled.div` |
||||
text-transform: uppercase; |
||||
background-color: rgba(0,0,0,0.4); |
||||
padding: 8px 25px; |
||||
color: #B9B9B9; |
||||
margin-right: 25px; |
||||
border-radius: 5px; |
||||
${isMobileDevice |
||||
? css` |
||||
padding: 0.7em 2.5rem; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const WatchLive = styled.div` |
||||
display: flex; |
||||
align-items: center; |
||||
` |
||||
|
||||
export const WatchLiveText = styled.div` |
||||
color: #EB5757; |
||||
letter-spacing: .2rem; |
||||
` |
||||
|
||||
export const WatchLiveCircle = styled.div` |
||||
width: 20px; |
||||
height: 20px; |
||||
border-radius: 50%; |
||||
background-color: #CC0000; |
||||
margin-right: 5px; |
||||
${isMobileDevice |
||||
? css` |
||||
width: 15px; |
||||
height: 15px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const TeamsNameWrapper = styled.div` |
||||
margin: 35px 0 40px; |
||||
font-size: 20px; |
||||
font-weight: 500; |
||||
${isMobileDevice |
||||
? css` |
||||
margin: 10px 0; |
||||
font-size: 16px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const MainInfoTitle = styled.div` |
||||
font-weight: 600; |
||||
font-size: 46px; |
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 32px; |
||||
margin-bottom: 15px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const MainInfoButton = styled(ButtonSolid)` |
||||
width: 260px; |
||||
height: 50px; |
||||
font-size: 20px; |
||||
${isMobileDevice |
||||
? css` |
||||
width: 100%; |
||||
border-radius: 10px; |
||||
font-size: 17px; |
||||
margin-bottom: 30px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const MainInfoText = styled.div` |
||||
max-width: 400px; |
||||
margin: 40px 0; |
||||
font-size: 17px; |
||||
line-height: 150%; |
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 15px; |
||||
margin: 15px 0 25px; |
||||
width: 85%; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const Footer = styled.div` |
||||
font-size: 14px; |
||||
background-color: black; |
||||
padding: 16px 0; |
||||
padding-left: 20%; |
||||
width: 100%; |
||||
@media ${devices.laptop} { |
||||
padding-left: 5%; |
||||
} |
||||
@media ${devices.mobile} { |
||||
padding-left: 35px; |
||||
} |
||||
${isMobileDevice |
||||
? css` |
||||
display: flex; |
||||
padding: 15px 35px; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const FooterLogo = styled(Logo)` |
||||
display: none; |
||||
${isMobileDevice |
||||
? css` |
||||
display: block; |
||||
width: 48px; |
||||
height: 11px; |
||||
opacity: .4; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const FooterRights = styled.div` |
||||
opacity: .5; |
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 12px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const SportImgMobileDevice = styled(SportImgWrapper)` |
||||
display: none; |
||||
${isMobileDevice |
||||
? css` |
||||
display: block; |
||||
height: 53%; |
||||
width: 100%; |
||||
margin-right: 0; |
||||
@media screen and (orientation: landscape){
|
||||
display: none; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const EmptySpan = styled.span`` |
||||
@ -0,0 +1,28 @@ |
||||
import { useEffect, useState } from 'react' |
||||
|
||||
import type { Events } from 'requests' |
||||
import { getMatchEvents } from 'requests' |
||||
|
||||
import { usePageParams } from 'hooks/usePageParams' |
||||
|
||||
import { useEventsLexics } from './useEventsLexics' |
||||
|
||||
export const useEvents = () => { |
||||
const [events, setEvents] = useState<Events>([]) |
||||
const { fetchLexics } = useEventsLexics() |
||||
const { profileId: matchId, sportType } = usePageParams() |
||||
|
||||
useEffect(() => { |
||||
getMatchEvents({ |
||||
matchId, |
||||
sportType, |
||||
}).then(fetchLexics) |
||||
.then(setEvents) |
||||
}, [ |
||||
fetchLexics, |
||||
matchId, |
||||
sportType, |
||||
]) |
||||
|
||||
return { events } |
||||
} |
||||
@ -0,0 +1,25 @@ |
||||
import { useCallback } from 'react' |
||||
|
||||
import isEmpty from 'lodash/isEmpty' |
||||
import map from 'lodash/map' |
||||
import uniq from 'lodash/uniq' |
||||
|
||||
import type { Events } from 'requests' |
||||
|
||||
import { useLexicsStore } from 'features/LexicsStore' |
||||
|
||||
export const useEventsLexics = () => { |
||||
const { addLexicsConfig } = useLexicsStore() |
||||
|
||||
const fetchLexics = useCallback((events: Events) => { |
||||
const lexics = uniq(map(events, ({ l }) => l)) |
||||
|
||||
if (!isEmpty(lexics)) { |
||||
addLexicsConfig(lexics) |
||||
} |
||||
|
||||
return events |
||||
}, [addLexicsConfig]) |
||||
|
||||
return { fetchLexics } |
||||
} |
||||
@ -0,0 +1,88 @@ |
||||
import { ProfileTypes } from 'config' |
||||
|
||||
import type { Event, Team } from 'requests' |
||||
|
||||
import { usePageParams } from 'hooks/usePageParams' |
||||
|
||||
import type { PlayerPlaylistOption } from 'features/MatchPage/types' |
||||
import { Name } from 'features/Name' |
||||
import { T9n } from 'features/T9n' |
||||
|
||||
import { |
||||
Avatar, |
||||
Button, |
||||
EventInfo, |
||||
EventDesc, |
||||
Title, |
||||
SubTitle, |
||||
EventTime, |
||||
} from '../TabEvents/styled' |
||||
|
||||
type Props = { |
||||
active?: boolean, |
||||
disabled?: boolean, |
||||
event: Event, |
||||
isHomeTeam: boolean, |
||||
onClick: () => void, |
||||
player?: PlayerPlaylistOption, |
||||
team?: Team, |
||||
} |
||||
|
||||
export const EventButton = ({ |
||||
active, |
||||
disabled, |
||||
event, |
||||
isHomeTeam, |
||||
onClick, |
||||
player, |
||||
team, |
||||
}: Props) => { |
||||
const { sportType } = usePageParams() |
||||
const { |
||||
c: clearTime, |
||||
l: lexica, |
||||
p: playerId, |
||||
sc1: score1, |
||||
sc2: score2, |
||||
t: teamId, |
||||
} = event |
||||
|
||||
const avatarId = playerId || teamId |
||||
const profileType = playerId |
||||
? ProfileTypes.PLAYERS |
||||
: ProfileTypes.TEAMS |
||||
const nameObj = player || team |
||||
|
||||
return ( |
||||
<Button |
||||
onClick={onClick} |
||||
active={active} |
||||
disabled={disabled} |
||||
isHomeTeam={isHomeTeam} |
||||
> |
||||
{avatarId && ( |
||||
<Avatar |
||||
id={avatarId} |
||||
isHomeTeam={isHomeTeam} |
||||
isPlayer={Boolean(playerId)} |
||||
profileType={profileType} |
||||
sportType={sportType} |
||||
/> |
||||
)} |
||||
<EventInfo> |
||||
<EventTime> |
||||
{clearTime} |
||||
</EventTime> |
||||
<EventDesc> |
||||
<Title> |
||||
<T9n t={lexica} /> |
||||
{(score1 || score2) && ` (${score1}-${score2})`} |
||||
</Title> |
||||
<SubTitle> |
||||
{(playerId || teamId) && nameObj && <Name nameObj={nameObj} />} |
||||
</SubTitle> |
||||
</EventDesc> |
||||
</EventInfo> |
||||
</Button> |
||||
) |
||||
} |
||||
@ -0,0 +1,63 @@ |
||||
import find from 'lodash/find' |
||||
import map from 'lodash/map' |
||||
|
||||
import type { Events, MatchInfo } from 'requests' |
||||
|
||||
import type { PlaylistOption, Playlists } from 'features/MatchPage/types' |
||||
import { PlaylistTypes } from 'features/MatchPage/types' |
||||
|
||||
import { isEqual } from '../../helpers' |
||||
import { EventButton } from '../EventButton' |
||||
import { Event, List } from '../TabEvents/styled' |
||||
|
||||
type Props = { |
||||
events: Events, |
||||
onSelect: (option: PlaylistOption) => void, |
||||
playlists: Playlists, |
||||
profile: MatchInfo, |
||||
selectedPlaylist?: PlaylistOption, |
||||
} |
||||
|
||||
export const EventsList = ({ |
||||
events, |
||||
onSelect, |
||||
playlists, |
||||
profile, |
||||
selectedPlaylist, |
||||
}: Props) => ( |
||||
<List> |
||||
{map(events, (event) => { |
||||
const eventPlaylist = { |
||||
data: [{ |
||||
e: event.e, |
||||
h: event.h, |
||||
s: event.s, |
||||
}], |
||||
id: event.n, |
||||
type: PlaylistTypes.EVENT, |
||||
} as PlaylistOption |
||||
|
||||
const isHomeTeam = event.t === profile?.team1.id |
||||
const team = isHomeTeam |
||||
? profile?.team1 |
||||
: profile?.team2 |
||||
const players = isHomeTeam |
||||
? playlists.players.team1 |
||||
: playlists.players.team2 |
||||
const player = find(players, { id: event.p }) |
||||
|
||||
return ( |
||||
<Event key={event.n}> |
||||
<EventButton |
||||
active={isEqual(eventPlaylist, selectedPlaylist)} |
||||
event={event} |
||||
isHomeTeam={isHomeTeam} |
||||
onClick={() => onSelect(eventPlaylist)} |
||||
player={player} |
||||
team={team} |
||||
/> |
||||
</Event> |
||||
) |
||||
})} |
||||
</List> |
||||
) |
||||
@ -0,0 +1,119 @@ |
||||
import { Fragment, useMemo } from 'react' |
||||
|
||||
import groupBy from 'lodash/groupBy' |
||||
import isEmpty from 'lodash/isEmpty' |
||||
import map from 'lodash/map' |
||||
import reverse from 'lodash/reverse' |
||||
import values from 'lodash/values' |
||||
|
||||
import type { Events, MatchInfo } from 'requests' |
||||
|
||||
import { useToggle } from 'hooks' |
||||
|
||||
import type { PlaylistOption, Playlists } from 'features/MatchPage/types' |
||||
import { T9n } from 'features/T9n' |
||||
|
||||
import { EventsList } from '../EventsList' |
||||
import { |
||||
BlockTitle, |
||||
Wrapper, |
||||
HalfList, |
||||
HalfEvents, |
||||
Tabs, |
||||
Tab, |
||||
} from './styled' |
||||
|
||||
type Props = { |
||||
events: Events, |
||||
onSelect: (option: PlaylistOption) => void, |
||||
playlists: Playlists, |
||||
profile: MatchInfo, |
||||
selectedPlaylist?: PlaylistOption, |
||||
} |
||||
|
||||
export const TabEvents = ({ |
||||
events, |
||||
onSelect, |
||||
playlists, |
||||
profile, |
||||
selectedPlaylist, |
||||
}: Props) => { |
||||
const { |
||||
close: setUnreversed, |
||||
isOpen: areEventsReversed, |
||||
open: setReversed, |
||||
} = useToggle() |
||||
|
||||
const groupedEvents = useMemo(() => values( |
||||
groupBy( |
||||
areEventsReversed ? reverse([...events]) : events, |
||||
'h', |
||||
), |
||||
), [areEventsReversed, events]) |
||||
|
||||
if (!profile) return null |
||||
|
||||
return ( |
||||
<Wrapper> |
||||
{isEmpty(events) |
||||
? ( |
||||
<BlockTitle> |
||||
<T9n t='no_data' /> |
||||
</BlockTitle> |
||||
) |
||||
: ( |
||||
<Fragment> |
||||
<Tabs> |
||||
<Tab |
||||
active={!areEventsReversed} |
||||
onClick={setUnreversed} |
||||
> |
||||
<T9n t='from_start_match' /> |
||||
</Tab> |
||||
<Tab |
||||
active={areEventsReversed} |
||||
onClick={setReversed} |
||||
> |
||||
<T9n t='from_end_match' /> |
||||
</Tab> |
||||
</Tabs> |
||||
<HalfList> |
||||
{ |
||||
map( |
||||
areEventsReversed |
||||
? reverse(groupedEvents) |
||||
: groupedEvents, |
||||
(halfEvents, idx) => { |
||||
const firstEvent = halfEvents[0] |
||||
const isFirstBlock = idx === 0 |
||||
|
||||
return ( |
||||
<HalfEvents key={firstEvent.h}> |
||||
{ |
||||
!isFirstBlock && ( |
||||
<BlockTitle> |
||||
<T9n t='half_time' /> |
||||
</BlockTitle> |
||||
) |
||||
} |
||||
<BlockTitle> |
||||
<T9n t={firstEvent.l} /> |
||||
</BlockTitle> |
||||
<EventsList |
||||
events={halfEvents} |
||||
onSelect={onSelect} |
||||
playlists={playlists} |
||||
profile={profile} |
||||
selectedPlaylist={selectedPlaylist} |
||||
/> |
||||
</HalfEvents> |
||||
) |
||||
}, |
||||
) |
||||
} |
||||
</HalfList> |
||||
</Fragment> |
||||
)} |
||||
</Wrapper> |
||||
) |
||||
} |
||||
@ -0,0 +1,143 @@ |
||||
import styled, { css } from 'styled-components/macro' |
||||
|
||||
import { ProfileLogo } from 'features/ProfileLogo' |
||||
|
||||
import { Tabs as TabsBase, Tab as TabBase } from '../PlayersPlaylists/styled' |
||||
import { |
||||
BlockTitle as BlockTitleBase, |
||||
Button as ButtonBase, |
||||
} from '../../styled' |
||||
|
||||
export const Wrapper = styled.div` |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
` |
||||
|
||||
export const HalfList = styled.ul` |
||||
width: 100%; |
||||
` |
||||
|
||||
export const HalfEvents = styled.li` |
||||
:not(:last-child) { |
||||
margin-bottom: 12px; |
||||
} |
||||
` |
||||
|
||||
export const List = styled.ul` |
||||
margin-top: 12px; |
||||
` |
||||
|
||||
export const Event = styled.li` |
||||
width: 100%; |
||||
height: 48px; |
||||
|
||||
:not(:last-child) { |
||||
margin-bottom: 12px; |
||||
} |
||||
` |
||||
|
||||
type AvatarProps = { |
||||
isHomeTeam: boolean, |
||||
isPlayer: boolean, |
||||
} |
||||
|
||||
export const Avatar = styled(ProfileLogo)<AvatarProps>` |
||||
position: absolute; |
||||
width: 35px; |
||||
height: 43px; |
||||
object-fit: cover; |
||||
|
||||
${({ isHomeTeam }) => ( |
||||
isHomeTeam |
||||
? css`left: 5px;` |
||||
: css`right: 5px;` |
||||
)} |
||||
|
||||
${({ isPlayer }) => ( |
||||
isPlayer |
||||
? css`bottom: 0;` |
||||
: css` |
||||
top: 50%; |
||||
transform: translateY(-50%); |
||||
` |
||||
)} |
||||
` |
||||
|
||||
export const EventInfo = styled.div` |
||||
display: flex; |
||||
width: 100%; |
||||
` |
||||
|
||||
export const EventDesc = styled.div` |
||||
position: relative; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: flex-start; |
||||
overflow: hidden; |
||||
white-space: nowrap; |
||||
text-overflow: ellipsis; |
||||
` |
||||
|
||||
export const Title = styled.span` |
||||
font-weight: 600; |
||||
font-size: 14px; |
||||
line-height: 15px; |
||||
color: #ffffff; |
||||
width: 100%; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
text-align: left; |
||||
` |
||||
|
||||
export const SubTitle = styled(Title)` |
||||
font-size: 10px; |
||||
line-height: 16px; |
||||
font-weight: normal; |
||||
color: rgba(255, 255, 255, 0.7); |
||||
margin-top: 2px; |
||||
` |
||||
|
||||
export const EventTime = styled(Title)` |
||||
font-size: 14px; |
||||
font-weight: normal; |
||||
margin-right: 10px; |
||||
width: auto; |
||||
overflow: initial; |
||||
min-width: 29px; |
||||
` |
||||
|
||||
export const Tabs = styled(TabsBase)` |
||||
margin-top: 0px; |
||||
margin-bottom: 18px; |
||||
` |
||||
|
||||
export const Tab = styled(TabBase)` |
||||
text-transform: none; |
||||
|
||||
:first-child { |
||||
margin-right: 15px; |
||||
} |
||||
` |
||||
|
||||
export const BlockTitle = styled(BlockTitleBase)` |
||||
text-align: center; |
||||
width: 100%; |
||||
display: inline-block; |
||||
` |
||||
|
||||
type ButtonProps = { |
||||
isHomeTeam: boolean, |
||||
} |
||||
|
||||
export const Button = styled(ButtonBase)<ButtonProps>` |
||||
&:hover ${EventDesc} { |
||||
overflow: visible; |
||||
} |
||||
|
||||
${({ isHomeTeam }) => ( |
||||
isHomeTeam |
||||
? css`padding-left: 60px;` |
||||
: css`padding: 0 40px 0 60px;` |
||||
)} |
||||
` |
||||
@ -0,0 +1,69 @@ |
||||
import { |
||||
DATA_URL, |
||||
PROCEDURES, |
||||
SportTypes, |
||||
} from 'config' |
||||
|
||||
import { Episode, Episodes } from 'requests' |
||||
|
||||
import { callApi, getSportLexic } from 'helpers' |
||||
|
||||
const proc = PROCEDURES.ott_match_events |
||||
|
||||
type Args = { |
||||
matchId: number, |
||||
sportType: SportTypes, |
||||
} |
||||
|
||||
export type Event = Episode & { |
||||
/** clear time */ |
||||
c: string, |
||||
|
||||
/** event lexic */ |
||||
l: number, |
||||
|
||||
/** event id */ |
||||
n: number, |
||||
|
||||
/** player id */ |
||||
p?: number, |
||||
|
||||
/** repeat */ |
||||
rep?: Episodes, |
||||
|
||||
/** score team1 */ |
||||
sc1?: number, |
||||
|
||||
/** score team2 */ |
||||
sc2?: number, |
||||
|
||||
/** team id */ |
||||
t?: number, |
||||
} |
||||
|
||||
export type Events = Array<Event> |
||||
|
||||
type Response = { |
||||
data?: Events, |
||||
} |
||||
|
||||
export const getMatchEvents = async ({ |
||||
matchId, |
||||
sportType, |
||||
}: Args) => { |
||||
const config = { |
||||
body: { |
||||
params: { |
||||
_p_match_id: matchId, |
||||
}, |
||||
proc, |
||||
}, |
||||
} |
||||
|
||||
const response: Response = await callApi({ |
||||
config, |
||||
url: `${DATA_URL}/${getSportLexic(sportType)}`, |
||||
}) |
||||
|
||||
return response?.data || [] |
||||
} |
||||
@ -0,0 +1,42 @@ |
||||
import { |
||||
DATA_URL, |
||||
PROCEDURES, |
||||
SportTypes, |
||||
} from 'config' |
||||
|
||||
import { callApi } from 'helpers' |
||||
|
||||
const proc = PROCEDURES.landing_get_match_info |
||||
|
||||
type Team = { |
||||
name_eng: string, |
||||
name_rus: string, |
||||
} |
||||
|
||||
export type UnauthenticatedMatch = { |
||||
date: string, |
||||
team1: Team, |
||||
team2: Team, |
||||
tournament: { |
||||
name_eng: string, |
||||
name_rus: string, |
||||
}, |
||||
} | null |
||||
|
||||
export const getUnauthenticatedMatch = (sportId: SportTypes, matchId: number) |
||||
: Promise<UnauthenticatedMatch> => { |
||||
const config = { |
||||
body: { |
||||
params: { |
||||
_p_match_id: matchId, |
||||
_p_sport: sportId, |
||||
}, |
||||
proc, |
||||
}, |
||||
} |
||||
|
||||
return callApi({ |
||||
config, |
||||
url: DATA_URL, |
||||
}) |
||||
} |
||||
Loading…
Reference in new issue