diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx
index d828d2fa..4c57a709 100644
--- a/src/config/lexics/indexLexics.tsx
+++ b/src/config/lexics/indexLexics.tsx
@@ -75,6 +75,7 @@ export const indexLexics = {
available_matches_shown: 13385,
basketball: 6960,
broadcast: 13049,
+ check_connection: 15700,
cm: 817,
features: 13051,
football: 6958,
@@ -96,6 +97,7 @@ export const indexLexics = {
live: 13024,
loading: 3527,
logout: 4306,
+ lost_connection: 15699,
match_status_finished: 12985,
match_status_live: 12984,
match_status_soon: 12986,
diff --git a/src/features/App/AuthenticatedApp.tsx b/src/features/App/AuthenticatedApp.tsx
index e861c774..a25d174b 100644
--- a/src/features/App/AuthenticatedApp.tsx
+++ b/src/features/App/AuthenticatedApp.tsx
@@ -20,6 +20,7 @@ import { MatchPopup, MatchPopupStore } from 'features/MatchPopup'
import { BuyMatchPopup, BuyMatchPopupStore } from 'features/BuyMatchPopup'
import { PreferencesPopup, PreferencesPopupStore } from 'features/PreferencesPopup'
import { CardsStore } from 'features/CardsStore'
+import { NoNetworkPopup, NoNetworkPopupStore } from 'features/NoNetworkPopup'
const HomePage = lazy(() => import('features/HomePage'))
const UserAccount = lazy(() => import('features/UserAccount'))
@@ -40,32 +41,35 @@ export const AuthenticatedApp = () => {
-
-
-
+
+
+
+
+
- {/* в Switch как прямой children можно рендерить только Route или Redirect */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {/* в Switch как прямой children можно рендерить только Route или Redirect */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/features/Background/index.tsx b/src/features/Background/index.tsx
index 4c6aabfe..5381a717 100644
--- a/src/features/Background/index.tsx
+++ b/src/features/Background/index.tsx
@@ -1,5 +1,7 @@
import { ReactNode } from 'react'
+import { FakeArrowLoader } from 'features/NoNetworkPopup/styled'
+
import { GradientBackground, ImageBackground } from './styled'
type Props = {
@@ -9,6 +11,9 @@ type Props = {
export const Background = ({ children }: Props) => (
+ {/* FakeArrowLoader пришлось добавить, чтобы при отсутствии интернета
+ всегда была доступена svg arrowGroup для отображения лоадера в NoNetwork */}
+
{children}
diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx
index e7ad840f..afe939f5 100644
--- a/src/features/MultiSourcePlayer/hooks/index.tsx
+++ b/src/features/MultiSourcePlayer/hooks/index.tsx
@@ -10,6 +10,7 @@ import size from 'lodash/size'
import { useControlsVisibility } from 'features/StreamPlayer/hooks/useControlsVisibility'
import { useFullscreen } from 'features/StreamPlayer/hooks/useFullscreen'
import { useVolume } from 'features/VideoPlayer/hooks/useVolume'
+import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
import { useObjectState } from 'hooks'
@@ -70,6 +71,7 @@ export const useMultiSourcePlayer = ({
onReady,
playNextChapter,
playPrevChapter,
+ stopPlaying,
togglePlaying,
} = usePlayingHandlers(setPlayerState, numberOfChapters)
@@ -203,6 +205,17 @@ export const useMultiSourcePlayer = ({
playNextChapter,
])
+ const { isOnline } = useNoNetworkPopupStore()
+
+ useEffect(() => {
+ if (!isOnline) {
+ stopPlaying()
+ }
+ }, [
+ isOnline,
+ stopPlaying,
+ ])
+
return {
activeChapterIndex,
activePlayer,
diff --git a/src/features/NoNetworkPopup/index.tsx b/src/features/NoNetworkPopup/index.tsx
new file mode 100644
index 00000000..3ad1b6c6
--- /dev/null
+++ b/src/features/NoNetworkPopup/index.tsx
@@ -0,0 +1,32 @@
+import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
+import { Background } from 'features/Background'
+
+import {
+ ArrowLoader,
+ Container,
+ Logo,
+ SubTitle,
+ Title,
+ Wrapper,
+} from './styled'
+
+export * from './store'
+
+export const NoNetworkPopup = () => {
+ const { isOnline } = useNoNetworkPopupStore()
+
+ if (isOnline) return null
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/features/NoNetworkPopup/store/hooks/index.tsx b/src/features/NoNetworkPopup/store/hooks/index.tsx
new file mode 100644
index 00000000..4d2b098d
--- /dev/null
+++ b/src/features/NoNetworkPopup/store/hooks/index.tsx
@@ -0,0 +1,23 @@
+import { useState } from 'react'
+
+import { useEventListener } from 'hooks'
+
+export const useNetwork = () => {
+ const [isOnline, setNetwork] = useState(window.navigator.onLine)
+
+ const updateNetwork = () => {
+ setNetwork(window.navigator.onLine)
+ }
+
+ useEventListener({
+ callback: updateNetwork,
+ event: 'offline',
+ })
+
+ useEventListener({
+ callback: updateNetwork,
+ event: 'online',
+ })
+
+ return { isOnline }
+}
diff --git a/src/features/NoNetworkPopup/store/index.tsx b/src/features/NoNetworkPopup/store/index.tsx
new file mode 100644
index 00000000..75852472
--- /dev/null
+++ b/src/features/NoNetworkPopup/store/index.tsx
@@ -0,0 +1,20 @@
+import type { ReactNode } from 'react'
+import { createContext, useContext } from 'react'
+
+import { useNetwork } from './hooks'
+
+type Context = ReturnType
+type Props = { children: ReactNode }
+
+const NoNetworkPopupContext = createContext({} as Context)
+
+export const NoNetworkPopupStore = ({ children }: Props) => {
+ const value = useNetwork()
+ return (
+
+ {children}
+
+ )
+}
+
+export const useNoNetworkPopupStore = () => useContext(NoNetworkPopupContext)
diff --git a/src/features/NoNetworkPopup/styled.tsx b/src/features/NoNetworkPopup/styled.tsx
new file mode 100644
index 00000000..50163c6b
--- /dev/null
+++ b/src/features/NoNetworkPopup/styled.tsx
@@ -0,0 +1,81 @@
+import styled from 'styled-components/macro'
+
+import { Arrows } from 'features/ArrowLoader/styled'
+import { T9n } from 'features/T9n'
+
+export const Wrapper = styled.div`
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ z-index: 1000;
+`
+
+export const Container = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #FFFFFF;
+`
+
+export const Logo = styled.div`
+ width: 234px;
+ height: 54px;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-image: url(/images/logo.svg);
+ margin-bottom: 87px;
+
+ @media (max-width: 850px) {
+ width: 144px;
+ height: 33px;
+ margin-bottom: 54px;
+ }
+`
+
+export const FakeArrowLoader = styled.div`
+ width: 0;
+ height: 0;
+ visibility: hidden;
+ background-image: url(/images/arrowGroup.svg);
+`
+
+export const ArrowLoader = styled(Arrows)`
+ width: 94px;
+ height: 87px;
+
+ @media (max-width: 850px) {
+ width: 58px;
+ height: 54px;
+ }
+`
+
+export const Title = styled(T9n)`
+ font-weight: bold;
+ font-size: 24px;
+ line-height: 24px;
+ margin-top: 87px;
+
+ @media (max-width: 850px) {
+ font-size: 14px;
+ line-height: 15px;
+ margin-top: 54px;
+ }
+`
+
+export const SubTitle = styled(T9n)`
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 20px;
+ letter-spacing: 0.03em;
+ opacity: 0.8;
+ margin-top: 12px;
+
+ @media (max-width: 850px) {
+ font-size: 10px;
+ line-height: 12px;
+ margin-top: 7px;
+ }
+`
diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx
index 88ee0e3f..86c5afbc 100644
--- a/src/features/StreamPlayer/hooks/index.tsx
+++ b/src/features/StreamPlayer/hooks/index.tsx
@@ -1,10 +1,15 @@
import type { MouseEvent } from 'react'
-import { useCallback, useMemo } from 'react'
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+} from 'react'
import once from 'lodash/once'
import { useVolume } from 'features/VideoPlayer/hooks/useVolume'
import { REWIND_SECONDS } from 'features/MultiSourcePlayer/config'
+import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
import { useObjectState } from 'hooks'
@@ -112,6 +117,19 @@ export const useVideoPlayer = ({
setPlayerState({ playedProgress: liveProgressMs, seek: liveProgressMs / 1000 })
}, [duration, setPlayerState])
+ const { isOnline } = useNoNetworkPopupStore()
+
+ useEffect(() => {
+ if (!isOnline) {
+ setPlayerState({ playing: false })
+ onPlayingChange(false)
+ }
+ }, [
+ isOnline,
+ onPlayingChange,
+ setPlayerState,
+ ])
+
return {
backToLive,
duration,