VID-168-donwload-video #285

Open
andrey.dekterev wants to merge 4 commits from VID-168-donwload-video into develop
  1. 4
      src/config/lexics/matchDownload.tsx
  2. 1
      src/config/queries.tsx
  3. 109
      src/features/MatchPage/components/MatchDownloadPopup/index.tsx
  4. 23
      src/features/MatchPage/components/MatchDownloadPopup/styled.tsx
  5. 62
      src/features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification.tsx
  6. 48
      src/features/MatchSidePlaylists/components/DownloadNotification/styled.tsx
  7. 68
      src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx
  8. 35
      src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx
  9. 17
      src/features/MatchSidePlaylists/styled.tsx
  10. 19
      src/helpers/downloadFile/index.tsx
  11. 1
      src/helpers/index.tsx
  12. 38
      src/requests/downloadPlaylist.tsx

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

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

@ -1,7 +1,18 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { useQuery } from 'react-query'
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 {
Header,
Footer,
@ -13,20 +24,76 @@ import {
FirstTitle,
SecondTitle,
RadioButtonsWrapper,
Input,
Label,
} from './styled'
type Props = {
closePopup: () => void,
isModalOpen: boolean,
openDownloadNotification: () => void,
setPlaylistConfig: (config: DownloadPlaylistProps) => 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> = {
entire_record: true,
in_game_time_only: false,
}
export const MatchDownloadPopup = ({
closePopup,
isModalOpen,
openDownloadNotification,
setPlaylistConfig,
}: Props) => {
const [selected, setSelected] = useState(true)
const [downloadConfig, setDownloadConfig] = useState<typeof initialRadioBtns>(initialRadioBtns)
const { profileId: match_id, sportType: sport_id } = usePageParams()
const config: DownloadPlaylistProps = {
ball_in_play: downloadConfig.in_game_time_only,
match_id,
sport_id,
}
const { refetch } = useQuery(
querieKeys.downloadPlaylist,
() => downloadPlaylist(config),
{
enabled: false, // disable this query from automatically running
refetchOnWindowFocus: false,
staleTime: 0,
},
)
const handleDownload = (id = fileType.download_single_file) => {
if (downloadConfig.in_game_time_only) {
config.concat = fileType.download_single_file === id
}
setPlaylistConfig(config)
refetch()
closePopup()
openDownloadNotification()
}
useEffect(() => {
setPlaylistConfig(config)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
downloadConfig,
])
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 (
<Modal
@ -42,28 +109,28 @@ export const MatchDownloadPopup = ({
</HeaderTitle>
</Header>
<RadioButtonsWrapper>
<Label>
<Input
defaultChecked={selected}
name='in_game_time_only'
onClick={() => setSelected(true)}
/>
<T9n t='in_game_time_only' />
</Label>
<Label>
<Input
name='entire_record'
defaultChecked={!selected}
onClick={() => setSelected(false)}
/>
<T9n t='entire_record' />
</Label>
{Object.entries(downloadConfig).map(([id, checked], index) => (
<Label>
<Radio
name={id}
key={id}
checked={checked}
onChange={(e) => handleChange(e.target.name)}
/>
<T9n t={id} />
</Label>
))}
</RadioButtonsWrapper>
<Footer>
<ScApplyButton>
<ScApplyButton
onClick={() => handleDownload(fileType.download_single_file)}
>
<T9n t='download_single_file' />
</ScApplyButton>
<ScApplyButton disabled={!selected}>
<ScApplyButton
disabled={!downloadConfig.in_game_time_only}
onClick={() => handleDownload(fileType.download_files_for_periods)}
>
<T9n t='download_files_for_periods' />
</ScApplyButton>
</Footer>

@ -100,29 +100,6 @@ export const Label = styled.label`
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 ScApplyButton = styled(ApplyButton)`

@ -0,0 +1,62 @@
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,
Error,
} from './styled'
type TDownloadNotification = {
close: () => void,
}
export const DownloadNotification = ({ close }:TDownloadNotification) => {
const client = useQueryClient()
const data = client.getQueryData<DownloadResponse>(querieKeys.downloadPlaylist)
if (!data) {
return null
}
return (
<Container>
<Header>
<CloseBtn
onClick={close}
/>
</Header>
<MainContainer>
<Title>
<T9n t='processed' />
</Title>
<Description>
{data?.status === 'ERROR'
? (
<Error>
<T9n t='error_message' />
</Error>
) : (
<>
<T9n t='can_close' />&nbsp;
<T9n t='will_notified' />&nbsp;
{/* <LinkToDownload href='/useraccount/downloads'> */}
{/* My Videos */}
{/* </LinkToDownload> */}
</>
)}
</Description>
</MainContainer>
</Container>
)
}

@ -0,0 +1,48 @@
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;
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;
`

@ -11,14 +11,31 @@ import { MatchDownloadPopup } from 'features/MatchPage/components/MatchDownloadP
import { usePageParams } from 'hooks/usePageParams'
import { Item } from '../MatchPlaylists'
import { useQuery } from 'react-query'
import { downloadPlaylist, type DownloadPlaylistProps } from 'requests/downloadPlaylist'
import { querieKeys } from 'config'
import { useInterval } from 'hooks'
import { useEffect, useState } from 'react'
import { downloadFile } from 'helpers'
import { DownloadButton, Title } from '../../styled'
import { Item } from '../MatchPlaylists'
type TMatchDownloadButton = {
close: () => void,
open: () => void,
}
export const MatchDownloadButton = () => {
const INTERVAL_CHECK_DOWNLOAD_STATUS = 60 * 1000
export const MatchDownloadButton = ({
close: closeDownloadNotification,
open: openDownloadNotification,
}:TMatchDownloadButton) => {
const { user, userInfo } = useAuthStore()
const { profile } = useMatchPageStore()
const { sportType } = usePageParams()
const [playlistConfig, setPlaylistConfig] = useState<DownloadPlaylistProps | null>(null)
const [isDownloaded, setIsDownloaded] = useState(false)
const {
close,
isOpen,
@ -47,6 +64,41 @@ export const MatchDownloadButton = () => {
return null
}
const { data, refetch } = useQuery(
querieKeys.downloadPlaylist,
() => playlistConfig && downloadPlaylist(playlistConfig),
{
enabled: false,
refetchOnWindowFocus: false,
staleTime: 0,
},
)
const { start, stop } = useInterval({
callback: refetch,
intervalDuration: INTERVAL_CHECK_DOWNLOAD_STATUS,
startImmediate: true,
})
useEffect(() => {
if (!data) return undefined
if (
data?.status === 'COMPLETED'
&& data.urls
&& !isDownloaded) {
downloadFile(data.urls)
setIsDownloaded(true)
closeDownloadNotification()
stop()
} else if (data?.status === 'ERROR') {
stop()
}
return () => stop()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data?.status, refetch, playlistConfig])
const isNeedDownloadButton = user && (isAvailableTournaments() || isAvailableTeams())
if (!isNeedDownloadButton) return null
@ -56,8 +108,16 @@ export const MatchDownloadButton = () => {
<MatchDownloadPopup
isModalOpen={isOpen}
closePopup={close}
openDownloadNotification={openDownloadNotification}
setPlaylistConfig={setPlaylistConfig}
/>
<DownloadButton onClick={open}>
<DownloadButton onClick={
() => {
open()
start()
}
}
>
<Title>
<T9n t='download_full_match' />
</Title>

@ -1,5 +1,6 @@
import type { ForwardedRef } from 'react'
import { forwardRef } from 'react'
import { forwardRef, useEffect } from 'react'
import { useQueryClient } from 'react-query'
import styled, { css } from 'styled-components/macro'
@ -7,7 +8,9 @@ import isEmpty from 'lodash/isEmpty'
import map from 'lodash/map'
import some from 'lodash/some'
import { isMobileDevice } from 'config'
import { isMobileDevice, querieKeys } from 'config'
import { DownloadResponse } from 'requests/downloadPlaylist'
import type {
MatchPlaylistOption,
@ -22,6 +25,9 @@ import { useLexicsStore } from 'features/LexicsStore'
import { MATCH_ADS } from 'components/Ads/types'
import { usePageParams, useToggle } from 'hooks'
import { DownloadNotification } from '../DownloadNotification/DownloadNotification'
import { PlayButton } from '../PlayButton'
import { MatchDownloadButton } from '../MatchDownloadButton'
@ -71,6 +77,13 @@ export const MatchPlaylists = forwardRef(
) => {
const { ads, setEpisodeInfo } = useMatchPageStore()
const { translate } = useLexicsStore()
const {
close,
isOpen,
open,
} = useToggle()
const { profileId } = usePageParams()
const handleButtonClick = (playlist: MatchPlaylistOption) => {
onSelect?.(playlist)
@ -82,13 +95,22 @@ export const MatchPlaylists = forwardRef(
})
}
const client = useQueryClient()
const data = client.getQueryData<DownloadResponse>(querieKeys.downloadPlaylist)
useEffect(() => {
close()
}, [profileId, close])
return (
<List
ref={ref}
isAdsExist={some(ads, ({ position }) => position.id === MATCH_ADS.WATCH_TOP)}
>
{
map(playlists, (playlist) => (
{isOpen && data
? (<DownloadNotification close={close} />)
: map(playlists, (playlist) => (
<Item
key={playlist.id}
id={`match_watch_${playlist.id}${live ? '_live' : ''}`}
@ -103,9 +125,8 @@ export const MatchPlaylists = forwardRef(
<T9n t={playlist.lexic} />
</PlayButton>
</Item>
))
}
<MatchDownloadButton />
))}
<MatchDownloadButton open={open} close={close} />
</List>
)
},

@ -6,7 +6,7 @@ import {
devices,
} from 'config'
import { customScrollbar } from 'features/Common'
import { ButtonOutline, customScrollbar } from 'features/Common'
import { T9n } from 'features/T9n'
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 {
background-color: ${({ theme }) => theme.colors.buttonHover};
}
${({ active }) => (active
? css`
border: 1px solid #FFFFFF;
border-radius: 2px;
background-color: black;
`
: '')}
`
export const Title = styled.span`

@ -0,0 +1,19 @@
/* скачивание файлов без клика */
export const downloadFile = (urls: Array<string>) => {
if (!urls.length) return
urls.forEach((url) => {
const link = document.createElement('a')
link.href = url
link.download = 'video.mp4'
link.target = '_blank'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
}

@ -17,3 +17,4 @@ export * from './languageUrlParam'
export * from './bodyScrollLock'
export * from './getLocalStorage'
export * from './checkPage'
export * from './downloadFile'

@ -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