diff --git a/.gitignore b/.gitignore index 8239645e..a37a4cc9 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,6 @@ dist # TernJS port file .tern-port + +# storybook +storybook-static \ No newline at end of file diff --git a/backend/libs/consts/index.ts b/backend/libs/consts/index.ts index 7867a849..747e8618 100644 --- a/backend/libs/consts/index.ts +++ b/backend/libs/consts/index.ts @@ -1,5 +1,13 @@ const MINUTE = 60; -const HOUR = 60 * MINUTE; +export const HOUR = 60 * MINUTE; + +export const DAY = 24 * HOUR; + +export const WEEK = 7 * DAY; + +export const MONTH = 30 * DAY; + +export const YEAR = 365 * DAY; export const EXPIRATION = { ACCESS_TOKEN: 600, diff --git a/backend/src/user/utils/query.ts b/backend/src/user/utils/query.ts index 35213b15..c1f66a2a 100644 --- a/backend/src/user/utils/query.ts +++ b/backend/src/user/utils/query.ts @@ -1,3 +1,5 @@ +import { YEAR } from '@libs/consts'; + export const pinnedRepositoriesQuery = `query pinnedReposities($username: String!) { user(login: $username) { organizations(first:100) { @@ -110,7 +112,7 @@ export const forkRepositoryQuery = `query repositories($username: String!, $id: defaultBranchRef { target { ... on Commit { - history(author: {id: $id}, first: 100) { + history(author: {id: $id}, since: "${new Date(new Date().getTime() - 3 * YEAR * 1000).toISOString()}") { nodes { committedDate } diff --git a/frontend/src/components/Profile/ProfileRefreshButton/index.tsx b/frontend/src/components/Profile/ProfileRefreshButton/index.tsx index ed5228c9..86b2e36a 100644 --- a/frontend/src/components/Profile/ProfileRefreshButton/index.tsx +++ b/frontend/src/components/Profile/ProfileRefreshButton/index.tsx @@ -1,6 +1,6 @@ import { Trans } from 'next-i18next'; import Image from 'next/image'; -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import styled, { keyframes } from 'styled-components'; import { useInterval } from '@hooks/useInterval'; @@ -13,9 +13,9 @@ interface ProfileRefreshButtonProps { function ProfileRefreshButton({ updateDelayTime, updateData, isLoading, isMine }: ProfileRefreshButtonProps) { const [count, setCount] = useState(updateDelayTime); - useInterval(() => { - setCount(count - 1); - }, 1000); + const countDown = useCallback(() => setCount((prev) => prev - 1), []); + + useInterval(countDown, 1000, count > 0); useEffect(() => { setCount(updateDelayTime); diff --git a/frontend/src/hooks/useInterval.ts b/frontend/src/hooks/useInterval.ts index d1cfaa2f..c9ccd424 100644 --- a/frontend/src/hooks/useInterval.ts +++ b/frontend/src/hooks/useInterval.ts @@ -1,26 +1,17 @@ -import { useEffect, useRef } from 'react'; +import { useEffect } from 'react'; interface CallbackType { (): void; } -export function useInterval(callback: CallbackType, delay: number) { - const savedCallback = useRef(); - +export function useInterval(callback: CallbackType, delay: number, isActivate: boolean) { useEffect(() => { - if (callback) { - savedCallback.current = callback; - } - }, [callback]); + if (!isActivate) return; - useEffect(() => { - function tick() { - if (savedCallback.current) { - savedCallback.current(); - } - } + const id = setInterval(callback, delay); - const id = setInterval(tick, delay); - return () => clearInterval(id); - }, [delay]); + return () => { + clearInterval(id); + }; + }, [callback, delay, isActivate]); } diff --git a/frontend/src/pages/profile/[username].tsx b/frontend/src/pages/profile/[username].tsx index 276994b4..dea766e8 100644 --- a/frontend/src/pages/profile/[username].tsx +++ b/frontend/src/pages/profile/[username].tsx @@ -1,6 +1,7 @@ import { GetServerSideProps } from 'next'; import { useTranslation } from 'next-i18next'; import Image from 'next/image'; +import { AxiosError } from 'axios'; import { useEffect } from 'react'; import styled from 'styled-components'; import { useQueryData } from '@hooks'; @@ -29,10 +30,20 @@ function Profile({ username }: ProfileProps) { const { mutate, isLoading } = useMutation({ mutationFn: () => requestUserInfoByUsername({ username, method: 'PATCH' }), - onError: () => alert('최근에 업데이트 했습니다.'), + onError: (err) => updateErrorHandler(err), onSettled: () => refetch(), }); + const { t } = useTranslation(['profile', 'meta']); + const updateErrorHandler = (err: unknown) => { + if (err instanceof AxiosError && err.response) { + if (err.response.status >= 500) { + alert('정보를 불러올 수 없는 유저입니다.'); + } else if (err.response.status >= 400) { + alert('최근에 업데이트 했습니다. 잠시 후 다시 시도해주세요.'); + } + } + }; useEffect(() => { requestTokenRefresh(); diff --git a/frontend/src/utils/axiosInstance.ts b/frontend/src/utils/axiosInstance.ts index aeb692bd..de6ea664 100644 --- a/frontend/src/utils/axiosInstance.ts +++ b/frontend/src/utils/axiosInstance.ts @@ -34,6 +34,10 @@ instance.interceptors.response.use( } } } + + if (originConfig.url.startsWith('/users/') && originConfig.method === 'patch') { + return Promise.reject(err); + } }, );