Skip to content

Commit 15fcce5

Browse files
committed
refactor: 리팩토링
- sonarcloud issue 반영
1 parent ed93a52 commit 15fcce5

9 files changed

Lines changed: 101 additions & 103 deletions

File tree

src/components/Callvan/components/AddPostForm/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ export default function AddPostForm() {
9191
if (!form.departureType || !form.arrivalType || isPending) return;
9292

9393
const selectedDateTime = new Date(form.departureDate);
94-
const hour24 = form.isPM ? (form.departureHour === 12 ? 12 : form.departureHour + 12) : form.departureHour === 12 ? 0 : form.departureHour;
94+
let hour24: number;
95+
if (form.isPM) {
96+
hour24 = form.departureHour === 12 ? 12 : form.departureHour + 12;
97+
} else {
98+
hour24 = form.departureHour === 12 ? 0 : form.departureHour;
99+
}
95100
selectedDateTime.setHours(hour24, form.departureMinute, 0, 0);
96101

97102
if (selectedDateTime < new Date()) {

src/components/Callvan/components/CallvanPageLayout/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default function CallvanPageLayout({
8484
departures: filter.departures.length > 0 ? filter.departures.join(',') : undefined,
8585
arrivals: filter.arrivals.length > 0 ? filter.arrivals.join(',') : undefined,
8686
sort: filter.sort !== 'LATEST_DESC' ? filter.sort : undefined,
87-
author: filter.author !== 'ALL' ? filter.author : undefined,
87+
author: filter.author === 'ALL' ? undefined : filter.author,
8888
joined: filter.joined ? 'true' : undefined,
8989
page: undefined,
9090
},

src/components/Callvan/components/CallvanRestrictionModal/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { useBodyScrollLock } from 'utils/hooks/ui/useBodyScrollLock';
55
import styles from './CallvanRestrictionModal.module.scss';
66

77
interface CallvanRestrictionModalProps {
8-
restriction: RestrictedCallvanResponse | null;
9-
onClose: () => void;
8+
readonly restriction: RestrictedCallvanResponse | null;
9+
readonly onClose: () => void;
1010
}
1111

1212
export default function CallvanRestrictionModal({ restriction, onClose }: CallvanRestrictionModalProps) {
@@ -29,7 +29,7 @@ export default function CallvanRestrictionModal({ restriction, onClose }: Callva
2929
}, [onClose]);
3030

3131
return (
32-
<div className={styles.modal__overlay} role="dialog" aria-modal="true" aria-labelledby="callvan-restriction-title">
32+
<dialog className={styles.modal__overlay} aria-modal="true" aria-labelledby="callvan-restriction-title" open>
3333
<button type="button" className={styles.modal__dim} onClick={onClose} aria-label="닫기" />
3434
<div className={styles.modal__sheet}>
3535
<div className={styles.modal__content}>
@@ -49,6 +49,6 @@ export default function CallvanRestrictionModal({ restriction, onClose }: Callva
4949
</button>
5050
</div>
5151
</div>
52-
</div>
52+
</dialog>
5353
);
5454
}

src/components/CampusInfo/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const formatDateRange = (fromDate: string, toDate: string) => {
3434
};
3535

3636
type ShopIconProps = {
37-
iconUrl: string | null | undefined;
38-
name: string;
37+
readonly iconUrl: string | null | undefined;
38+
readonly name: string;
3939
};
4040

4141
function ShopIcon({ iconUrl, name }: ShopIconProps) {

src/components/TimetablePage/components/MainTimetable/index.tsx

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { useRouter } from 'next/router';
33
import { useSuspenseQuery } from '@tanstack/react-query';
44
import { deptQueries } from 'api/dept/queries';
5-
import { Lecture, MyLectureInfo } from 'api/timetable/entity';
5+
import { Lecture, MyLectureInfo, SemesterCheckResponse, TimetableFrameListResponse } from 'api/timetable/entity';
66
import { isValidTimetableFrameId } from 'api/timetable/queries';
77
import DownloadIcon from 'assets/svg/download-icon.svg';
88
import GraduationIcon from 'assets/svg/graduation-icon.svg';
@@ -24,13 +24,30 @@ import DownloadTimetableModal from './DownloadTimetableModal';
2424
import styles from './MyLectureTimetable.module.scss';
2525

2626
interface MainTimetableLayoutProps {
27-
curriculum: React.ReactNode;
28-
myLectures: Lecture[] | MyLectureInfo[] | undefined;
29-
onClickDownloadImage: (e: React.MouseEvent<HTMLButtonElement>) => void;
30-
onClickEdit: () => void;
31-
onClickGraduation: () => void;
32-
timetableContent: React.ReactNode;
33-
footer?: React.ReactNode;
27+
readonly curriculum: React.ReactNode;
28+
readonly myLectures: Lecture[] | MyLectureInfo[] | undefined;
29+
readonly onClickDownloadImage: (e: React.MouseEvent<HTMLButtonElement>) => void;
30+
readonly onClickEdit: () => void;
31+
readonly onClickGraduation: () => void;
32+
readonly timetableContent: React.ReactNode;
33+
readonly footer?: React.ReactNode;
34+
}
35+
36+
function checkSemesterAndTimetable(
37+
mySemester: SemesterCheckResponse | null | undefined,
38+
frameList: TimetableFrameListResponse,
39+
): boolean {
40+
if (mySemester?.semesters.length === 0) {
41+
toast.error('학기가 존재하지 않습니다. 학기를 추가해주세요.');
42+
return false;
43+
}
44+
45+
if (!frameList.some((frame) => isValidTimetableFrameId(frame.id))) {
46+
toast.error('시간표가 존재하지 않습니다. 시간표를 추가해주세요.');
47+
return false;
48+
}
49+
50+
return true;
3451
}
3552

3653
function MainTimetableLayout({
@@ -79,27 +96,13 @@ function InvalidMainTimetable() {
7996
const { data: deptList } = useSuspenseQuery(deptQueries.list());
8097
const { data: mySemester } = useSemesterCheck(token);
8198

82-
const isSemesterAndTimetableExist = () => {
83-
if (mySemester?.semesters.length === 0) {
84-
toast.error('학기가 존재하지 않습니다. 학기를 추가해주세요.');
85-
return false;
86-
}
87-
88-
if (!timeTableFrameList.some((frame) => isValidTimetableFrameId(frame.id))) {
89-
toast.error('시간표가 존재하지 않습니다. 시간표를 추가해주세요.');
90-
return false;
91-
}
92-
93-
return true;
94-
};
95-
9699
const onClickDownloadImage = (e: React.MouseEvent<HTMLButtonElement>) => {
97100
e.stopPropagation();
98-
isSemesterAndTimetableExist();
101+
checkSemesterAndTimetable(mySemester, timeTableFrameList);
99102
};
100103

101104
const onClickEdit = () => {
102-
isSemesterAndTimetableExist();
105+
checkSemesterAndTimetable(mySemester, timeTableFrameList);
103106
};
104107

105108
return (
@@ -121,7 +124,7 @@ function InvalidMainTimetable() {
121124
);
122125
}
123126

124-
function ValidMainTimetable({ timetableFrameId }: { timetableFrameId: number }) {
127+
function ValidMainTimetable({ timetableFrameId }: { readonly timetableFrameId: number }) {
125128
const [isModalOpen, openModal, closeModal] = useBooleanState(false);
126129
const token = useTokenState();
127130
const semester = useSemester();
@@ -132,24 +135,10 @@ function ValidMainTimetable({ timetableFrameId }: { timetableFrameId: number })
132135
const { data: deptList } = useSuspenseQuery(deptQueries.list());
133136
const { data: mySemester } = useSemesterCheck(token);
134137

135-
const isSemesterAndTimetableExist = () => {
136-
if (mySemester?.semesters.length === 0) {
137-
toast.error('학기가 존재하지 않습니다. 학기를 추가해주세요.');
138-
return false;
139-
}
140-
141-
if (!timeTableFrameList.some((frame) => isValidTimetableFrameId(frame.id))) {
142-
toast.error('시간표가 존재하지 않습니다. 시간표를 추가해주세요.');
143-
return false;
144-
}
145-
146-
return true;
147-
};
148-
149138
const onClickDownloadImage = (e: React.MouseEvent<HTMLButtonElement>) => {
150139
e.stopPropagation();
151140

152-
if (isSemesterAndTimetableExist()) {
141+
if (checkSemesterAndTimetable(mySemester, timeTableFrameList)) {
153142
logger.actionEventClick({
154143
team: 'USER',
155144
event_label: 'timetable',
@@ -161,7 +150,7 @@ function ValidMainTimetable({ timetableFrameId }: { timetableFrameId: number })
161150
};
162151

163152
const onClickEdit = () => {
164-
if (isSemesterAndTimetableExist()) {
153+
if (checkSemesterAndTimetable(mySemester, timeTableFrameList)) {
165154
router.push(
166155
`/${ROUTES.TimetableModify({ id: String(timetableFrameId), type: 'regular' })}&year=${semester?.year}&term=${semester?.term}`,
167156
);
@@ -190,7 +179,7 @@ function ValidMainTimetable({ timetableFrameId }: { timetableFrameId: number })
190179
);
191180
}
192181

193-
function MainTimetable({ timetableFrameId }: { timetableFrameId: number }) {
182+
function MainTimetable({ timetableFrameId }: { readonly timetableFrameId: number }) {
194183
if (!isValidTimetableFrameId(timetableFrameId)) {
195184
return <InvalidMainTimetable />;
196185
}

src/components/TimetablePage/components/TimetableGridPlaceholder/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ const DEFAULT_TIME_STRING = ['9', '10', '11', '12', '13', '14', '15', '16', '17'
88
]);
99

1010
interface TimetableGridPlaceholderProps {
11-
firstColumnWidth: number;
12-
columnWidth: number;
13-
rowHeight: number;
14-
totalHeight: number;
11+
readonly firstColumnWidth: number;
12+
readonly columnWidth: number;
13+
readonly rowHeight: number;
14+
readonly totalHeight: number;
1515
}
1616

1717
export default function TimetableGridPlaceholder({

src/pages/room/[id]/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
import styles from './RoomDetailPage.module.scss';
2121

2222
interface RoomDetailPageProps {
23-
id: string;
23+
readonly id: string;
2424
}
2525

2626
export const getStaticPaths: GetStaticPaths = async () => {

src/pages/timetable/index.tsx

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,43 @@ const MobilePage = dynamic(
3030
{ ssr: true },
3131
);
3232

33+
async function prefetchTimetableData(
34+
queryClient: QueryClient,
35+
context: GetServerSidePropsContext,
36+
token: string,
37+
year: number,
38+
term: Term,
39+
validatedFrameId: number | null,
40+
): Promise<void> {
41+
try {
42+
const mySemesterData = await queryClient.fetchQuery(timetableQueries.mySemester(token));
43+
const userSemester = mySemesterData?.semesters?.[0];
44+
const semester = year && term ? { year, term } : userSemester || getRecentSemester();
45+
46+
const timetableFrameList = await queryClient.fetchQuery(timetableQueries.frameList(token, semester));
47+
48+
const mainFrame = timetableFrameList.find((frame) => frame.is_main);
49+
const currentFrameId = validatedFrameId ?? mainFrame?.id ?? null;
50+
51+
const prefetchPromises = [
52+
queryClient.prefetchQuery(timetableQueries.semesterInfo()),
53+
queryClient.prefetchQuery(deptQueries.list()),
54+
];
55+
56+
if (currentFrameId !== null) {
57+
prefetchPromises.push(queryClient.prefetchQuery(timetableQueries.lectureInfo(token, currentFrameId)));
58+
}
59+
60+
await Promise.all(prefetchPromises);
61+
} catch (error) {
62+
const isAuthError = isServerAuthError(error);
63+
const isForbiddenError = isKoinError(error) && error.status === 403;
64+
if (!isAuthError && !isForbiddenError) throw error;
65+
if (isAuthError) clearServerAuthCookies(context);
66+
queryClient.setQueryData(timetableQueryKeys.frameList(getRecentSemester()), createDefaultTimetableFrameList());
67+
}
68+
}
69+
3370
export const getServerSideProps = withCacheControl(async (context: GetServerSidePropsContext, cacheControl) => {
3471
const queryClient = new QueryClient();
3572
const { token, query } = parseServerSideParams(context);
@@ -39,38 +76,9 @@ export const getServerSideProps = withCacheControl(async (context: GetServerSide
3976
const validatedFrameId = isValidTimetableFrameId(frameId) ? frameId : null;
4077

4178
if (token) {
42-
try {
43-
const mySemesterData = await queryClient.fetchQuery(timetableQueries.mySemester(token));
44-
const userSemester = mySemesterData?.semesters?.[0];
45-
const semester = year && term ? { year, term } : userSemester || getRecentSemester();
46-
47-
const timetableFrameList = await queryClient.fetchQuery(timetableQueries.frameList(token, semester));
48-
49-
const mainFrame = timetableFrameList.find((frame) => frame.is_main);
50-
const currentFrameId = validatedFrameId ?? mainFrame?.id ?? null;
51-
52-
const prefetchPromises = [
53-
queryClient.prefetchQuery(timetableQueries.semesterInfo()),
54-
queryClient.prefetchQuery(deptQueries.list()),
55-
];
56-
57-
if (currentFrameId !== null) {
58-
prefetchPromises.push(queryClient.prefetchQuery(timetableQueries.lectureInfo(token, currentFrameId)));
59-
}
60-
61-
await Promise.all(prefetchPromises);
62-
} catch (error) {
63-
if (!isServerAuthError(error) && !(isKoinError(error) && error.status === 403)) throw error;
64-
if (isServerAuthError(error)) clearServerAuthCookies(context);
65-
const semester = getRecentSemester();
66-
queryClient.setQueryData(timetableQueryKeys.frameList(semester), createDefaultTimetableFrameList());
67-
}
79+
await prefetchTimetableData(queryClient, context, token, year, term, validatedFrameId);
6880
} else {
69-
const semester = getRecentSemester();
70-
queryClient.setQueryData(timetableQueryKeys.frameList(semester), createDefaultTimetableFrameList());
71-
}
72-
73-
if (!token) {
81+
queryClient.setQueryData(timetableQueryKeys.frameList(getRecentSemester()), createDefaultTimetableFrameList());
7482
cacheControl.enablePublicCache();
7583
}
7684

src/utils/ts/withCacheControl.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {
44
GetServerSidePropsResult,
55
PreviewData,
66
} from 'next';
7-
import type { ParsedUrlQuery } from 'querystring';
7+
import type { ParsedUrlQuery } from 'node:querystring';
88

99
export const PUBLIC_SSR_CACHE_CONTROL = 'public, s-maxage=60, stale-while-revalidate=300';
1010
export const STORE_PUBLIC_SSR_CACHE_CONTROL = 'public, s-maxage=300, stale-while-revalidate=1800';
@@ -16,26 +16,22 @@ export interface SSRCacheControl {
1616
enablePublicCache: (cacheControl?: string) => void;
1717
}
1818

19-
export interface GetServerSidePropsWithCacheControl<
19+
export type GetServerSidePropsWithCacheControl<
2020
Props extends SSRPageProps = SSRPageProps,
2121
Params extends ParsedUrlQuery = ParsedUrlQuery,
2222
Preview extends PreviewData = PreviewData,
23-
> {
24-
(
25-
context: GetServerSidePropsContext<Params, Preview>,
26-
cacheControl: SSRCacheControl,
27-
): Promise<GetServerSidePropsResult<Props>>;
28-
}
23+
> = (
24+
context: GetServerSidePropsContext<Params, Preview>,
25+
cacheControl: SSRCacheControl,
26+
) => Promise<GetServerSidePropsResult<Props>>;
2927

30-
export interface WithCacheControl {
31-
<
32-
Props extends SSRPageProps = SSRPageProps,
33-
Params extends ParsedUrlQuery = ParsedUrlQuery,
34-
Preview extends PreviewData = PreviewData,
35-
>(
36-
getServerSideProps: GetServerSidePropsWithCacheControl<Props, Params, Preview>,
37-
): GetServerSideProps<Props, Params, Preview>;
38-
}
28+
export type WithCacheControl = <
29+
Props extends SSRPageProps = SSRPageProps,
30+
Params extends ParsedUrlQuery = ParsedUrlQuery,
31+
Preview extends PreviewData = PreviewData,
32+
>(
33+
getServerSideProps: GetServerSidePropsWithCacheControl<Props, Params, Preview>,
34+
) => GetServerSideProps<Props, Params, Preview>;
3935

4036
export const withCacheControl: WithCacheControl = (getServerSideProps) => async (context) => {
4137
let shouldCachePublicResponse = false;

0 commit comments

Comments
 (0)