fix(sentry): sentry bug fix #223

Merged
andrey.dekterev merged 1 commits from in-643-sentry-bug-fix into develop 3 years ago
  1. 105
      package-lock.json
  2. 1
      package.json
  3. 54
      src/components/ErrorBoundary/index.tsx
  4. 31
      src/components/PictureInPicture/PiP.tsx
  5. 2
      src/features/App/index.tsx
  6. 2
      src/features/AuthStore/hooks/useAuth.tsx
  7. 10
      src/features/MatchPage/components/FavouriteTeam/hooks.tsx
  8. 2
      src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx
  9. 4
      src/features/UserAccount/components/PagePersonalInfo/hooks/index.tsx
  10. 9
      src/helpers/callApi/logoutIfUnauthorized.tsx
  11. 4
      src/hooks/usePageLogger.tsx
  12. 15
      src/index.tsx
  13. 2
      src/requests/getFavouriteTeam.tsx
  14. 2
      src/requests/getMatches/getHomeMatches.tsx
  15. 2
      src/requests/getMatches/getPlayerMatches.tsx
  16. 82
      src/requests/getMatches/getPreviews.tsx
  17. 2
      src/requests/getMatches/getTeamMatches.tsx
  18. 2
      src/requests/getMatches/getTournamentMatches.tsx

105
package-lock.json generated

@ -3616,6 +3616,111 @@
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg=="
}, },
"@sentry-internal/tracing": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.53.1.tgz",
"integrity": "sha512-a4H4rvVdz0XDGgNfRqc7zg6rMt2P1P05xBmgfIfztYy94Vciw1QMdboNiT7einr8ra8wogdEaK4Pe2AzYAPBJQ==",
"requires": {
"@sentry/core": "7.53.1",
"@sentry/types": "7.53.1",
"@sentry/utils": "7.53.1",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/browser": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.53.1.tgz",
"integrity": "sha512-1zas2R6riJaj0k7FoeieCW0SuC7UyKaBGA6jEG2LsgIqyD7IDOlF3BPZ4Yt08GFav0ImpyhGn5Vbrq5JLbeQdw==",
"requires": {
"@sentry-internal/tracing": "7.53.1",
"@sentry/core": "7.53.1",
"@sentry/replay": "7.53.1",
"@sentry/types": "7.53.1",
"@sentry/utils": "7.53.1",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/core": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.53.1.tgz",
"integrity": "sha512-DAH8IJNORJJ7kQLqsZuhMkN6cwJjXzFuuUoZor7IIDHIHjtl51W+2F3Stg3+I3ZoKDfJfUNKqhipk2WZjG0FBg==",
"requires": {
"@sentry/types": "7.53.1",
"@sentry/utils": "7.53.1",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/react": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.53.1.tgz",
"integrity": "sha512-eEOY/peBepSD/nhPn4SU77aYdjQfAI1svOqpG4sbpjaGZU1P6L7+IIGmip8l2T68oPEeKDaiH9Qy/3uxu55B/Q==",
"requires": {
"@sentry/browser": "7.53.1",
"@sentry/types": "7.53.1",
"@sentry/utils": "7.53.1",
"hoist-non-react-statics": "^3.3.2",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sentry/replay": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.53.1.tgz",
"integrity": "sha512-5He5JLJiYLeWtXHC53z2ZzfbgAedafbHNZVS4+MBCOtydCk7cnuyJ0gGV6Rfxej/lZSNXZxOdW7HeMhzBtZCxw==",
"requires": {
"@sentry/core": "7.53.1",
"@sentry/types": "7.53.1",
"@sentry/utils": "7.53.1"
}
},
"@sentry/types": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.53.1.tgz",
"integrity": "sha512-/ijchRIu+jz3+j/zY+7KRPfLSCY14fTx5xujjbOdmEKjmIHQmwPBdszcQm40uwofrR8taV4hbt5MFN+WnjCkCw=="
},
"@sentry/utils": {
"version": "7.53.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.53.1.tgz",
"integrity": "sha512-DKJA1LSUOEv4KOR828MzVuLh+drjeAgzyKgN063OEKmnirgjgRgNNS8wUgwpG0Tn2k6ANZGCwrdfzPeSBxshKg==",
"requires": {
"@sentry/types": "7.53.1",
"tslib": "^1.9.3"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"@sinclair/typebox": { "@sinclair/typebox": {
"version": "0.24.51", "version": "0.24.51",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz",

@ -23,6 +23,7 @@
}, },
"dependencies": { "dependencies": {
"@reactour/tour": "^3.3.0", "@reactour/tour": "^3.3.0",
"@sentry/react": "^7.53.1",
"@stripe/react-stripe-js": "^1.4.0", "@stripe/react-stripe-js": "^1.4.0",
"@stripe/stripe-js": "^1.13.2", "@stripe/stripe-js": "^1.13.2",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",

@ -1,8 +1,8 @@
// eslint-disable react/destructuring-assignment import React from 'react'
import { Component } from 'react' import type{ ReactNode } from 'react'
import type{ ErrorInfo, ReactNode } from 'react' import * as Sentry from '@sentry/react'
import { Error } from '../Error' import { Error } from '../Error'
@ -10,41 +10,15 @@ interface Props {
children?: ReactNode, children?: ReactNode,
} }
interface State { export const ErrorBoundary = ({ children }: Props) => (
hasError: boolean, <Sentry.ErrorBoundary fallback={(
} <>
{children}
class ErrorBoundary extends Component<Props, State> { <Error />
// eslint-disable-next-line react/state-in-constructor </>
public state: State = { )}
hasError: false, >
} { children }
</Sentry.ErrorBoundary>
public static getDerivedStateFromError(_: Error): State { )
// Update state so the next render will show the fallback UI.
return { hasError: true }
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
// eslint-disable-next-line no-console
console.error(
'Uncaught error:',
error,
errorInfo,
)
}
public render() {
const { hasError } = this.state
const { children } = this.props
return (
<>
{hasError && <Error />}
{children}
</>
)
}
}
export default ErrorBoundary

@ -1,5 +1,4 @@
import { import {
memo,
RefObject, RefObject,
useEffect, useEffect,
} from 'react' } from 'react'
@ -17,11 +16,10 @@ const PipWrapper = styled.div`
` `
type PipProps = { type PipProps = {
isPlaying: boolean,
videoRef: RefObject<HTMLVideoElement>, videoRef: RefObject<HTMLVideoElement>,
} }
export const PiP = memo(({ isPlaying, videoRef }: PipProps) => { export const PiP = ({ videoRef }: PipProps) => {
const { user } = useAuthStore() const { user } = useAuthStore()
const togglePip = async () => { const togglePip = async () => {
try { try {
@ -38,23 +36,38 @@ export const PiP = memo(({ isPlaying, videoRef }: PipProps) => {
} }
useEffect(() => { useEffect(() => {
window.addEventListener('visibilitychange', async () => { const onVisibilityChange = async () => {
if ( if (
document.hidden === true document.hidden === true
&& document.pictureInPictureEnabled && document.pictureInPictureEnabled
&& videoRef.current !== document.pictureInPictureElement && videoRef.current !== document.pictureInPictureElement
&& videoRef.current?.hidden === false && videoRef.current?.hidden === false
&& isPlaying && !videoRef.current?.paused
&& document.visibilityState !== 'visible'
&& user && user
) { ) {
await videoRef.current?.requestPictureInPicture() try {
await videoRef.current?.requestPictureInPicture()
} catch (error) { /* empty */ }
}
if (
document.visibilityState === 'visible'
&& document.pictureInPictureEnabled
&& videoRef.current === document.pictureInPictureElement
) {
try {
await document.exitPictureInPicture()
} catch (error) { /* empty */ }
} }
}) }
}, [videoRef, isPlaying, user]) window.addEventListener('visibilitychange', onVisibilityChange)
return () => window.removeEventListener('visibilitychange', onVisibilityChange)
}, [videoRef, user])
return ( return (
<PipWrapper id='match_video_pic_in_pic'> <PipWrapper id='match_video_pic_in_pic'>
<Icon refIcon='PiP' onClick={togglePip} /> <Icon refIcon='PiP' onClick={togglePip} />
</PipWrapper> </PipWrapper>
) )
}) }

@ -23,7 +23,7 @@ import { GlobalStyles } from 'features/GlobalStyles'
import { Theme } from 'features/Theme' import { Theme } from 'features/Theme'
import { UnavailableText } from 'components/UnavailableText' import { UnavailableText } from 'components/UnavailableText'
import ErrorBoundary from 'components/ErrorBoundary' import { ErrorBoundary } from 'components/ErrorBoundary'
import { AuthenticatedApp } from './AuthenticatedApp' import { AuthenticatedApp } from './AuthenticatedApp'
import { useAuthStore } from '../AuthStore' import { useAuthStore } from '../AuthStore'

@ -105,7 +105,7 @@ export const useAuth = () => {
token && await fetchUserInfo() token && await fetchUserInfo()
return Promise.resolve() return Promise.resolve()
} }
return Promise.reject() return Promise.resolve()
} }
storeUser(loadedUser) storeUser(loadedUser)

@ -38,21 +38,21 @@ export const useFavouriteTeam = () => {
useEffect(() => { useEffect(() => {
(async () => { (async () => {
const { data: { data: teams1 }, status }: ResponseType = await getFavouriteTeam({ const { data: teams1, status }: ResponseType = await getFavouriteTeam({
country_id: 77, country_id: 77,
season: 30, season: 30,
sport_id: 1, sport_id: 1,
tournament_id: 131, tournament_id: 131,
}) })
const { data: { data: teams2 } }: ResponseType = await getFavouriteTeam({ const { data: teams2 }: ResponseType = await getFavouriteTeam({
country_id: 77, country_id: 77,
season: 30, season: 30,
sport_id: 1, sport_id: 1,
tournament_id: 2032, tournament_id: 2032,
}) })
if (!status) { if (!status && teams1?.data && teams2?.data) {
setGroup1(sortTeam(teams1)) setGroup1(sortTeam(teams1?.data))
setGroup2(sortTeam(teams2)) setGroup2(sortTeam(teams2?.data))
setIsOpen(true) setIsOpen(true)
} }
})() })()

@ -120,7 +120,7 @@ export const ControlsWeb = (controlsProps: { props: ControlsPropsExtended }) =>
)} )}
<ChromeCast src={src} /> <ChromeCast src={src} />
{document.pictureInPictureEnabled && ( {document.pictureInPictureEnabled && (
<PiP videoRef={videoRef} isPlaying={playing} /> <PiP videoRef={videoRef} />
)} )}
<Settings <Settings
onSelect={onQualitySelect} onSelect={onQualitySelect}

@ -23,6 +23,8 @@ import {
import type { FormState } from 'features/FormStore/hooks/useFormState' import type { FormState } from 'features/FormStore/hooks/useFormState'
import { useLexicsStore } from 'features/LexicsStore' import { useLexicsStore } from 'features/LexicsStore'
import { readToken } from 'helpers'
const transformToFormState = async (userInfo: UserInfo, lang: string) => { const transformToFormState = async (userInfo: UserInfo, lang: string) => {
const cities = userInfo.country?.id const cities = userInfo.country?.id
? await getCountryCities('', userInfo.country.id) ? await getCountryCities('', userInfo.country.id)
@ -87,7 +89,7 @@ export const useUserInfo = () => {
}, [fetchUserInfo]) }, [fetchUserInfo])
useEffect(() => { useEffect(() => {
fetchUserInfo() readToken() && fetchUserInfo()
}, [fetchUserInfo]) }, [fetchUserInfo])
return { return {

@ -1,5 +1,13 @@
import * as Sentry from '@sentry/react'
export const logoutIfUnauthorized = async (response: Response) => { export const logoutIfUnauthorized = async (response: Response) => {
/* отключили из-за доступа без авторизации */ /* отключили из-за доступа без авторизации */
const body = await response.json()
if (response.status === 400) {
Sentry.captureException(body)
}
if (response.status === 401 || response.status === 403) { if (response.status === 401 || response.status === 403) {
window.dispatchEvent(new Event('FORBIDDEN_REQUEST')) window.dispatchEvent(new Event('FORBIDDEN_REQUEST'))
} }
@ -8,6 +16,5 @@ export const logoutIfUnauthorized = async (response: Response) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(error) console.error(error)
const body = await response.json()
return Promise.reject(body) return Promise.reject(body)
} }

@ -9,6 +9,8 @@ import round from 'lodash/round'
import { LogActions, logUserAction } from 'requests/logUserAction' import { LogActions, logUserAction } from 'requests/logUserAction'
import { readToken } from 'helpers'
export const usePageLogger = (page?: string) => { export const usePageLogger = (page?: string) => {
const location = useLocation() const location = useLocation()
const startTimeRef = useRef(new Date()) const startTimeRef = useRef(new Date())
@ -24,7 +26,7 @@ export const usePageLogger = (page?: string) => {
const url = page || location.pathname const url = page || location.pathname
const log = useCallback(() => { const log = useCallback(() => {
logUserAction({ readToken() && logUserAction({
actionType: LogActions.PageChange, actionType: LogActions.PageChange,
dateVisit: startTimeRef.current.toISOString(), dateVisit: startTimeRef.current.toISOString(),
duration: getSpentTime(), duration: getSpentTime(),

@ -5,11 +5,24 @@ import {
} from 'react' } from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { isIOS } from 'config/userAgent' import * as Sentry from '@sentry/react'
import { BrowserTracing } from '@sentry/react'
import { isIOS, ENV } from 'config'
// import { makeServer } from 'utilits/mirage/Mirage' // import { makeServer } from 'utilits/mirage/Mirage'
import * as serviceWorker from './serviceWorker' import * as serviceWorker from './serviceWorker'
if (process.env.NODE_ENV !== 'development') {
Sentry.init({
dsn: 'https://bbe0cdfb954644ebaf3be16bb472cc3d@sentry.insports.tv/21',
environment: ENV,
integrations: [new BrowserTracing()],
tracesSampleRate: 1.0,
})
}
export const App = process.env.REACT_APP_TYPE === 'auth-service' export const App = process.env.REACT_APP_TYPE === 'auth-service'
? lazy(() => import('features/AuthServiceApp')) ? lazy(() => import('features/AuthServiceApp'))
: lazy(() => import('features/App')) : lazy(() => import('features/App'))

@ -20,7 +20,7 @@ export type FavouriteTeams = {
export type ResponseType = { export type ResponseType = {
data: { data: {
data: Array<FavouriteTeams>, data: Array<FavouriteTeams>,
}, } | null,
msg: string, msg: string,
status: string, status: string,
} }

@ -4,7 +4,6 @@ import { client } from 'config/clients'
import type { MatchesBySection } from './types' import type { MatchesBySection } from './types'
import { requestMatches } from './request' import { requestMatches } from './request'
import { getMatchesPreviews } from './getPreviews'
const proc = PROCEDURES.get_matches const proc = PROCEDURES.get_matches
@ -34,5 +33,4 @@ export const getHomeMatches = async ({
} }
return requestMatches(config, url) return requestMatches(config, url)
.then(getMatchesPreviews)
} }

@ -10,7 +10,6 @@ import { addSportType } from 'features/Matches/helpers/addSportType'
import type { MatchesBySection } from './types' import type { MatchesBySection } from './types'
import { requestMatches } from './request' import { requestMatches } from './request'
import { getMatchesPreviews } from './getPreviews'
const proc = PROCEDURES.get_player_matches const proc = PROCEDURES.get_player_matches
@ -47,5 +46,4 @@ export const getPlayerMatches = async ({
return requestMatches(config, url) return requestMatches(config, url)
.then((matches) => addSportType(matches, sportType)) .then((matches) => addSportType(matches, sportType))
.then(getMatchesPreviews)
} }

@ -1,82 +0,0 @@
import isEmpty from 'lodash/isEmpty'
import reduce from 'lodash/reduce'
import find from 'lodash/find'
import map from 'lodash/map'
import type { PreviewsData, Previews } from 'requests'
import { getMatchesPreviewImages } from 'requests'
import type { MatchesBySection, Matches } from './types'
const combinePreviews = (matches: Matches, previews: Previews) => (
map(matches, (match) => {
const preview = find(
previews,
{ match_id: match.id, sport_id: match.sport },
)?.preview
return preview ? { ...match, preview } : match
})
)
/**
* Запрашивает превью картинок матчей с видео и статус которых Завершенный
*/
const getPreviews = async (matches: Matches) => {
const previewsData = reduce(
matches,
(acc: PreviewsData, {
has_video,
id,
sport,
}) => {
if (has_video) {
acc.push({
match_id: id,
sport_id: sport,
})
}
return acc
},
[],
)
if (isEmpty(previewsData)) return matches
const previews = await getMatchesPreviewImages(previewsData)
return combinePreviews(matches, previews)
}
export const getMatchesPreviews = async (matches: MatchesBySection) => {
try {
if (matches.isVideoSections) {
const [
broadcast,
features,
highlights,
] = await Promise.all(
[
getPreviews(matches.broadcast),
getPreviews(matches.features),
getPreviews(matches.highlights),
],
)
return {
...matches,
broadcast,
features,
highlights,
}
}
const broadcast = await getPreviews(matches.broadcast)
return {
...matches,
broadcast,
features: [],
highlights: [],
}
} catch (error) {
return matches
}
}

@ -9,7 +9,6 @@ import { client } from 'config/clients'
import { addSportType } from 'features/Matches/helpers/addSportType' import { addSportType } from 'features/Matches/helpers/addSportType'
import type { MatchesBySection } from './types' import type { MatchesBySection } from './types'
import { getMatchesPreviews } from './getPreviews'
import { requestMatches } from './request' import { requestMatches } from './request'
const proc = PROCEDURES.get_team_matches const proc = PROCEDURES.get_team_matches
@ -41,5 +40,4 @@ export const getTeamMatches = async ({
return requestMatches(config, url) return requestMatches(config, url)
.then((matches) => addSportType(matches, sportType)) .then((matches) => addSportType(matches, sportType))
.then(getMatchesPreviews)
} }

@ -9,7 +9,6 @@ import { client } from 'config/clients'
import { addSportType } from 'features/Matches/helpers/addSportType' import { addSportType } from 'features/Matches/helpers/addSportType'
import type { MatchesBySection } from './types' import type { MatchesBySection } from './types'
import { getMatchesPreviews } from './getPreviews'
import { requestMatches } from './request' import { requestMatches } from './request'
const proc = PROCEDURES.get_tournament_matches const proc = PROCEDURES.get_tournament_matches
@ -41,5 +40,4 @@ export const getTournamentMatches = async ({
return requestMatches(config, url) return requestMatches(config, url)
.then((matches) => addSportType(matches, sportType)) .then((matches) => addSportType(matches, sportType))
.then(getMatchesPreviews)
} }

Loading…
Cancel
Save