feat(#168): add video download process

andreidekterev 3 years ago
parent d07278d785
commit 54f12db5b7
  1. 4
      src/config/lexics/matchDownload.tsx
  2. 1
      src/config/queries.tsx
  3. 98
      src/features/MatchPage/components/MatchDownloadPopup/index.tsx
  4. 23
      src/features/MatchPage/components/MatchDownloadPopup/styled.tsx
  5. 59
      src/features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification.tsx
  6. 49
      src/features/MatchSidePlaylists/components/DownloadNotification/styled.tsx
  7. 6
      src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx
  8. 17
      src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx
  9. 17
      src/features/MatchSidePlaylists/styled.tsx
  10. 38
      src/requests/downloadPlaylist.tsx

@ -1,8 +1,12 @@
export const matchDownload = { export const matchDownload = {
can_close: 20238,
choose_what_to_download: 20193, choose_what_to_download: 20193,
download_files_for_periods: 20197, download_files_for_periods: 20197,
download_full_match: 20198, download_full_match: 20198,
download_single_file: 20196, download_single_file: 20196,
entire_record: 20195, entire_record: 20195,
error_message: 20240,
in_game_time_only: 20194, in_game_time_only: 20194,
processed: 20200,
will_notified: 20239,
} }

@ -1,4 +1,5 @@
export const querieKeys = { export const querieKeys = {
downloadPlaylist: 'downloadPlaylist',
liveMatchScores: 'liveMatchScores', liveMatchScores: 'liveMatchScores',
matchScore: 'matchScore', matchScore: 'matchScore',
sportsList: 'sportsList', sportsList: 'sportsList',

@ -1,7 +1,18 @@
import { useState } from 'react' import { useState } from 'react'
import { useQuery } from 'react-query'
import { T9n } from 'features/T9n' import { T9n } from 'features/T9n'
import { usePageParams } from 'hooks'
import { querieKeys } from 'config'
import {
downloadPlaylist,
type DownloadPlaylistProps,
} from 'requests/downloadPlaylist'
import { Radio } from 'features/Common'
import { import {
Header, Header,
Footer, Footer,
@ -13,20 +24,73 @@ import {
FirstTitle, FirstTitle,
SecondTitle, SecondTitle,
RadioButtonsWrapper, RadioButtonsWrapper,
Input,
Label, Label,
} from './styled' } from './styled'
type Props = { type Props = {
closePopup: () => void, closePopup: () => void,
isModalOpen: boolean, isModalOpen: boolean,
openDownloadNotification: () => void,
}
const fileType: Record<'download_single_file'| 'download_files_for_periods', string> = {
download_files_for_periods: 'download_files_for_periods',
download_single_file: 'download_single_file',
}
const initialRadioBtns: Record<string, boolean> = {
// надо именно такую сортировку
in_game_time_only: true,
// eslint-disable-next-line sort-keys
entire_record: false,
} }
export const MatchDownloadPopup = ({ export const MatchDownloadPopup = ({
closePopup, closePopup,
isModalOpen, isModalOpen,
openDownloadNotification,
}: Props) => { }: Props) => {
const [selected, setSelected] = useState(true) const [downloadConfig, setDownloadConfig] = useState<typeof initialRadioBtns>(initialRadioBtns)
const { profileId: match_id, sportType: sport_id } = usePageParams()
useQuery(
querieKeys.downloadPlaylist,
() => handleDownload(fileType.download_files_for_periods),
{
enabled: false, // disable this query from automatically running
refetchOnWindowFocus: false,
},
)
const handleDownload = async (id = fileType.download_single_file) => {
const config: DownloadPlaylistProps = {
ball_in_play: downloadConfig.entire_record,
match_id,
sport_id,
}
if (downloadConfig.entire_record) {
config.concat = fileType.download_single_file === id
}
try {
const links = await downloadPlaylist(config)
closePopup()
openDownloadNotification()
return links
} catch (e) {
return null
}
}
const handleChange = (id: string) => {
setDownloadConfig((prev) => Object.keys(prev)
.reduce((result: typeof initialRadioBtns, key: keyof typeof initialRadioBtns) => ({
...result,
[key]: id === key,
}), {} as typeof initialRadioBtns))
}
return ( return (
<Modal <Modal
@ -42,28 +106,28 @@ export const MatchDownloadPopup = ({
</HeaderTitle> </HeaderTitle>
</Header> </Header>
<RadioButtonsWrapper> <RadioButtonsWrapper>
{Object.entries(downloadConfig).map(([id, checked], index) => (
<Label> <Label>
<Input <Radio
defaultChecked={selected} name={id}
name='in_game_time_only' key={id}
onClick={() => setSelected(true)} checked={checked}
/> onChange={(e) => handleChange(e.target.name)}
<T9n t='in_game_time_only' />
</Label>
<Label>
<Input
name='entire_record'
defaultChecked={!selected}
onClick={() => setSelected(false)}
/> />
<T9n t='entire_record' /> <T9n t={id} />
</Label> </Label>
))}
</RadioButtonsWrapper> </RadioButtonsWrapper>
<Footer> <Footer>
<ScApplyButton> <ScApplyButton
onClick={() => handleDownload(fileType.download_single_file)}
>
<T9n t='download_single_file' /> <T9n t='download_single_file' />
</ScApplyButton> </ScApplyButton>
<ScApplyButton disabled={!selected}> <ScApplyButton
disabled={!downloadConfig.entire_record}
onClick={() => handleDownload(fileType.download_files_for_periods)}
>
<T9n t='download_files_for_periods' /> <T9n t='download_files_for_periods' />
</ScApplyButton> </ScApplyButton>
</Footer> </Footer>

@ -100,29 +100,6 @@ export const Label = styled.label`
font-size: 14px;` font-size: 14px;`
: ''}; : ''};
` `
export const Input = styled.input.attrs(() => ({
type: 'radio',
}))`
margin: 0 25px 0 0;
appearance: none;
width: 25px;
height: 25px;
cursor: pointer;
background-image: url(/images/${({ defaultChecked }) => (
defaultChecked
? 'checkedRadiobutton.png'
: 'radiobutton.png'
)});
${isMobileDevice
? css`
margin-right: 10px;`
: ''};
`
export const Footer = styled.div`` export const Footer = styled.div``
export const ScApplyButton = styled(ApplyButton)` export const ScApplyButton = styled(ApplyButton)`

@ -0,0 +1,59 @@
import { useQueryClient } from 'react-query'
import { T9n } from 'features/T9n'
import { querieKeys } from 'config'
import { DownloadResponse } from 'requests/downloadPlaylist'
import {
Container,
Description,
Title,
CloseBtn,
Header,
MainContainer,
LinkToDownload,
Error,
} from './styled'
type TDownloadNotification = {
close: () => void,
}
export const DownloadNotification = ({ close }:TDownloadNotification) => {
const client = useQueryClient()
const data = client.getQueryData<DownloadResponse>(querieKeys.downloadPlaylist)
return (
<Container>
<Header>
<CloseBtn
onClick={close}
/>
</Header>
<MainContainer>
<Title>
<T9n t='processed' />
</Title>
<Description>
{data?.status === 'ERROR'
? (
<>
<T9n t='can_close' />&nbsp;
<T9n t='will_notified' />&nbsp;
<LinkToDownload href='/useraccount/downloads'>
My Videos
</LinkToDownload>
</>
) : (
<Error>
<T9n t='error_message' />
</Error>
)}
</Description>
</MainContainer>
</Container>
)
}

@ -0,0 +1,49 @@
import styled from 'styled-components/macro'
import { CloseButton } from 'features/PopupComponents'
export const Container = styled.section`
width: 100%;
border-radius: 0.125rem;
background: #333;
padding: 0.5rem 0.5rem ;
color: #FFF;
font-weight: 400;
line-height: normal;
font-size: 0.75rem;
margin-bottom: 0.45rem;
`
export const Title = styled.h3`
font-size: 0.875rem;
font-style: normal;
font-weight: 700;
line-height: 1.875rem;
margin-bottom: 0.56rem;
`
export const Description = styled.span`
`
export const CloseBtn = styled(CloseButton)`
padding: 4px;
`
export const Header = styled.header`
display: flex;
justify-content: end;
`
export const MainContainer = styled.main`
padding: 0.4rem 1.1rem 2rem 1.3rem;
`
export const LinkToDownload = styled.a`
text-decoration: underline;
cursor: pointer;
color: white;
font-weight: 600;
`
export const Error = styled.span`
color: red;
`

@ -14,7 +14,10 @@ import { usePageParams } from 'hooks/usePageParams'
import { Item } from '../MatchPlaylists' import { Item } from '../MatchPlaylists'
import { DownloadButton, Title } from '../../styled' import { DownloadButton, Title } from '../../styled'
export const MatchDownloadButton = () => { type TMatchDownloadButton = {
open: () => void,
}
export const MatchDownloadButton = ({ open: openDownloadNotification }:TMatchDownloadButton) => {
const { user, userInfo } = useAuthStore() const { user, userInfo } = useAuthStore()
const { profile } = useMatchPageStore() const { profile } = useMatchPageStore()
const { sportType } = usePageParams() const { sportType } = usePageParams()
@ -56,6 +59,7 @@ export const MatchDownloadButton = () => {
<MatchDownloadPopup <MatchDownloadPopup
isModalOpen={isOpen} isModalOpen={isOpen}
closePopup={close} closePopup={close}
openDownloadNotification={openDownloadNotification}
/> />
<DownloadButton onClick={open}> <DownloadButton onClick={open}>
<Title> <Title>

@ -19,6 +19,8 @@ import { T9n } from 'features/T9n'
import { useMatchPageStore } from 'features/MatchPage/store' import { useMatchPageStore } from 'features/MatchPage/store'
import { useLexicsStore } from 'features/LexicsStore' import { useLexicsStore } from 'features/LexicsStore'
import { DownloadNotification } from 'features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification'
import { useToggle } from 'hooks'
import { PlayButton } from '../PlayButton' import { PlayButton } from '../PlayButton'
import { MatchDownloadButton } from '../MatchDownloadButton' import { MatchDownloadButton } from '../MatchDownloadButton'
@ -64,6 +66,11 @@ export const MatchPlaylists = forwardRef(
) => { ) => {
const { setEpisodeInfo } = useMatchPageStore() const { setEpisodeInfo } = useMatchPageStore()
const { translate } = useLexicsStore() const { translate } = useLexicsStore()
const {
close,
isOpen,
open,
} = useToggle()
const handleButtonClick = (playlist: MatchPlaylistOption) => { const handleButtonClick = (playlist: MatchPlaylistOption) => {
onSelect?.(playlist) onSelect?.(playlist)
@ -77,8 +84,9 @@ export const MatchPlaylists = forwardRef(
return ( return (
<List ref={ref}> <List ref={ref}>
{ {isOpen
map(playlists, (playlist) => ( ? (<DownloadNotification close={close} />)
: map(playlists, (playlist) => (
<Item <Item
key={playlist.id} key={playlist.id}
id={`match_watch_${playlist.id}${live ? '_live' : ''}`} id={`match_watch_${playlist.id}${live ? '_live' : ''}`}
@ -93,9 +101,8 @@ export const MatchPlaylists = forwardRef(
<T9n t={playlist.lexic} /> <T9n t={playlist.lexic} />
</PlayButton> </PlayButton>
</Item> </Item>
)) ))}
} <MatchDownloadButton open={open} />
<MatchDownloadButton />
</List> </List>
) )
}, },

@ -6,7 +6,7 @@ import {
devices, devices,
} from 'config' } from 'config'
import { customScrollbar } from 'features/Common' import { ButtonOutline, customScrollbar } from 'features/Common'
import { T9n } from 'features/T9n' import { T9n } from 'features/T9n'
type WrapperProps = { type WrapperProps = {
@ -219,19 +219,16 @@ export const Button = styled.button<ButtonProps>`
}} }}
` `
export const DownloadButton = styled(Button)` export const DownloadButton = styled(ButtonOutline)`
width: 100%;
height: 2.25rem;
font-size: 0.875rem;
font-weight: 600;
line-height: 1rem;
:hover { :hover {
background-color: ${({ theme }) => theme.colors.buttonHover}; background-color: ${({ theme }) => theme.colors.buttonHover};
} }
${({ active }) => (active
? css`
border: 1px solid #FFFFFF;
border-radius: 2px;
background-color: black;
`
: '')}
` `
export const Title = styled.span` export const Title = styled.span`

@ -0,0 +1,38 @@
import { API_ROOT } from 'config'
import { callApi } from 'helpers'
export type DownloadPlaylistProps = {
ball_in_play: boolean,
concat?: boolean,
match_id: number,
sport_id: number,
}
type Status = 'COMPLETED' | 'IN PROGRESS' | 'ERROR'
export type DownloadResponse = {
status:Status,
urls?: Array<string>,
}
export const downloadPlaylist = async (
{
ball_in_play,
concat,
match_id,
sport_id,
}: DownloadPlaylistProps,
)
: Promise<DownloadResponse> => {
const config = {
body: {
ball_in_play,
concat,
},
}
return callApi({
config,
url: `${API_ROOT}/v1/matches/${sport_id}/${match_id}/download`,
})
}
Loading…
Cancel
Save