From fcaa0015e5b5116cbbd7c6c07b82bf721608b393 Mon Sep 17 00:00:00 2001 From: Rakov Date: Mon, 29 May 2023 11:15:40 +0300 Subject: [PATCH] fix(sentry): sentry bug fix --- package-lock.json | 105 ++++++++++++++++++ package.json | 1 + src/components/ErrorBoundary/index.tsx | 54 +++------ src/components/PictureInPicture/PiP.tsx | 31 ++++-- src/features/App/index.tsx | 2 +- src/features/AuthStore/hooks/useAuth.tsx | 2 +- .../components/FavouriteTeam/hooks.tsx | 10 +- .../Controls/Components/ControlsWeb/index.tsx | 2 +- .../PagePersonalInfo/hooks/index.tsx | 4 +- src/helpers/callApi/logoutIfUnauthorized.tsx | 9 +- src/hooks/usePageLogger.tsx | 4 +- src/index.tsx | 15 ++- src/requests/getFavouriteTeam.tsx | 2 +- src/requests/getMatches/getHomeMatches.tsx | 2 - src/requests/getMatches/getPlayerMatches.tsx | 2 - src/requests/getMatches/getPreviews.tsx | 82 -------------- src/requests/getMatches/getTeamMatches.tsx | 2 - .../getMatches/getTournamentMatches.tsx | 2 - 18 files changed, 179 insertions(+), 152 deletions(-) delete mode 100644 src/requests/getMatches/getPreviews.tsx diff --git a/package-lock.json b/package-lock.json index be12c447..a69b3e22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3616,6 +3616,111 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", "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": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", diff --git a/package.json b/package.json index 8e59a5b2..c023ddac 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@reactour/tour": "^3.3.0", + "@sentry/react": "^7.53.1", "@stripe/react-stripe-js": "^1.4.0", "@stripe/stripe-js": "^1.13.2", "babel-polyfill": "^6.26.0", diff --git a/src/components/ErrorBoundary/index.tsx b/src/components/ErrorBoundary/index.tsx index b3a27e45..4f3ad182 100644 --- a/src/components/ErrorBoundary/index.tsx +++ b/src/components/ErrorBoundary/index.tsx @@ -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' @@ -10,41 +10,15 @@ interface Props { children?: ReactNode, } -interface State { - hasError: boolean, -} - -class ErrorBoundary extends Component { - // eslint-disable-next-line react/state-in-constructor - public state: State = { - hasError: false, - } - - 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 && } - {children} - - ) - } -} +export const ErrorBoundary = ({ children }: Props) => ( + + {children} + + + )} + > + { children } + +) -export default ErrorBoundary diff --git a/src/components/PictureInPicture/PiP.tsx b/src/components/PictureInPicture/PiP.tsx index 7584fb28..bd509707 100644 --- a/src/components/PictureInPicture/PiP.tsx +++ b/src/components/PictureInPicture/PiP.tsx @@ -1,5 +1,4 @@ import { - memo, RefObject, useEffect, } from 'react' @@ -17,11 +16,10 @@ const PipWrapper = styled.div` ` type PipProps = { - isPlaying: boolean, videoRef: RefObject, } -export const PiP = memo(({ isPlaying, videoRef }: PipProps) => { +export const PiP = ({ videoRef }: PipProps) => { const { user } = useAuthStore() const togglePip = async () => { try { @@ -38,23 +36,38 @@ export const PiP = memo(({ isPlaying, videoRef }: PipProps) => { } useEffect(() => { - window.addEventListener('visibilitychange', async () => { + const onVisibilityChange = async () => { if ( document.hidden === true && document.pictureInPictureEnabled && videoRef.current !== document.pictureInPictureElement && videoRef.current?.hidden === false - && isPlaying + && !videoRef.current?.paused + && document.visibilityState !== 'visible' && 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 ( ) -}) +} diff --git a/src/features/App/index.tsx b/src/features/App/index.tsx index af66da71..d65ffd0a 100644 --- a/src/features/App/index.tsx +++ b/src/features/App/index.tsx @@ -23,7 +23,7 @@ import { GlobalStyles } from 'features/GlobalStyles' import { Theme } from 'features/Theme' import { UnavailableText } from 'components/UnavailableText' -import ErrorBoundary from 'components/ErrorBoundary' +import { ErrorBoundary } from 'components/ErrorBoundary' import { AuthenticatedApp } from './AuthenticatedApp' import { useAuthStore } from '../AuthStore' diff --git a/src/features/AuthStore/hooks/useAuth.tsx b/src/features/AuthStore/hooks/useAuth.tsx index c31be46b..558d4df0 100644 --- a/src/features/AuthStore/hooks/useAuth.tsx +++ b/src/features/AuthStore/hooks/useAuth.tsx @@ -105,7 +105,7 @@ export const useAuth = () => { token && await fetchUserInfo() return Promise.resolve() } - return Promise.reject() + return Promise.resolve() } storeUser(loadedUser) diff --git a/src/features/MatchPage/components/FavouriteTeam/hooks.tsx b/src/features/MatchPage/components/FavouriteTeam/hooks.tsx index c0a7b3b8..757cdd5e 100644 --- a/src/features/MatchPage/components/FavouriteTeam/hooks.tsx +++ b/src/features/MatchPage/components/FavouriteTeam/hooks.tsx @@ -38,21 +38,21 @@ export const useFavouriteTeam = () => { useEffect(() => { (async () => { - const { data: { data: teams1 }, status }: ResponseType = await getFavouriteTeam({ + const { data: teams1, status }: ResponseType = await getFavouriteTeam({ country_id: 77, season: 30, sport_id: 1, tournament_id: 131, }) - const { data: { data: teams2 } }: ResponseType = await getFavouriteTeam({ + const { data: teams2 }: ResponseType = await getFavouriteTeam({ country_id: 77, season: 30, sport_id: 1, tournament_id: 2032, }) - if (!status) { - setGroup1(sortTeam(teams1)) - setGroup2(sortTeam(teams2)) + if (!status && teams1?.data && teams2?.data) { + setGroup1(sortTeam(teams1?.data)) + setGroup2(sortTeam(teams2?.data)) setIsOpen(true) } })() diff --git a/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx b/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx index 7b4ad837..7575cb8a 100644 --- a/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx +++ b/src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx @@ -120,7 +120,7 @@ export const ControlsWeb = (controlsProps: { props: ControlsPropsExtended }) => )} {document.pictureInPictureEnabled && ( - + )} { const cities = userInfo.country?.id ? await getCountryCities('', userInfo.country.id) @@ -87,7 +89,7 @@ export const useUserInfo = () => { }, [fetchUserInfo]) useEffect(() => { - fetchUserInfo() + readToken() && fetchUserInfo() }, [fetchUserInfo]) return { diff --git a/src/helpers/callApi/logoutIfUnauthorized.tsx b/src/helpers/callApi/logoutIfUnauthorized.tsx index 18e71881..d9958362 100644 --- a/src/helpers/callApi/logoutIfUnauthorized.tsx +++ b/src/helpers/callApi/logoutIfUnauthorized.tsx @@ -1,5 +1,13 @@ +import * as Sentry from '@sentry/react' + 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) { window.dispatchEvent(new Event('FORBIDDEN_REQUEST')) } @@ -8,6 +16,5 @@ export const logoutIfUnauthorized = async (response: Response) => { // eslint-disable-next-line no-console console.error(error) - const body = await response.json() return Promise.reject(body) } diff --git a/src/hooks/usePageLogger.tsx b/src/hooks/usePageLogger.tsx index a45a539b..50437201 100644 --- a/src/hooks/usePageLogger.tsx +++ b/src/hooks/usePageLogger.tsx @@ -9,6 +9,8 @@ import round from 'lodash/round' import { LogActions, logUserAction } from 'requests/logUserAction' +import { readToken } from 'helpers' + export const usePageLogger = (page?: string) => { const location = useLocation() const startTimeRef = useRef(new Date()) @@ -24,7 +26,7 @@ export const usePageLogger = (page?: string) => { const url = page || location.pathname const log = useCallback(() => { - logUserAction({ + readToken() && logUserAction({ actionType: LogActions.PageChange, dateVisit: startTimeRef.current.toISOString(), duration: getSpentTime(), diff --git a/src/index.tsx b/src/index.tsx index 81041121..8622573d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,11 +5,24 @@ import { } from 'react' 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 * 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' ? lazy(() => import('features/AuthServiceApp')) : lazy(() => import('features/App')) diff --git a/src/requests/getFavouriteTeam.tsx b/src/requests/getFavouriteTeam.tsx index 23bc47c4..50b44cfd 100644 --- a/src/requests/getFavouriteTeam.tsx +++ b/src/requests/getFavouriteTeam.tsx @@ -20,7 +20,7 @@ export type FavouriteTeams = { export type ResponseType = { data: { data: Array, - }, + } | null, msg: string, status: string, } diff --git a/src/requests/getMatches/getHomeMatches.tsx b/src/requests/getMatches/getHomeMatches.tsx index e14b7cdf..37d382bd 100644 --- a/src/requests/getMatches/getHomeMatches.tsx +++ b/src/requests/getMatches/getHomeMatches.tsx @@ -4,7 +4,6 @@ import { client } from 'config/clients' import type { MatchesBySection } from './types' import { requestMatches } from './request' -import { getMatchesPreviews } from './getPreviews' const proc = PROCEDURES.get_matches @@ -34,5 +33,4 @@ export const getHomeMatches = async ({ } return requestMatches(config, url) - .then(getMatchesPreviews) } diff --git a/src/requests/getMatches/getPlayerMatches.tsx b/src/requests/getMatches/getPlayerMatches.tsx index 5e181474..31684f63 100644 --- a/src/requests/getMatches/getPlayerMatches.tsx +++ b/src/requests/getMatches/getPlayerMatches.tsx @@ -10,7 +10,6 @@ import { addSportType } from 'features/Matches/helpers/addSportType' import type { MatchesBySection } from './types' import { requestMatches } from './request' -import { getMatchesPreviews } from './getPreviews' const proc = PROCEDURES.get_player_matches @@ -47,5 +46,4 @@ export const getPlayerMatches = async ({ return requestMatches(config, url) .then((matches) => addSportType(matches, sportType)) - .then(getMatchesPreviews) } diff --git a/src/requests/getMatches/getPreviews.tsx b/src/requests/getMatches/getPreviews.tsx deleted file mode 100644 index 61ea2233..00000000 --- a/src/requests/getMatches/getPreviews.tsx +++ /dev/null @@ -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 - } -} diff --git a/src/requests/getMatches/getTeamMatches.tsx b/src/requests/getMatches/getTeamMatches.tsx index 2501e9aa..555fc804 100644 --- a/src/requests/getMatches/getTeamMatches.tsx +++ b/src/requests/getMatches/getTeamMatches.tsx @@ -9,7 +9,6 @@ import { client } from 'config/clients' import { addSportType } from 'features/Matches/helpers/addSportType' import type { MatchesBySection } from './types' -import { getMatchesPreviews } from './getPreviews' import { requestMatches } from './request' const proc = PROCEDURES.get_team_matches @@ -41,5 +40,4 @@ export const getTeamMatches = async ({ return requestMatches(config, url) .then((matches) => addSportType(matches, sportType)) - .then(getMatchesPreviews) } diff --git a/src/requests/getMatches/getTournamentMatches.tsx b/src/requests/getMatches/getTournamentMatches.tsx index 2e09f143..e10cf687 100644 --- a/src/requests/getMatches/getTournamentMatches.tsx +++ b/src/requests/getMatches/getTournamentMatches.tsx @@ -9,7 +9,6 @@ import { client } from 'config/clients' import { addSportType } from 'features/Matches/helpers/addSportType' import type { MatchesBySection } from './types' -import { getMatchesPreviews } from './getPreviews' import { requestMatches } from './request' const proc = PROCEDURES.get_tournament_matches @@ -41,5 +40,4 @@ export const getTournamentMatches = async ({ return requestMatches(config, url) .then((matches) => addSportType(matches, sportType)) - .then(getMatchesPreviews) }