Skip to content

Commit

Permalink
Fix : silent refresh interval
Browse files Browse the repository at this point in the history
  • Loading branch information
oikkoikk committed Oct 9, 2023
1 parent 8adfbb3 commit 43e69bd
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 67 deletions.
2 changes: 2 additions & 0 deletions src/api/ErrorMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const ErrorMessage = {
LOGIN: '로그인에 실패했어요',
PROFILE_UPDATE: '프로필을 업데이트하지 못했어요',
REFRESH: '세션 업데이트에 실패했어요',
UNAUTHORIZED: '로그인이 필요해요',
DASHBOARDS: '대시보드 정보를 불러오지 못했어요',
CLASSROOM: '강의실 정보를 불러오지 못했어요',
SEARCH: '검색 결과를 불러오지 못했어요',
Expand All @@ -21,5 +22,6 @@ export const ErrorMessage = {
} as const;

export const API_FETCH_ERROR = 'API_FETCH_ERROR'
export const SESSION_ERROR = 'SESSION_ERROR'

type ErrorMessage = (typeof ErrorMessage)[keyof typeof ErrorMessage];
23 changes: 7 additions & 16 deletions src/api/courses/courses.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import getQueryURL from '@/src/util/http/getQueryURL';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { QueryKeys } from '../queryKeys';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function enrollLectureInNewCourse(
params: EnrollLectureInNewCourseParams
Expand All @@ -17,9 +18,7 @@ export async function enrollLectureInNewCourse(
if (res.ok) {
return (await res.json()) as Promise<EnrollLectureResponse>;
} else {
return Promise.reject(
new Error(ErrorMessage.ENROLLMENT, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.ENROLLMENT);
}
});
}
Expand All @@ -38,9 +37,7 @@ export async function enrollLectureInExistingCourse(
if (res.ok) {
return (await res.json()) as Promise<EnrollLectureResponse>;
} else {
return Promise.reject(
new Error(ErrorMessage.ENROLLMENT, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.ENROLLMENT);
}
});
}
Expand All @@ -55,9 +52,7 @@ export async function fetchCourseDetail(course_id: number) {
if (res.ok) {
return (await res.json()) as Promise<CourseDetail>;
} else {
return Promise.reject(
new Error(ErrorMessage.DETAIL_COURSE, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.DETAIL_COURSE);
}
});
}
Expand All @@ -71,9 +66,7 @@ export async function fetchClassroom() {
if (res.ok) {
return (await res.json()) as Promise<ClassRoom>;
} else {
return Promise.reject(
new Error(ErrorMessage.CLASSROOM, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.CLASSROOM);
}
});
}
Expand All @@ -87,9 +80,7 @@ export async function deleteCourse(course_id: number) {
if (res.ok) {
return (await res.json()) as Promise<ClassRoom>;
} else {
return Promise.reject(
new Error(ErrorMessage.CLASSROOM, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.CLASSROOM);
}
});
}
7 changes: 3 additions & 4 deletions src/api/dashboards/dashboards.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function fetchDashboardInfo() {
const headers = await getAuthorizedHeaders();
Expand All @@ -11,9 +12,7 @@ export async function fetchDashboardInfo() {
if (res.ok) {
return (await res.json()) as Promise<DashboardInfo>;
} else {
return Promise.reject(
new Error(ErrorMessage.DASHBOARDS, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.DASHBOARDS);
}
});
}
23 changes: 7 additions & 16 deletions src/api/lectures/search.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import getQueryURL from '@/src/util/http/getQueryURL';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function fetchLecturesByKeyword(params: SearchLectureParams) {
const headers = await getAuthorizedHeaders();
Expand All @@ -12,9 +13,7 @@ export async function fetchLecturesByKeyword(params: SearchLectureParams) {
if (res.ok) {
return (await res.json()) as Promise<SearchResultsList>;
} else {
return Promise.reject(
new Error(ErrorMessage.SEARCH, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.SEARCH);
}
});
}
Expand All @@ -34,9 +33,7 @@ export async function fetchLectureDetail(
if (res.ok) {
return (await res.json()) as Promise<LectureDetail>;
} else {
return Promise.reject(
new Error(ErrorMessage.DETAIL, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.DETAIL);
}
});
}
Expand All @@ -56,9 +53,7 @@ export async function fetchLectureDetailIndex(
if (res.ok) {
return (await res.json()) as Promise<LectureIndexList>;
} else {
return Promise.reject(
new Error(ErrorMessage.DETAIL_INDEX, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.DETAIL_INDEX);
}
});
}
Expand All @@ -78,9 +73,7 @@ export async function fetchLectureDetailReview(
if (res.ok) {
return (await res.json()) as Promise<LectureReviewList>;
} else {
return Promise.reject(
new Error(ErrorMessage.DETAIL_REVIEW, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.DETAIL_REVIEW);
}
});
}
Expand All @@ -94,9 +87,7 @@ export async function fetchLectureRecommendations() {
if (res.ok) {
return (await res.json()) as Promise<LectureRecommendations>;
} else {
return Promise.reject(
new Error(ErrorMessage.RECOMMENDATIONS, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.RECOMMENDATIONS);
}
});
}
7 changes: 3 additions & 4 deletions src/api/lectures/time.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import getQueryURL from '@/src/util/http/getQueryURL';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function updateViewDuration(
params: CourseTakingParams,
Expand All @@ -25,9 +26,7 @@ export async function updateViewDuration(
if (res.ok) {
return (await res.json()) as Promise<CourseTakingInfo>;
} else {
return Promise.reject(
new Error(ErrorMessage.COURSE_TAKING, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.COURSE_TAKING);
}
});
}
15 changes: 5 additions & 10 deletions src/api/materials/materials.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';

export async function fetchCourseMaterials(course_video_id: number) {
Expand All @@ -11,9 +12,7 @@ export async function fetchCourseMaterials(course_video_id: number) {
if (res.ok) {
return (await res.json()) as Promise<CourseMaterials>;
} else {
return Promise.reject(
new Error(ErrorMessage.COURSE_MATERIALS, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.COURSE_MATERIALS);
}
});
}
Expand All @@ -32,9 +31,7 @@ export async function updateCourseLectureNotes(
if (res.ok) {
return (await res.json()) as Promise<Response>;
} else {
return Promise.reject(
new Error(ErrorMessage.LECTURENOTES, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.LECTURENOTES);
}
});
}
Expand All @@ -53,9 +50,7 @@ export async function updateCourseQuizGrade(
if (res.ok) {
return (await res.json()) as Promise<Response>;
} else {
return Promise.reject(
new Error(ErrorMessage.QUIZZES, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.QUIZZES);
}
});
}
9 changes: 3 additions & 6 deletions src/api/members/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import getHeaders from '@/src/util/http/getHeaders';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function fetchUserAuthWithCredential(
credential: GoogleLoginCredential
Expand Down Expand Up @@ -36,9 +37,7 @@ export async function fetchUserAuthWithRefreshToken(
if (res.ok) {
return (await res.json()) as Promise<LoginResponse>;
} else {
return Promise.reject(
new Error(ErrorMessage.REFRESH, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.REFRESH);
}
});
}
Expand All @@ -54,9 +53,7 @@ export async function updateUserProfile(name: string) {
if (res.ok) {
return (await res.json()) as Promise<ProfileUpdateResponse>;
} else {
return Promise.reject(
new Error(ErrorMessage.PROFILE_UPDATE, { cause: API_FETCH_ERROR })
);
fetchErrorHandling(res, ErrorMessage.PROFILE_UPDATE);
}
});
}
11 changes: 4 additions & 7 deletions src/api/reviews/reviews.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getAuthorizedHeaders } from '@/src/util/http/getAuthorizedHeaders';
import { Endpoints } from '../Endpoints';
import { API_FETCH_ERROR, ErrorMessage } from '../ErrorMessage';
import { ErrorMessage } from '../ErrorMessage';
import { fetchErrorHandling } from '@/src/util/http/fetchErrorHandling';

export async function fetchReviewListByCourse(courseId: number) {
const headers = await getAuthorizedHeaders();
Expand All @@ -11,9 +12,7 @@ export async function fetchReviewListByCourse(courseId: number) {
if (res.ok) {
return (await res.json()) as Promise<CourseReviewResponse>;
} else {
return Promise.reject(
new Error(ErrorMessage.REVIEW_LIST, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.REVIEW_LIST);
}
});
}
Expand All @@ -32,9 +31,7 @@ export async function updateLectureReview(
if (res.ok) {
return (await res.json()) as Promise<Response>;
} else {
return Promise.reject(
new Error(ErrorMessage.REVIEW_UPDATE, { cause: API_FETCH_ERROR })
);
return fetchErrorHandling(res, ErrorMessage.REVIEW_UPDATE);
}
});
}
1 change: 1 addition & 0 deletions src/components/gnb/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default function NavBar({ logo, profileDropdown }: Props) {
const { mutate } = useMutation(() => updateUserProfile(name), {
onSuccess: (data) => {
setIsEditMode(false);
if (!data) return;
setName(() => data.name);
}
});
Expand Down
1 change: 1 addition & 0 deletions src/constants/query/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ import { ONE_MINUTE_IN_MS } from "../time/time";

export const CACHE_TIME = ONE_MINUTE_IN_MS * 30;
export const STALE_TIME = ONE_MINUTE_IN_MS * 5;
export const UNAUTHORIZED = 401;
19 changes: 16 additions & 3 deletions src/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@ import { ErrorMessage } from '../api/ErrorMessage';
import { ONE_MINUTE_IN_MS } from '../constants/time/time';
import setErrorToast from '../util/toast/setErrorToast';

const refreshInterval = ONE_MINUTE_IN_MS * 29;

export default function useAuth() {
const router = useRouter();
const { data: session, status, update } = useSession();

const refreshToken = { refresh_token: session?.refresh_token ?? '' };

const calculateRefreshInterval = () => {
if (!session) return 0;

const NOW = Date.now();
const EXPIRES_AT = session.expires_at * 1000;

const REFRESH_INTERVAL = EXPIRES_AT - NOW - ONE_MINUTE_IN_MS;

if (REFRESH_INTERVAL <= 0) {
return 0;
}
return REFRESH_INTERVAL;
};

const silentRefresh = async () => {
const response = await fetchUserAuthWithRefreshToken(refreshToken).catch(
async () => {
Expand All @@ -27,7 +40,7 @@ export default function useAuth() {

useQuery([QueryKeys.REFRESH], silentRefresh, {
enabled: !!session,
refetchInterval: refreshInterval,
refetchInterval: calculateRefreshInterval,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchIntervalInBackground: true,
Expand Down
14 changes: 13 additions & 1 deletion src/providers/QueryProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ import { useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

export default function QueryProvider({ children }: React.PropsWithChildren) {
const [queryClient] = useState(() => new QueryClient({}));
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
retry: 2
},
mutations: {
retry: 2
}
}
})
);

return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
Expand Down
16 changes: 16 additions & 0 deletions src/util/http/fetchErrorHandling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {
API_FETCH_ERROR,
ErrorMessage,
SESSION_ERROR
} from '@/src/api/ErrorMessage';
import { UNAUTHORIZED } from '@/src/constants/query/query';

export function fetchErrorHandling(res: Response, errorMessage: string) {
if (res.status === UNAUTHORIZED) {
return Promise.reject(
new Error(ErrorMessage.UNAUTHORIZED, { cause: SESSION_ERROR })
);
} else {
return Promise.reject(new Error(errorMessage, { cause: API_FETCH_ERROR }));
}
}

0 comments on commit 43e69bd

Please sign in to comment.