diff --git a/500.html b/500.html new file mode 100644 index 0000000..56939b6 --- /dev/null +++ b/500.html @@ -0,0 +1,180 @@ + + + + + + Velog Dashboard - 500 + + + +
+
+
+ VD +
+

Velog Dashboard

+
+ 알 수 없는 오류가 발생했습니다. +
+ + + + diff --git a/package.json b/package.json index 186bf20..5409b0f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dependencies": { "@channel.io/channel-web-sdk-loader": "^2.0.0", "@next/third-parties": "^15.1.7", + "@sentry/core": "^9.4.0", "@sentry/nextjs": "^8.47.0", "@tanstack/react-query": "^5.61.3", "@tanstack/react-query-devtools": "^5.62.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29ce0d1..85f3689 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@next/third-parties': specifier: ^15.1.7 version: 15.1.7(next@14.2.18(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@sentry/core': + specifier: ^9.4.0 + version: 9.4.0 '@sentry/nextjs': specifier: ^8.47.0 version: 8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@14.2.18(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.97.1) @@ -1499,6 +1502,10 @@ packages: resolution: {integrity: sha512-iSEJZMe3DOcqBFZQAqgA3NB2lCWBc4Gv5x/SCri/TVg96wAlss4VrUunSI2Mp0J4jJ5nJcJ2ChqHSBAU48k3FA==} engines: {node: '>=14.18'} + '@sentry/core@9.4.0': + resolution: {integrity: sha512-Edd/uWDGZ+1CMuVVWdxIOm1rBhzgpqiqz984TZu20wryoIoRsA8ZllUar6N+cWK17VusNY0OS2DozKO69y7fVQ==} + engines: {node: '>=18'} + '@sentry/nextjs@8.47.0': resolution: {integrity: sha512-qr++MBYhyAwF25hGq7LAxe3Xehs+w2V4b8mVxilRYFXNkWFazY1ukZcVzq9pKrrt5uTiURTf68e8eVMraHnHEQ==} engines: {node: '>=14.18'} @@ -6373,6 +6380,8 @@ snapshots: '@sentry/core@8.47.0': {} + '@sentry/core@9.4.0': {} + '@sentry/nextjs@8.47.0(@opentelemetry/core@1.30.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.56.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.0(@opentelemetry/api@1.9.0))(next@14.2.18(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.97.1)': dependencies: '@opentelemetry/api': 1.9.0 diff --git a/src/apis/instance.request.ts b/src/apis/instance.request.ts index 05ba80b..613fd03 100644 --- a/src/apis/instance.request.ts +++ b/src/apis/instance.request.ts @@ -75,10 +75,9 @@ export const instance = async ( return (data.body as unknown as SuccessType).data; } catch (err: unknown) { const context = err as Response; - if (location && !context.ok && context.status === 403) { + if (location && !context.ok && context.status === 401) { window.location.replace('/'); } - //context.status === 401 || setContext('Request', { path: context.url, status: context.status, diff --git a/src/app/(with-tracker)/(login)/Content.tsx b/src/app/(with-tracker)/(login)/Content.tsx index 8c63710..bad17fb 100644 --- a/src/app/(with-tracker)/(login)/Content.tsx +++ b/src/app/(with-tracker)/(login)/Content.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import Image from 'next/image'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; import { Input, Button } from '@/components'; import { LoginVo } from '@/types'; import { login, sampleLogin } from '@/apis'; @@ -14,7 +14,6 @@ const responsiveStyle = export const Content = () => { const { replace } = useRouter(); - const client = useQueryClient(); const { register, @@ -23,7 +22,6 @@ export const Content = () => { } = useForm({ mode: 'all' }); const onSuccess = () => { - client.clear(); trackUserEvent(MessageEnum.LOGIN); replace('/main?asc=false&sort='); }; diff --git a/src/components/auth-required/header/index.tsx b/src/components/auth-required/header/index.tsx index 6984f7b..530a488 100644 --- a/src/components/auth-required/header/index.tsx +++ b/src/components/auth-required/header/index.tsx @@ -9,6 +9,8 @@ import { NameType } from '@/components'; import { useResponsive } from '@/hooks'; import { logout, me } from '@/apis'; import { trackUserEvent, MessageEnum } from '@/utils/trackUtil'; +import { revalidate } from '@/utils/revalidateUtil'; + import { defaultStyle, Section, textStyle } from './Section'; const PARAMS = { @@ -37,13 +39,19 @@ export const Header = () => { const { mutate: out } = useMutation({ mutationFn: logout, - onMutate: () => router.replace('/'), - onSuccess: () => client.removeQueries(), + onSuccess: async () => { + await revalidate(); + client.clear(); + router.replace('/'); + }, }); const { data: profiles } = useQuery({ queryKey: [PATHS.ME], queryFn: me, + enabled: !!client.getQueryData([PATHS.ME]), + // 로그아웃 후 리렌더링되어 다시 fetch되는 경우 해결 + // 어차피 prefetch를 통해 데이터를 불러온 상태에서 렌더하기 때문에, 캐시 여부만 판단하면 됨 }); useEffect(() => { diff --git a/src/components/auth-required/main/Section/index.tsx b/src/components/auth-required/main/Section/index.tsx index 91ce6dc..bdb1c45 100644 --- a/src/components/auth-required/main/Section/index.tsx +++ b/src/components/auth-required/main/Section/index.tsx @@ -1,27 +1,22 @@ 'use client'; -import { useQueryClient } from '@tanstack/react-query'; import { useState } from 'react'; -import { UserNameNotFoundError } from '@/errors'; import { trackUserEvent, MessageEnum } from '@/utils/trackUtil'; import { parseNumber } from '@/utils/numberUtil'; import { COLORS, env, PATHS } from '@/constants'; import { PostType, UserDto } from '@/types'; import { Icon } from '@/components'; +import { getQueryClient } from '@/utils/queryUtil'; import { Graph } from './Graph'; export const Section = (p: PostType) => { const [open, setOpen] = useState(false); - const client = useQueryClient(); - const { username } = client.getQueryData([PATHS.ME]) as UserDto; - const URL = env.VELOG_URL; + const username = ( + getQueryClient().getQueryData([PATHS.ME]) as Partial + )?.username; - if (!username) { - throw new UserNameNotFoundError(); - } - - const url = `${URL}/@${username}/${p.slug}`; + const url = `${env.VELOG_URL}/@${username}/${p.slug}`; return (
diff --git a/src/utils/queryUtil.ts b/src/utils/queryUtil.ts index 9e40e0a..ad54707 100644 --- a/src/utils/queryUtil.ts +++ b/src/utils/queryUtil.ts @@ -3,7 +3,7 @@ import { toast } from 'react-toastify'; let localQueryClient: QueryClient | undefined; const STALE_TIME = 1000 * 60 * 3; -const GC_TIME = 1000; +const GC_TIME = 1000 * 60 * 20; const createQueryClient = () => new QueryClient({ diff --git a/src/utils/revalidateUtil.ts b/src/utils/revalidateUtil.ts new file mode 100644 index 0000000..375a030 --- /dev/null +++ b/src/utils/revalidateUtil.ts @@ -0,0 +1,9 @@ +'use server'; + +import { revalidatePath } from 'next/cache'; +import { redirect } from 'next/navigation'; + +export async function revalidate() { + revalidatePath('/', 'layout'); + redirect('/'); +}