diff --git a/src/config/lexics/matchDownload.tsx b/src/config/lexics/matchDownload.tsx index d8c12bf3..d2b41fab 100644 --- a/src/config/lexics/matchDownload.tsx +++ b/src/config/lexics/matchDownload.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, } diff --git a/src/config/queries.tsx b/src/config/queries.tsx index 45fbda9d..fbf1d8bb 100644 --- a/src/config/queries.tsx +++ b/src/config/queries.tsx @@ -1,5 +1,6 @@ export const querieKeys = { ads: 'ads', + downloadPlaylist: 'downloadPlaylist', liveMatchScores: 'liveMatchScores', matchScore: 'matchScore', sportsList: 'sportsList', diff --git a/src/features/MatchPage/components/MatchDownloadPopup/index.tsx b/src/features/MatchPage/components/MatchDownloadPopup/index.tsx index ec97ad86..87afc107 100644 --- a/src/features/MatchPage/components/MatchDownloadPopup/index.tsx +++ b/src/features/MatchPage/components/MatchDownloadPopup/index.tsx @@ -1,7 +1,18 @@ import { 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,65 @@ import { FirstTitle, SecondTitle, RadioButtonsWrapper, - Input, Label, } from './styled' type Props = { closePopup: () => void, 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 = { + entire_record: true, + in_game_time_only: false, } export const MatchDownloadPopup = ({ closePopup, isModalOpen, + openDownloadNotification, }: Props) => { - const [selected, setSelected] = useState(true) + const [downloadConfig, setDownloadConfig] = useState(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, + }, + ) + + const handleDownload = (id = fileType.download_single_file) => { + if (downloadConfig.in_game_time_only) { + config.concat = fileType.download_single_file === id + } + + refetch() + closePopup() + openDownloadNotification() + } + + 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 ( - - + {Object.entries(downloadConfig).map(([id, checked], index) => ( + + ))}
- + handleDownload(fileType.download_single_file)} + > - + handleDownload(fileType.download_files_for_periods)} + >
diff --git a/src/features/MatchPage/components/MatchDownloadPopup/styled.tsx b/src/features/MatchPage/components/MatchDownloadPopup/styled.tsx index 9ec9dc8a..1863bd9c 100644 --- a/src/features/MatchPage/components/MatchDownloadPopup/styled.tsx +++ b/src/features/MatchPage/components/MatchDownloadPopup/styled.tsx @@ -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)` diff --git a/src/features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification.tsx b/src/features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification.tsx new file mode 100644 index 00000000..124c8025 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/DownloadNotification/DownloadNotification.tsx @@ -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(querieKeys.downloadPlaylist) + + if (!data) { + return null + } + + return ( + +
+ +
+ + + <T9n t='processed' /> + + + {data?.status === 'ERROR' + ? ( + + + + ) : ( + <> +   +   + {/* */} + {/* My Videos */} + {/* */} + + )} + + +
+ ) +} diff --git a/src/features/MatchSidePlaylists/components/DownloadNotification/styled.tsx b/src/features/MatchSidePlaylists/components/DownloadNotification/styled.tsx new file mode 100644 index 00000000..f19fbe57 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/DownloadNotification/styled.tsx @@ -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; +` diff --git a/src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx b/src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx index 2f15f826..866bed2f 100644 --- a/src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx +++ b/src/features/MatchSidePlaylists/components/MatchDownloadButton/index.tsx @@ -11,10 +11,22 @@ import { MatchDownloadPopup } from 'features/MatchPage/components/MatchDownloadP import { usePageParams } from 'hooks/usePageParams' -import { Item } from '../MatchPlaylists' +import { useQueryClient } from 'react-query' +import { DownloadResponse } from 'requests/downloadPlaylist' +import { querieKeys } from 'config' +import { useInterval } from 'hooks' +import { useEffect } from 'react' +import { downloadFile } from 'helpers' import { DownloadButton, Title } from '../../styled' +import { Item } from '../MatchPlaylists' + +type TMatchDownloadButton = { + open: () => void, +} -export const MatchDownloadButton = () => { +const INTERVAL_CHECK_DOWNLOAD_STATUS = 60 * 1000 + +export const MatchDownloadButton = ({ open: openDownloadNotification }:TMatchDownloadButton) => { const { user, userInfo } = useAuthStore() const { profile } = useMatchPageStore() const { sportType } = usePageParams() @@ -47,6 +59,34 @@ export const MatchDownloadButton = () => { return null } + const client = useQueryClient() + + const data = client.getQueryData(querieKeys.downloadPlaylist) + + const handleRefetch = () => { + client.refetchQueries(querieKeys.downloadPlaylist) + } + + const { start, stop } = useInterval({ + callback: handleRefetch, + intervalDuration: INTERVAL_CHECK_DOWNLOAD_STATUS, + startImmediate: false, + }) + + useEffect(() => { + start() + + if (data?.status === 'COMPLETED' && data.urls) { + downloadFile(data.urls) + stop() + } else if (data?.status === 'ERROR') { + stop() + } + + return () => stop() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data?.status]) + const isNeedDownloadButton = user && (isAvailableTournaments() || isAvailableTeams()) if (!isNeedDownloadButton) return null @@ -56,6 +96,7 @@ export const MatchDownloadButton = () => { diff --git a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx index b66725a6..d881d2f9 100644 --- a/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx @@ -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} /> </List> ) }, diff --git a/src/features/MatchSidePlaylists/styled.tsx b/src/features/MatchSidePlaylists/styled.tsx index 4a6894ac..218f96e5 100644 --- a/src/features/MatchSidePlaylists/styled.tsx +++ b/src/features/MatchSidePlaylists/styled.tsx @@ -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` diff --git a/src/helpers/downloadFile/index.tsx b/src/helpers/downloadFile/index.tsx new file mode 100644 index 00000000..6e6f7b80 --- /dev/null +++ b/src/helpers/downloadFile/index.tsx @@ -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) + }) +} diff --git a/src/helpers/index.tsx b/src/helpers/index.tsx index 814a4711..9223f1bd 100644 --- a/src/helpers/index.tsx +++ b/src/helpers/index.tsx @@ -17,3 +17,4 @@ export * from './languageUrlParam' export * from './bodyScrollLock' export * from './getLocalStorage' export * from './checkPage' +export * from './downloadFile' diff --git a/src/requests/downloadPlaylist.tsx b/src/requests/downloadPlaylist.tsx new file mode 100644 index 00000000..4c431fa2 --- /dev/null +++ b/src/requests/downloadPlaylist.tsx @@ -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`, + }) +}