diff --git a/front/package-lock.json b/front/package-lock.json index 6824131..71ae8f0 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@react-three/drei": "^9.88.11", "@react-three/fiber": "^8.15.10", + "@sentry/react": "^7.86.0", + "@sentry/tracing": "^7.86.0", "@types/react-router-dom": "^5.3.3", "@types/styled-components": "^5.1.29", "@types/three": "^0.158.1", @@ -884,6 +886,121 @@ "node": ">=14.0.0" } }, + "node_modules/@sentry-internal/feedback": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.86.0.tgz", + "integrity": "sha512-6rl0JYjmAKnhm4/fuFaROh4Ht8oi9f6ZeIcViCuGJcrGICZJJY0s+R77XJI78rNa82PYFrSCcnWXcGji4T8E7g==", + "dependencies": { + "@sentry/core": "7.86.0", + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sentry-internal/tracing": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.86.0.tgz", + "integrity": "sha512-b4dUsNWlPWRwakGwR7bhOkqiFlqQszH1hhVFwrm/8s3kqEBZ+E4CeIfCvuHBHQ1cM/fx55xpXX/BU163cy+3iQ==", + "dependencies": { + "@sentry/core": "7.86.0", + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/browser": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.86.0.tgz", + "integrity": "sha512-nfYWpVOmug+W7KJO7/xhA1JScMZcYHcoOVHLsUFm4znx51U4qZEk+zZDM11Q2Nw6MuDyEYg6bsH1QCwaoC6nLw==", + "dependencies": { + "@sentry-internal/feedback": "7.86.0", + "@sentry-internal/tracing": "7.86.0", + "@sentry/core": "7.86.0", + "@sentry/replay": "7.86.0", + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/core": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.86.0.tgz", + "integrity": "sha512-SbLvqd1bRYzhDS42u7GMnmbDMfth/zRiLElQWbLK/shmuZzTcfQSwNNdF4Yj+VfjOkqPFgGmICHSHVUc9dh01g==", + "dependencies": { + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/react": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.86.0.tgz", + "integrity": "sha512-2bHi+YcG4cT+4xHXXzv+AZpU3pdPUlDBorSgHOpa9At4yxr17UWW2f8bP9wPYRgj+NEIM3YhDgR46FlBu9GSKg==", + "dependencies": { + "@sentry/browser": "7.86.0", + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0", + "hoist-non-react-statics": "^3.3.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": "15.x || 16.x || 17.x || 18.x" + } + }, + "node_modules/@sentry/replay": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.86.0.tgz", + "integrity": "sha512-YYZO8bfQSx1H87Te/zzyHPLHvExWiYwUfMWW68yGX+PPZIIzxaM81/iCQHkoucxlvuPCOtxCgf7RSMbsnqEa8g==", + "dependencies": { + "@sentry-internal/tracing": "7.86.0", + "@sentry/core": "7.86.0", + "@sentry/types": "7.86.0", + "@sentry/utils": "7.86.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sentry/tracing": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.86.0.tgz", + "integrity": "sha512-WPqgmbLm6ntpIoTZd1L/RHIVEDMmvVjIDxKeXGiJeXHZG2VMtgwoxuZAFluVFaD0Sr20Nhj+ZS7HvKOWTxrjjA==", + "dependencies": { + "@sentry-internal/tracing": "7.86.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/types": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.86.0.tgz", + "integrity": "sha512-pGAt0+bMfWgo0KG2epthfNV4Wae03tURpoxNjGo5Fr4cXxvLTSijSAQ6rmmO4bXBJ7+rErEjX30g30o/eEdP9g==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/utils": { + "version": "7.86.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.86.0.tgz", + "integrity": "sha512-6PejFtw9VTFFy5vu0ks+U7Ozkqz+eMt+HN8AZKBKErYzX5/xs0kpkOcSRpu3ETdTYcZf8VAmLVgFgE2BE+3WuQ==", + "dependencies": { + "@sentry/types": "7.86.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@swc/core": { "version": "1.3.96", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.96.tgz", diff --git a/front/package.json b/front/package.json index c1dd327..82ad52d 100644 --- a/front/package.json +++ b/front/package.json @@ -12,6 +12,7 @@ "dependencies": { "@react-three/drei": "^9.88.11", "@react-three/fiber": "^8.15.10", + "@sentry/react": "^7.86.0", "@types/react-router-dom": "^5.3.3", "@types/styled-components": "^5.1.29", "@types/three": "^0.158.1", diff --git a/front/src/App.tsx b/front/src/App.tsx index 7447212..f9cd2c7 100644 --- a/front/src/App.tsx +++ b/front/src/App.tsx @@ -9,6 +9,7 @@ import { SnowBallProvider } from '@pages/Visit/SnowBallProvider'; import { MessageProvider } from '@pages/Visit/MessageProvider'; import { DecoProvider } from '@pages/Visit/Deco/DecoProvider'; import { MessageListProvider } from '@pages/Visit/MessageListProvider'; +import * as Sentry from '@sentry/react'; const Outer = styled.div` position: relative; @@ -21,75 +22,75 @@ const Outer = styled.div` width: ${theme.size['--desktop-width']}; } `; - const App = () => { return ( <> - - - - - - - - - - } - /> + + + + + + + + + + + } + /> + + + + + + + + + + + } + > + } /> + } /> + + + + + + + + } + > + } /> + } /> + - + - + - - } - > - } /> - } /> - - - - - - - - } - > - } /> - } /> - - - - - - - - - - } - /> - - } /> - - - - + } + /> + } /> + + + + + ); }; diff --git a/front/src/components/Modal/Modal.tsx b/front/src/components/Modal/Modal.tsx index fbbd205..13de5ba 100644 --- a/front/src/components/Modal/Modal.tsx +++ b/front/src/components/Modal/Modal.tsx @@ -1,7 +1,7 @@ import { useState, useRef, useEffect, useContext } from 'react'; import { useNavigate } from 'react-router-dom'; import { createPortal } from 'react-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { theme } from '@utils'; import { @@ -157,8 +157,7 @@ const DeleteModal = (props: DeleteModalProps) => { setMessageList(messageList); setUserData(userData); }) - .catch(e => { - console.error(e); + .catch(() => { navigate('*'); }); }) diff --git a/front/src/index.tsx b/front/src/index.tsx index 8b2e56b..22ba625 100644 --- a/front/src/index.tsx +++ b/front/src/index.tsx @@ -1,5 +1,19 @@ import ReactDOM from 'react-dom/client'; import App from './App'; +import * as Sentry from '@sentry/react'; + +Sentry.init({ + dsn: import.meta.env.VITE_APP_SENTRY_DSN, + integrations: [ + new Sentry.BrowserTracing({ + tracePropagationTargets: ['localhost', /^https:\/\/mysnowball\.kr\/api/] + }), + new Sentry.Replay() + ], + tracesSampleRate: 1.0, + replaysSessionSampleRate: 0.1, + replaysOnErrorSampleRate: 1.0 +}); const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement diff --git a/front/src/pages/Main/ListMsgs.tsx b/front/src/pages/Main/ListMsgs.tsx index f64c426..fbfb27c 100644 --- a/front/src/pages/Main/ListMsgs.tsx +++ b/front/src/pages/Main/ListMsgs.tsx @@ -1,6 +1,6 @@ import { useEffect, useState, useContext } from 'react'; import { createPortal } from 'react-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { useLogout } from '@hooks'; import { ListMsg, Prev } from '@components'; @@ -98,7 +98,7 @@ const ListMsgs = (props: ListMsgProps) => { console.error(e); logout(); }); - }, []); + }, [userData]); return ( <> diff --git a/front/src/pages/Main/Main.tsx b/front/src/pages/Main/Main.tsx index e851a9f..3af801f 100644 --- a/front/src/pages/Main/Main.tsx +++ b/front/src/pages/Main/Main.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useContext, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useCookies } from 'react-cookie'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { Loading } from '@utils'; import { useLogout } from '@hooks'; @@ -49,7 +49,7 @@ const moveSnowball = ( const nextSnowBallID = userData.snowball_list[(nowSnowBallID + nextIdx) % userData.snowball_count]; - axios(`/api/snowball/${nextSnowBallID}`) + axios(`/api/snowball/${nextSnowBallID + 1000}`) .then(res => { setSnowBallData(res.data as SnowBallData); setMessageListData(res.data.message_list as Array); diff --git a/front/src/pages/Main/MainBody.tsx b/front/src/pages/Main/MainBody.tsx index 2536e76..c29b00c 100644 --- a/front/src/pages/Main/MainBody.tsx +++ b/front/src/pages/Main/MainBody.tsx @@ -1,5 +1,5 @@ import { useContext, useEffect } from 'react'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { Msg } from '@components'; import { MessageListContext, Message } from '@pages/Visit/MessageListProvider'; diff --git a/front/src/pages/Make/Nickname/Nickname.tsx b/front/src/pages/Make/Nickname/Nickname.tsx index 69f2c5f..a93f2eb 100644 --- a/front/src/pages/Make/Nickname/Nickname.tsx +++ b/front/src/pages/Make/Nickname/Nickname.tsx @@ -1,6 +1,6 @@ import { useState, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { theme } from '@utils'; import { Button } from '@components'; diff --git a/front/src/pages/Make/Snowball/MainDeco/DecoEnroll.tsx b/front/src/pages/Make/Snowball/MainDeco/DecoEnroll.tsx index 133d949..01d8830 100644 --- a/front/src/pages/Make/Snowball/MainDeco/DecoEnroll.tsx +++ b/front/src/pages/Make/Snowball/MainDeco/DecoEnroll.tsx @@ -1,6 +1,6 @@ import React, { useState, useRef } from 'react'; import { NavigateFunction, useNavigate } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { theme, BlurBody } from '@utils'; import { useLogout } from '@hooks'; diff --git a/front/src/pages/Make/Snowball/MainDeco/MakeButton.tsx b/front/src/pages/Make/Snowball/MainDeco/MakeButton.tsx index 36b9be3..1b2defe 100644 --- a/front/src/pages/Make/Snowball/MainDeco/MakeButton.tsx +++ b/front/src/pages/Make/Snowball/MainDeco/MakeButton.tsx @@ -1,6 +1,6 @@ import { useState, useContext } from 'react'; import { useNavigate } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { LongButton } from '@utils'; import { DecoContext } from './DecoProvider'; diff --git a/front/src/pages/Make/Snowball/Snowball.tsx b/front/src/pages/Make/Snowball/Snowball.tsx index 4de3d82..ab4801e 100644 --- a/front/src/pages/Make/Snowball/Snowball.tsx +++ b/front/src/pages/Make/Snowball/Snowball.tsx @@ -1,7 +1,7 @@ import { useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import styled from 'styled-components'; -import axios from 'axios'; +import axios from '@utils/axios'; import { Loading, theme } from '@utils'; import { SnowGlobeCanvas, Button } from '@components'; import { MainDeco } from './MainDeco'; diff --git a/front/src/pages/Visit/Deco/PostButton.tsx b/front/src/pages/Visit/Deco/PostButton.tsx index 4cec04e..20ac211 100644 --- a/front/src/pages/Visit/Deco/PostButton.tsx +++ b/front/src/pages/Visit/Deco/PostButton.tsx @@ -1,6 +1,6 @@ import { useContext, useState, useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import styled from 'styled-components'; import { LongButton } from '@utils'; import { DecoContext } from './DecoProvider'; diff --git a/front/src/pages/Visit/SnowBallProvider.tsx b/front/src/pages/Visit/SnowBallProvider.tsx index d734a16..453e468 100644 --- a/front/src/pages/Visit/SnowBallProvider.tsx +++ b/front/src/pages/Visit/SnowBallProvider.tsx @@ -1,5 +1,5 @@ import React, { useState, createContext } from 'react'; -import axios from 'axios'; +import axios from '@utils/axios'; import mockData from '@mock'; interface SnowBallData { diff --git a/front/src/pages/Visit/Visit.tsx b/front/src/pages/Visit/Visit.tsx index fc0da13..d924d64 100644 --- a/front/src/pages/Visit/Visit.tsx +++ b/front/src/pages/Visit/Visit.tsx @@ -1,6 +1,6 @@ import { useState, useContext, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; import { Loading } from '@utils'; import { SnowGlobeCanvas, UIContainer } from '@components'; import VisitHeader from './VisitHeader'; diff --git a/front/src/pages/Visit/VisitBody.tsx b/front/src/pages/Visit/VisitBody.tsx index 0beb69d..74bf8e5 100644 --- a/front/src/pages/Visit/VisitBody.tsx +++ b/front/src/pages/Visit/VisitBody.tsx @@ -1,6 +1,6 @@ import { useContext, useRef } from 'react'; import styled from 'styled-components'; -import axios from 'axios'; +import axios from '@utils/axios'; import { Msg } from '@components'; import { MessageContext } from './MessageProvider'; import { SnowBallContext, SnowBallData, UserData } from './SnowBallProvider'; diff --git a/front/src/router/HasSnowballData.tsx b/front/src/router/HasSnowballData.tsx index 4acb370..e547ce9 100644 --- a/front/src/router/HasSnowballData.tsx +++ b/front/src/router/HasSnowballData.tsx @@ -1,6 +1,6 @@ import React, { ReactNode, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import axios from 'axios'; +import axios from '@utils/axios'; // const saveCookie = () => { // const cookieToken = import.meta.env.VITE_APP_COOKIE_TOKEN; diff --git a/front/src/utils/axios.tsx b/front/src/utils/axios.tsx new file mode 100644 index 0000000..b5e0843 --- /dev/null +++ b/front/src/utils/axios.tsx @@ -0,0 +1,17 @@ +import axios from 'axios'; +import * as Sentry from '@sentry/react'; + +const instance = axios.create(); + +instance.interceptors.response.use( + response => response, // 성공적인 응답 처리 + error => { + // 오류 처리 + if (error.response && error.response.status !== 409) { + Sentry.captureException(error); + } + return Promise.reject(error); + } +); + +export default instance;