@ -0,0 +1,9 @@ |
||||
{ |
||||
"applinks": { |
||||
"apps": [], |
||||
"details": [{ |
||||
"appID": "2X9NY5X2LZ.com.insports.ott", |
||||
"paths": ["*"] |
||||
}] |
||||
} |
||||
} |
||||
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<browserconfig> |
||||
<msapplication> |
||||
<tile> |
||||
<square70x70logo src="/mstile-70x70.png"/> |
||||
<square144x144logo src="/mstile-144x144.png"/> |
||||
<square150x150logo src="/mstile-150x150.png"/> |
||||
<square310x310logo src="/mstile-310x310.png"/> |
||||
<TileColor>#da532c</TileColor> |
||||
</tile> |
||||
</msapplication> |
||||
</browserconfig> |
||||
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,19 @@ |
||||
{ |
||||
"name": "", |
||||
"short_name": "", |
||||
"icons": [ |
||||
{ |
||||
"src": "/android-chrome-192x192.png", |
||||
"sizes": "192x192", |
||||
"type": "image/png" |
||||
}, |
||||
{ |
||||
"src": "/android-chrome-512x512.png", |
||||
"sizes": "512x512", |
||||
"type": "image/png" |
||||
} |
||||
], |
||||
"theme_color": "#ffffff", |
||||
"background_color": "#ffffff", |
||||
"display": "standalone" |
||||
} |
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 229 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 908 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,15 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<title></title> |
||||
</head> |
||||
<body> |
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.11.5/oidc-client.min.js" integrity="sha512-pGtU1n/6GJ8fu6bjYVGIOT9Dphaw5IWPwVlqkpvVgqBxFkvdNbytUh0H8AP15NYF777P4D3XEeA/uDWFCpSQ1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> |
||||
<script> |
||||
new Oidc.UserManager().signinSilentCallback() |
||||
.catch((err) => { |
||||
console.error('OIDC: silent refresh callback error', err); |
||||
}); |
||||
</script> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,128 @@ |
||||
import { |
||||
useEffect, |
||||
useState, |
||||
RefObject, |
||||
} from 'react' |
||||
|
||||
import { T9n } from 'features/T9n' |
||||
import { Icon } from 'features/Icon' |
||||
import { useAuthStore } from 'features/AuthStore' |
||||
|
||||
import { |
||||
AccessTimerContainer, |
||||
PreviewInfo, |
||||
SignInBtn, |
||||
SignText, |
||||
Timer, |
||||
TimerContainer, |
||||
} from './styled' |
||||
|
||||
import { SimplePopup } from '../SimplePopup' |
||||
import { secondsToHms } from '../../helpers' |
||||
import { getViewMatchDuration } from '../../requests/getViewMatchDuration' |
||||
import { usePageParams } from '../../hooks' |
||||
import { getUserInfo } from '../../requests' |
||||
|
||||
type AccessTimerType = { |
||||
access: boolean, |
||||
isFullscreen: boolean, |
||||
onFullscreenClick: () => void, |
||||
playing: boolean, |
||||
videoRef?: RefObject<HTMLVideoElement> | null, |
||||
} |
||||
|
||||
const ACCESS_TIME = 60 |
||||
|
||||
export const AccessTimer = ({ |
||||
access, |
||||
isFullscreen, |
||||
onFullscreenClick, |
||||
playing, |
||||
videoRef, |
||||
}: AccessTimerType) => { |
||||
const { |
||||
logout, |
||||
setUserInfo, |
||||
userInfo, |
||||
} = useAuthStore() |
||||
|
||||
const { profileId, sportType } = usePageParams() |
||||
|
||||
const [timeIsFinished, setTimeIsFinished] = useState(true) |
||||
const [time, setTime] = useState(ACCESS_TIME) |
||||
const isTimeExpired = time <= 0 || !access |
||||
|
||||
useEffect(() => { |
||||
if (isTimeExpired) { |
||||
document.pictureInPictureEnabled && document.exitPictureInPicture() |
||||
setTimeIsFinished(true) |
||||
videoRef?.current?.pause() |
||||
setTime(0) |
||||
if (isFullscreen) onFullscreenClick() |
||||
} |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [access, playing, profileId]) |
||||
|
||||
useEffect(() => { |
||||
let stopWatch: ReturnType<typeof setInterval> | null = null |
||||
if (playing) { |
||||
stopWatch = setInterval(() => { |
||||
setTime((prev) => prev - 1) |
||||
}, 1000) |
||||
} else { |
||||
stopWatch && clearInterval(stopWatch) |
||||
} |
||||
return () => { |
||||
stopWatch && clearInterval(stopWatch) |
||||
} |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [playing, profileId]) |
||||
|
||||
useEffect(() => { |
||||
(async () => { |
||||
setTime(ACCESS_TIME) |
||||
const updatedUserInfo = await getUserInfo() |
||||
setUserInfo(updatedUserInfo) |
||||
const timeViewed = await getViewMatchDuration({ |
||||
matchId: profileId, |
||||
sportType, |
||||
userId: Number(updatedUserInfo?.email), |
||||
}) |
||||
setTime(isTimeExpired ? 0 : (ACCESS_TIME - Number(timeViewed.duration))) |
||||
})() |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [profileId]) |
||||
|
||||
return ( |
||||
<> |
||||
{(!userInfo || Number(userInfo?.email) < 0) && access && time > 0 |
||||
? ( |
||||
<AccessTimerContainer isFullscreen={isFullscreen}> |
||||
<TimerContainer> |
||||
<PreviewInfo> |
||||
<Timer>{secondsToHms(time)} </Timer> |
||||
<T9n t='game_preview' className='gamePreview' /> |
||||
</PreviewInfo> |
||||
<SignText> |
||||
<T9n t='sign_in_full_game' /> |
||||
</SignText> |
||||
</TimerContainer> |
||||
<SignInBtn onClick={() => logout('saveToken')}> |
||||
<T9n t='sign_in' /> |
||||
</SignInBtn> |
||||
</AccessTimerContainer> |
||||
) |
||||
: ( |
||||
<SimplePopup |
||||
isModalOpen={timeIsFinished} |
||||
withCloseButton={false} |
||||
headerName='sec_60' |
||||
mainText='continue_watching' |
||||
buttonName='sign_in' |
||||
onHandle={() => logout('saveToken')} |
||||
icon={<Icon refIcon='ExclamationPoint' />} |
||||
/> |
||||
)} |
||||
</> |
||||
) |
||||
} |
||||
@ -0,0 +1,124 @@ |
||||
import styled, { css } from 'styled-components/macro' |
||||
|
||||
import { isMobileDevice } from 'config' |
||||
|
||||
import { ButtonSolid } from 'features/Common' |
||||
|
||||
export const AccessTimerContainer = styled.div<{isFullscreen?: boolean}>` |
||||
display: flex; |
||||
align-items: center; |
||||
|
||||
position: absolute; |
||||
left: 50%; |
||||
bottom: 5.7rem; |
||||
transform: translateX(-50%); |
||||
background-color: #333333; |
||||
border-radius: 5px; |
||||
padding: 20px 50px; |
||||
|
||||
gap: 40px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
padding: 9px 7px 9px 15px; |
||||
bottom: 6.5rem; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
max-width: 95%; |
||||
bottom: 4rem; |
||||
} |
||||
` |
||||
: ''}; |
||||
|
||||
${({ isFullscreen }) => isFullscreen && css` |
||||
${isMobileDevice |
||||
? css` |
||||
padding: 9px 7px 9px 15px; |
||||
bottom: 12rem; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
max-width: 95%; |
||||
bottom: 6rem; |
||||
} |
||||
` |
||||
: ''}; |
||||
`}
|
||||
` |
||||
|
||||
export const SignInBtn = styled(ButtonSolid)` |
||||
width: 246px; |
||||
border-radius: 5px; |
||||
height: 50px; |
||||
font-weight: 600; |
||||
font-size: 20px; |
||||
white-space: nowrap; |
||||
padding: 0 35px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 12px; |
||||
white-space: nowrap; |
||||
padding: 0px 16px; |
||||
width: 140px; |
||||
height: 30px; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
font-size: 12px; |
||||
padding: 0px 8px; |
||||
} |
||||
` |
||||
: ''}; |
||||
|
||||
` |
||||
|
||||
export const TimerContainer = styled.div` |
||||
color: white; |
||||
font-weight: 700; |
||||
font-size: 20px; |
||||
line-height: 24px; |
||||
white-space: nowrap; |
||||
max-width: 215px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 12px; |
||||
line-height: 28px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const PreviewInfo = styled.div` |
||||
display: flex; |
||||
line-height: 24px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
line-height: 14px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const Timer = styled.div` |
||||
min-width: 67px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
min-width: 40px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const SignText = styled.span` |
||||
display: block; |
||||
font-size: 16px; |
||||
line-height: 20px; |
||||
font-weight: 400; |
||||
white-space: break-spaces; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 9px; |
||||
line-height: 14px |
||||
` |
||||
: ''}; |
||||
` |
||||
@ -0,0 +1,65 @@ |
||||
import type { ReactNode } from 'react' |
||||
|
||||
import { T9n } from 'features/T9n' |
||||
|
||||
import { |
||||
Header, |
||||
Footer, |
||||
ScBody, |
||||
Modal, |
||||
ScApplyButton, |
||||
ScHeaderTitle, |
||||
ScText, |
||||
Wrapper, |
||||
} from './styled' |
||||
|
||||
type Props = { |
||||
buttonName?: string, |
||||
headerName?: string, |
||||
icon?: ReactNode, |
||||
isModalOpen: boolean, |
||||
mainText: string, |
||||
onHandle?: () => void, |
||||
withCloseButton: boolean, |
||||
} |
||||
|
||||
export const SimplePopup = (props: Props) => { |
||||
const { |
||||
buttonName, |
||||
headerName, |
||||
icon, |
||||
isModalOpen, |
||||
mainText, |
||||
onHandle, |
||||
withCloseButton, |
||||
} = props |
||||
|
||||
return ( |
||||
<Modal |
||||
isOpen={isModalOpen} |
||||
withCloseButton={withCloseButton} |
||||
> |
||||
<Wrapper> |
||||
<Header> |
||||
{icon} |
||||
<ScHeaderTitle> |
||||
<T9n t={headerName ?? ''} /> |
||||
</ScHeaderTitle> |
||||
</Header> |
||||
<ScBody> |
||||
<ScText> |
||||
<T9n t={mainText} /> |
||||
</ScText> |
||||
</ScBody> |
||||
{buttonName |
||||
&& ( |
||||
<Footer> |
||||
<ScApplyButton onClick={onHandle}> |
||||
<T9n t={buttonName} /> |
||||
</ScApplyButton> |
||||
</Footer> |
||||
)} |
||||
</Wrapper> |
||||
</Modal> |
||||
) |
||||
} |
||||
@ -0,0 +1,146 @@ |
||||
import styled, { css } from 'styled-components/macro' |
||||
|
||||
import { isMobileDevice } from 'config' |
||||
|
||||
import { ModalWindow } from 'features/Modal/styled' |
||||
import { |
||||
ApplyButton, |
||||
Body, |
||||
Modal as BaseModal, |
||||
HeaderTitle, |
||||
} from 'features/AuthServiceApp/components/RegisterPopup/styled' |
||||
import { Header as BaseHeader } from 'features/PopupComponents' |
||||
import { client } from 'features/AuthServiceApp/config/clients/index' |
||||
|
||||
export const Modal = styled(BaseModal)` |
||||
|
||||
|
||||
${ModalWindow} { |
||||
width: 705px; |
||||
height: 472px; |
||||
|
||||
padding: 60px 100px; |
||||
min-height: auto; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
max-width: 95vw; |
||||
padding: 50px 20px 80px 20px; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
max-height: 80vh; |
||||
max-width: 95vw; |
||||
padding: 24px 100px 60px 100px; |
||||
} |
||||
` |
||||
: ''}; |
||||
} |
||||
` |
||||
|
||||
export const Wrapper = styled.div` |
||||
gap: 30px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
max-height: 80vh; |
||||
gap: 10px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const ScHeaderTitle = styled(HeaderTitle)` |
||||
text-align: center; |
||||
font-weight: 700; |
||||
font-size: 34px; |
||||
line-height: 34px; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 20px; |
||||
line-height: 24px; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
font-size: 17px; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const ScBody = styled(Body)` |
||||
padding: 16px 0 0 0; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
@media screen and (orientation: landscape) { |
||||
max-width: 491px; |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const ScText = styled.span` |
||||
text-align: center; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 14px; |
||||
line-height: 22px; |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const ScApplyButton = styled(ApplyButton)` |
||||
width: 300px; |
||||
height: 60px; |
||||
margin: 0; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
font-size: 14px; |
||||
margin: 20px 0; |
||||
width: 293px; |
||||
height: 50px; |
||||
|
||||
@media screen and (orientation: landscape) { |
||||
margin: 0; |
||||
width: 225px; |
||||
height: 44px; |
||||
} |
||||
` |
||||
: ''}; |
||||
${client.styles.popupApplyButton} |
||||
` |
||||
|
||||
export const Header = styled(BaseHeader)` |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
height: auto; |
||||
justify-content: center; |
||||
gap: 30px; |
||||
${isMobileDevice |
||||
? css` |
||||
@media screen and (orientation: landscape) { |
||||
gap: 10px; |
||||
|
||||
svg { |
||||
width: 40px; |
||||
height: 40px; |
||||
} |
||||
} |
||||
` |
||||
: ''}; |
||||
` |
||||
|
||||
export const Footer = styled.div` |
||||
width: 100%; |
||||
display: flex; |
||||
justify-content: center; |
||||
padding: 33px 0 65px 0; |
||||
|
||||
${isMobileDevice |
||||
? css` |
||||
padding-top: 30px; |
||||
` |
||||
: ''}; |
||||
` |
||||
@ -1,57 +0,0 @@ |
||||
import { css } from 'styled-components/macro' |
||||
|
||||
import { |
||||
ClientConfig, |
||||
ClientIds, |
||||
ClientNames, |
||||
} from './types' |
||||
|
||||
const randomHash = () => ( |
||||
(Math.random() ** Math.random()) * 9999999999999999 |
||||
) |
||||
|
||||
export const tunis: ClientConfig = { |
||||
auth: { |
||||
clientId: ClientIds.Tunis, |
||||
metaDataUrlParams: `?hash=${randomHash()}`, |
||||
}, |
||||
defaultLanguage: 'fr', |
||||
description: 'Live sports streaming platform. All matches playing under the auspices of Czech Republic FA. Access to full matches, various player playlists, and highlights. Free access in the Czech Republic. Available across all devices', |
||||
disabledPreferences: false, |
||||
name: ClientNames.Tunis, |
||||
privacyLink: '/privacy-policy-and-statement', |
||||
showSearch: false, |
||||
styles: { |
||||
background: '', |
||||
homePageHeader: css` |
||||
background: radial-gradient( |
||||
160.34% 257.27% at -7.45% 162.22%, |
||||
#2AB7AA 3.27%, |
||||
#02505C 43.69%, #0B2E4D 100%); |
||||
`,
|
||||
logo: 'tunis-logo.svg', |
||||
logoHeight: 6.3, |
||||
logoLeft: 1.1, |
||||
logoTop: 1.74, |
||||
logoWidth: 8.25, |
||||
matchLogoHeight: 3.4, |
||||
matchLogoTopMargin: 0.9, |
||||
matchLogoWidth: 4.5, |
||||
matchPageMobileHeaderLogo: css` |
||||
width: 35px; |
||||
height: 25px; |
||||
top: 2px; |
||||
`,
|
||||
mobileHeaderLogo: css` |
||||
width: 48px; |
||||
height: 37px; |
||||
`,
|
||||
userAccountLogo: css` |
||||
width: 4.56rem; |
||||
height: 3.488rem; |
||||
`,
|
||||
}, |
||||
termsLink: '/terms-and-conditions?client_id=facr-ott-web', |
||||
title: 'FACR.TV - The home of Czech football streaming', |
||||
userAccountLinksDisabled: true, |
||||
} |
||||
@ -0,0 +1,58 @@ |
||||
import { css } from 'styled-components/macro' |
||||
|
||||
import { |
||||
ClientConfig, |
||||
ClientIds, |
||||
ClientNames, |
||||
} from './types' |
||||
|
||||
const randomHash = () => ( |
||||
(Math.random() ** Math.random()) * 9999999999999999 |
||||
) |
||||
|
||||
export const tunisia: ClientConfig = { |
||||
auth: { |
||||
clientId: ClientIds.Tunisia, |
||||
metaDataUrlParams: `?hash=${randomHash()}`, |
||||
}, |
||||
defaultLanguage: 'fr', |
||||
description: '', |
||||
disabledFilters: true, |
||||
disabledHighlights: true, |
||||
disabledPreferences: true, |
||||
name: ClientNames.Tunisia, |
||||
privacyLink: '/privacy-policy-and-statement?client_id=insports-ott-web', |
||||
showSearch: true, |
||||
styles: { |
||||
background: '', |
||||
homePageHeader: css` |
||||
background: radial-gradient( |
||||
160.34% 257.27% at -7.45% 162.22%, |
||||
#2AB7AA 3.27%, |
||||
#02505C 43.69%, #0B2E4D 100%); |
||||
`,
|
||||
logo: 'tunis-logo.svg', |
||||
logoHeight: 1.922, |
||||
logoLeft: 1.1, |
||||
logoTop: 1.14, |
||||
logoWidth: 9, |
||||
matchLogoHeight: 1.922, |
||||
matchLogoTopMargin: 1, |
||||
matchLogoWidth: 9, |
||||
matchPageMobileHeaderLogo: css` |
||||
width: 100px; |
||||
height: 21px; |
||||
top: 5px; |
||||
`,
|
||||
mobileHeaderLogo: css` |
||||
width: 100px; |
||||
height: 21px; |
||||
`,
|
||||
userAccountLogo: css` |
||||
width: 9rem; |
||||
height: 1.922rem; |
||||
`,
|
||||
}, |
||||
termsLink: '/terms-and-conditions?client_id=insports-ott-web', |
||||
title: 'Diwan Sport - The home of Tunisian Ligue Professionnelle 1', |
||||
} |
||||
@ -0,0 +1,3 @@ |
||||
export enum KEYBOARD_KEYS { |
||||
Enter = 'Enter', |
||||
} |
||||
@ -1,25 +0,0 @@ |
||||
import { createInstance } from '@jonkoops/matomo-tracker-react' |
||||
import { InstanceParams } from '@jonkoops/matomo-tracker-react/lib/types' |
||||
|
||||
import { PAGES } from 'config/pages' |
||||
|
||||
const getMatomoInstance = () => { |
||||
let matomoInstance: InstanceParams = { |
||||
siteId: 999, |
||||
urlBase: 'link.to.domain', |
||||
} |
||||
|
||||
switch (process.env.REACT_APP_CLIENT) { |
||||
case 'insports': |
||||
matomoInstance = { |
||||
...matomoInstance, |
||||
siteId: 1, |
||||
urlBase: PAGES.matomoInstatBaseUrl, |
||||
} |
||||
break |
||||
} |
||||
|
||||
return createInstance(matomoInstance) |
||||
} |
||||
|
||||
export const matomoInstance = getMatomoInstance() |
||||
@ -0,0 +1,22 @@ |
||||
import { ClientNames } from './clients/types' |
||||
|
||||
export enum PaymentSystem { |
||||
PagBrazil = 'pag_brasil', |
||||
Paymee = 'paymee', |
||||
Paytm = 'paytm', |
||||
Stripe = 'stripe' |
||||
} |
||||
|
||||
type PaymentsType = { |
||||
[key in ClientNames]: PaymentSystem |
||||
} |
||||
|
||||
export const payments: PaymentsType = { |
||||
[ClientNames.Tunisia]: PaymentSystem.Paymee, |
||||
brasil: PaymentSystem.PagBrazil, |
||||
[ClientNames.India]: PaymentSystem.Paytm, |
||||
[ClientNames.Insports]: PaymentSystem.Stripe, |
||||
[ClientNames.Instat]: PaymentSystem.Stripe, |
||||
[ClientNames.Facr]: PaymentSystem.Stripe, |
||||
[ClientNames.Lff]: PaymentSystem.Stripe, |
||||
} |
||||
@ -0,0 +1,4 @@ |
||||
export const querieKeys = { |
||||
liveMatchScores: 'liveMatchScores', |
||||
matchScore: 'matchScore', |
||||
} |
||||
@ -1,19 +1,35 @@ |
||||
export enum SportTypes { |
||||
FOOTBALL = 1, |
||||
HANDBALL = 7, |
||||
HOCKEY = 2, |
||||
BASKETBALL = 3, |
||||
TENNIS = 4, |
||||
VOLLEYBALL = 6, |
||||
HANDBALL = 7, |
||||
STREETBALL = 9, |
||||
BOXING = 12 |
||||
BOXING = 12, |
||||
FIELD_HOCKEY = 14, |
||||
FIGURE_SKATING = 15, |
||||
AMERICAN_FOOTBALL = 16, |
||||
FUTSAL = 17, |
||||
FLOORBALL = 18, |
||||
CRICKET = 19, |
||||
BASEBALL = 20 |
||||
} |
||||
|
||||
export const SPORT_NAMES = { |
||||
[SportTypes.BASKETBALL]: 'basketball', |
||||
[SportTypes.FOOTBALL]: 'football', |
||||
[SportTypes.TENNIS]: 'tennis', |
||||
[SportTypes.HANDBALL]: 'handball', |
||||
[SportTypes.HOCKEY]: 'hockey', |
||||
[SportTypes.VOLLEYBALL]: 'volleyball', |
||||
[SportTypes.STREETBALL]: 'streetball', |
||||
[SportTypes.BOXING]: 'boxing', |
||||
[SportTypes.BASEBALL]: 'baseball', |
||||
[SportTypes.FIELD_HOCKEY]: 'field_hockey', |
||||
[SportTypes.FIGURE_SKATING]: 'figure_skating', |
||||
[SportTypes.AMERICAN_FOOTBALL]: 'american_football', |
||||
[SportTypes.FUTSAL]: 'futsal', |
||||
[SportTypes.FLOORBALL]: 'floorball', |
||||
[SportTypes.CRICKET]: 'cricket', |
||||
} as const |
||||
|
||||
@ -0,0 +1,5 @@ |
||||
import { UserManager } from 'oidc-client' |
||||
|
||||
import { getClientSettings } from './helpers' |
||||
|
||||
export const userManager = new UserManager(getClientSettings()) |
||||
@ -1,101 +0,0 @@ |
||||
import { |
||||
useEffect, |
||||
useState, |
||||
MouseEvent, |
||||
} from 'react' |
||||
|
||||
import { useHistory } from 'react-router-dom' |
||||
|
||||
import { ProfileTypes } from 'config' |
||||
|
||||
import isNumber from 'lodash/isNumber' |
||||
|
||||
import { useLexicsStore } from 'features/LexicsStore' |
||||
import { useBuyMatchPopupStore } from 'features/BuyMatchPopup/store' |
||||
import { getProfileUrl } from 'features/ProfileLink/helpers' |
||||
|
||||
import { getMatchInfo } from 'requests/getMatchInfo' |
||||
import { getBrazilPaymentUrl } from 'requests/getBrazilPaymentUrl' |
||||
|
||||
import type { Props } from './index' |
||||
|
||||
type ResponsePayment = { |
||||
url: string, |
||||
} |
||||
|
||||
type ResponsePaymentArray = ResponsePayment | null |
||||
|
||||
export const useBrazilPayment = ({ |
||||
match, |
||||
open, |
||||
selectedPackage, |
||||
setIsOpenBrasilian, |
||||
}: Props) => { |
||||
const history = useHistory() |
||||
const { close } = useBuyMatchPopupStore() |
||||
|
||||
const [src, setSrc] = useState('') |
||||
const [error, setError] = useState('') |
||||
const { translate } = useLexicsStore() |
||||
|
||||
const { id, sportType } = match |
||||
|
||||
const { |
||||
name, |
||||
nameLexic, |
||||
originalObject, |
||||
pass, |
||||
} = selectedPackage |
||||
|
||||
const teams = isNumber(nameLexic) ? translate(String(nameLexic)) : name |
||||
const pack = translate(String(pass)) |
||||
|
||||
const matchLink = getProfileUrl({ |
||||
id, |
||||
profileType: ProfileTypes.MATCHES, |
||||
sportType, |
||||
}) |
||||
|
||||
const closePopup = async (e?: MouseEvent) => { |
||||
e?.stopPropagation() |
||||
setIsOpenBrasilian(false) |
||||
setError('') |
||||
|
||||
const accessMatch = await getMatchInfo(sportType, id) |
||||
if (accessMatch?.access) { |
||||
close() |
||||
history.push(matchLink) |
||||
} |
||||
} |
||||
|
||||
// eslint-disable-next-line
|
||||
window.onmessage = function (event) { |
||||
if (event.data === 'close') { |
||||
closePopup() |
||||
} |
||||
} |
||||
useEffect(() => { |
||||
if (open) { |
||||
(async () => { |
||||
try { |
||||
const json: ResponsePaymentArray = await getBrazilPaymentUrl({ |
||||
action: pass === 'pass_match_access' ? 'one_payment' : 'create_subscription', |
||||
item: originalObject, |
||||
product_name: `${pack} ${teams}`, |
||||
}) |
||||
setSrc(json?.url || '') |
||||
} catch (err) { |
||||
setError('error_payment_unsuccessful') |
||||
} |
||||
})() |
||||
} |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedPackage, open]) |
||||
|
||||
return { |
||||
closePopup, |
||||
error, |
||||
matchLink, |
||||
src, |
||||
} |
||||
} |
||||
@ -0,0 +1,173 @@ |
||||
import { |
||||
MouseEvent, |
||||
useCallback, |
||||
useEffect, |
||||
useState, |
||||
} from 'react' |
||||
|
||||
import { PAGES, ProfileTypes } from 'config' |
||||
import { ClientNames } from 'config/clients/types' |
||||
import { payments, PaymentSystem } from 'config/payments' |
||||
|
||||
import isNumber from 'lodash/isNumber' |
||||
|
||||
import { useLexicsStore } from 'features/LexicsStore' |
||||
import { useBuyMatchPopupStore } from 'features/BuyMatchPopup/store' |
||||
import { getProfileUrl } from 'features/ProfileLink/helpers' |
||||
|
||||
import { getMatchInfo } from 'requests/getMatchInfo' |
||||
import { getPaymentUrl } from 'requests/getPaymentUrl' |
||||
|
||||
import { redirectToUrl } from 'helpers' |
||||
|
||||
import type { Props } from './index' |
||||
|
||||
type ResponsePayment = { |
||||
url: string, |
||||
} |
||||
|
||||
type ResponsePaymentArray = ResponsePayment | null |
||||
|
||||
export const useIframePayment = ({ |
||||
match, |
||||
open, |
||||
paymentSystem, |
||||
selectedPackage, |
||||
setIsOpenIframe, |
||||
}: Props) => { |
||||
const { close } = useBuyMatchPopupStore() |
||||
|
||||
const [src, setSrc] = useState('') |
||||
const [error, setError] = useState('') |
||||
const [isPaymentProcessing, setIsPaymentProcessing] = useState(false) |
||||
const { translate } = useLexicsStore() |
||||
|
||||
const { id, sportType } = match |
||||
|
||||
const { |
||||
name, |
||||
nameLexic, |
||||
originalObject, |
||||
pass, |
||||
} = selectedPackage |
||||
|
||||
const teams = isNumber(nameLexic) ? translate(String(nameLexic)) : name |
||||
const pack = translate(String(pass)) |
||||
|
||||
const matchLink = getProfileUrl({ |
||||
id, |
||||
profileType: ProfileTypes.MATCHES, |
||||
sportType, |
||||
}) |
||||
|
||||
const closePopup = useCallback(async (e?: MouseEvent) => { |
||||
e?.stopPropagation() |
||||
|
||||
if (error) { |
||||
setIsOpenIframe(false) |
||||
setError('') |
||||
} |
||||
|
||||
const accessMatch = await getMatchInfo(sportType, id) |
||||
if (accessMatch?.access) { |
||||
setIsPaymentProcessing(false) |
||||
setIsOpenIframe(false) |
||||
setError('') |
||||
close() |
||||
redirectToUrl(matchLink) |
||||
} |
||||
}, [close, error, id, matchLink, setIsOpenIframe, sportType]) |
||||
|
||||
const paymentRequest = async () => { |
||||
let url_cancel |
||||
let url_return |
||||
let action: Parameters<typeof getPaymentUrl>[0]['action'] |
||||
|
||||
switch (paymentSystem) { |
||||
case PaymentSystem.Paymee: |
||||
url_cancel = `${window.origin}/failed-paymee` |
||||
url_return = null |
||||
// paymee не умеет работать с подписками
|
||||
action = 'one_payment' |
||||
break |
||||
default: |
||||
url_return = `${window.location.origin}${PAGES.thanksForSubscribe}` |
||||
action = pass === 'pass_match_access' ? 'one_payment' : 'create_subscription' |
||||
break |
||||
} |
||||
|
||||
const payment: ResponsePaymentArray = await getPaymentUrl({ |
||||
action, |
||||
item: originalObject, |
||||
product_name: `${pack} ${teams}`, |
||||
service: paymentSystem, |
||||
url_cancel, |
||||
url_return, |
||||
}) |
||||
setSrc(payment?.url || '') |
||||
} |
||||
|
||||
if (paymentSystem === payments[ClientNames.Brasil]) { |
||||
// eslint-disable-next-line
|
||||
window.onmessage = function (event) { |
||||
if (event.data === 'close') { |
||||
closePopup() |
||||
} |
||||
} |
||||
} |
||||
|
||||
useEffect(() => { |
||||
let interval: ReturnType<typeof setInterval> |
||||
let timeout: ReturnType<typeof setTimeout> |
||||
|
||||
const paymentCallback = (event: MessageEvent<{ event_id: string }>) => { |
||||
if (event.data.event_id === 'paymee.complete') { |
||||
setIsPaymentProcessing(true) |
||||
interval = setInterval(() => closePopup(), 2000) |
||||
timeout = setTimeout(() => { |
||||
clearInterval(interval) |
||||
setIsPaymentProcessing(false) |
||||
setError('failed_paymee') |
||||
setSrc('') |
||||
}, 60000) |
||||
} |
||||
} |
||||
if (paymentSystem === payments[ClientNames.Tunisia]) { |
||||
window.addEventListener( |
||||
'message', |
||||
paymentCallback, |
||||
false, |
||||
) |
||||
} |
||||
return () => { |
||||
window.removeEventListener( |
||||
'message', |
||||
paymentCallback, |
||||
false, |
||||
) |
||||
clearInterval(interval) |
||||
clearTimeout(timeout) |
||||
} |
||||
}, [closePopup, paymentSystem]) |
||||
|
||||
useEffect(() => { |
||||
if (open) { |
||||
(async () => { |
||||
try { |
||||
await paymentRequest() |
||||
} catch (err) { |
||||
setError('error_payment_unsuccessful') |
||||
} |
||||
})() |
||||
} |
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedPackage, open]) |
||||
|
||||
return { |
||||
closePopup, |
||||
error, |
||||
isPaymentProcessing, |
||||
matchLink, |
||||
src, |
||||
} |
||||
} |
||||