Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] - 상수화 작업 진행 #188

Merged
merged 7 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions frontend/src/apis/ApiError.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios";

const HTTP_STATUS = {
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
} as const;
import { HTTP_STATUS_CODE_MAP } from "@constants/httpStatusCode";

class ApiError<T = unknown> extends Error implements AxiosError<T> {
config: InternalAxiosRequestConfig;
Expand All @@ -23,23 +17,23 @@ class ApiError<T = unknown> extends Error implements AxiosError<T> {
const errorStatus = error.response?.status || 0;
let name = "ApiError";

if (errorStatus === HTTP_STATUS.BAD_REQUEST) {
if (errorStatus === HTTP_STATUS_CODE_MAP.BAD_REQUEST) {
name = "ApiBadRequestError";
}

if (errorStatus === HTTP_STATUS.UNAUTHORIZED) {
if (errorStatus === HTTP_STATUS_CODE_MAP.UNAUTHORIZED) {
name = "ApiUnauthorizedError";
}

if (errorStatus === HTTP_STATUS.FORBIDDEN) {
if (errorStatus === HTTP_STATUS_CODE_MAP.FORBIDDEN) {
name = "ApiForbiddenError";
}

if (errorStatus === HTTP_STATUS.NOT_FOUND) {
if (errorStatus === HTTP_STATUS_CODE_MAP.NOT_FOUND) {
name = "ApiNotFoundError";
}

if (errorStatus === HTTP_STATUS.INTERNAL_SERVER_ERROR) {
if (errorStatus === HTTP_STATUS_CODE_MAP.INTERNAL_SERVER_ERROR) {
name = "ApiInternalServerError";
}

Expand Down
7 changes: 4 additions & 3 deletions frontend/src/apis/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import type { User } from "@type/domain/user";

import ApiError from "@apis/ApiError";

import { ROUTE_PATHS } from "@constants/route";
import { ROUTE_PATHS_MAP } from "@constants/route";
import { STORAGE_KEYS_MAP } from "@constants/storage";

export const checkAccessToken = (
config: InternalAxiosRequestConfig,
accessToken: string | null,
) => {
if (!accessToken) {
alert("로그인이 필요합니다.");
window.location.href = ROUTE_PATHS.login;
window.location.href = ROUTE_PATHS_MAP.login;
}

return config;
Expand All @@ -32,7 +33,7 @@ export const setAuthorizationHeader = (
};

export const handlePreviousRequest = (config: InternalAxiosRequestConfig) => {
const user: User | null = JSON.parse(localStorage.getItem("tourootUser") ?? "{}");
const user: User | null = JSON.parse(localStorage.getItem(STORAGE_KEYS_MAP.user) ?? "{}");
let newConfig = { ...config };

newConfig = checkAccessToken(config, user?.accessToken ?? null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom";
// import { UserContext } from "@contexts/UserProvider";
import Icon from "@components/common/Icon/Icon";

import { ROUTE_PATHS } from "@constants/route";
import { ROUTE_PATHS_MAP } from "@constants/route";

import { PRIMITIVE_COLORS } from "@styles/tokens";

Expand All @@ -26,7 +26,7 @@ const FloatingButton = () => {
// alert("여행기 작성 전 로그인을 먼저 해주세요!");
// return;
// }
navigate(ROUTE_PATHS.travelogueRegister);
navigate(ROUTE_PATHS_MAP.travelogueRegister);
};

const handleClickShareButton = () => {};
Expand Down
16 changes: 8 additions & 8 deletions frontend/src/components/common/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import IconButton from "@components/common/IconButton/IconButton";

import useUser from "@hooks/useUser";

import { ROUTE_PATHS } from "@constants/route";
import { ROUTE_PATHS_MAP } from "@constants/route";

import theme from "@styles/theme";
import { PRIMITIVE_COLORS } from "@styles/tokens";
Expand All @@ -21,21 +21,21 @@ const Header = () => {
const navigate = useNavigate();

const handleClickButton =
pathName === ROUTE_PATHS.root || pathName === ROUTE_PATHS.login
? () => navigate(ROUTE_PATHS.root)
: () => navigate(-1);
pathName === ROUTE_PATHS_MAP.root || pathName === ROUTE_PATHS_MAP.login
? () => navigate(ROUTE_PATHS_MAP.root)
: () => navigate(ROUTE_PATHS_MAP.back);

const { user } = useUser();

return (
<Drawer>
<S.HeaderLayout>
<IconButton
color={pathName === ROUTE_PATHS.root ? theme.colors.primary : PRIMITIVE_COLORS.black}
color={pathName === ROUTE_PATHS_MAP.root ? theme.colors.primary : PRIMITIVE_COLORS.black}
onClick={handleClickButton}
iconType={pathName === ROUTE_PATHS.root ? "korean-logo" : "back-icon"}
iconType={pathName === ROUTE_PATHS_MAP.root ? "korean-logo" : "back-icon"}
/>
{pathName === ROUTE_PATHS.login ? (
{pathName === ROUTE_PATHS_MAP.login ? (
<>
<S.HeaderTitle>로그인</S.HeaderTitle>
<S.HiddenDiv />
Expand Down Expand Up @@ -67,7 +67,7 @@ const Header = () => {
) : (
<S.MenuItem
onClick={() => {
navigate(ROUTE_PATHS.login);
navigate(ROUTE_PATHS_MAP.login);
}}
>
로그인
Expand Down
11 changes: 6 additions & 5 deletions frontend/src/components/pages/login/KakaoCallbackPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

import { client } from "@apis/client";

import { ROUTE_PATHS } from "@constants/route";
import { API_ENDPOINT_MAP } from "@constants/endpoint";
import { ROUTE_PATHS_MAP } from "@constants/route";

const KakaoCallbackPage = () => {
const navigate = useNavigate();
Expand All @@ -17,20 +18,20 @@

if (code) {
client
.post(`${ROUTE_PATHS.loginOauth}?code=${code}`)
.get(API_ENDPOINT_MAP.loginOauth(code))
.then((res) => {
saveUser(res.data);
navigate(ROUTE_PATHS.root);
navigate(ROUTE_PATHS_MAP.root);
})
.catch(() => {
alert("로그인에 실패하였습니다. 다시 시도해주세요!");
navigate(ROUTE_PATHS.login);
navigate(ROUTE_PATHS_MAP.login);
});
} else {
alert("로그인에 실패하였습니다. 다시 시도해주세요!");
navigate(ROUTE_PATHS.login);
navigate(ROUTE_PATHS_MAP.login);
}
}, [navigate]);

Check warning on line 34 in frontend/src/components/pages/login/KakaoCallbackPage.tsx

View workflow job for this annotation

GitHub Actions / frontend-ci

React Hook useEffect has a missing dependency: 'saveUser'. Either include it or remove the dependency array

return <div>로그인 처리 중...</div>;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AvatarCircle, FallbackImage } from "@components/common";

import useImageError from "@hooks/useImageError";

import { ROUTE_PATHS_MAP } from "@constants/route";

import { EmptyHeart } from "@assets/svg";

import * as S from "./TravelogueCard.styled";
Expand All @@ -21,7 +23,7 @@ const TravelogueCard = ({
const { imageError, handleImageError } = useImageError({ imageUrl: thumbnail });

const handleCardClick = () => {
navigate(`/travelogue/${id}`);
navigate(ROUTE_PATHS_MAP.travelogue(id));
};

const handleLikeClick = (e: React.MouseEvent) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import DateRangePicker from "@components/common/DateRangePicker/DateRangePicker"
import { useTravelDays } from "@hooks/pages/useTravelDays";
import useUser from "@hooks/useUser";

import { ROUTE_PATHS_MAP } from "@constants/route";

import * as S from "./TravelPlanRegisterPage.styled";

const MAX_TITLE_LENGTH = 20;
Expand Down Expand Up @@ -74,9 +76,9 @@ const TravelPlanRegisterPage = () => {
handleAddTravelPlan(
{ title, startDate: formattedStartDate, days: travelDays },
{
onSuccess: ({ data }) => {
onSuccess: ({ data: { id } }) => {
handleCloseBottomSheet();
navigate(`/travel-plans/${data.id}`);
navigate(ROUTE_PATHS_MAP.travelPlan(id));
},
},
);
Expand All @@ -90,7 +92,7 @@ const TravelPlanRegisterPage = () => {
useEffect(() => {
if (!user?.accessToken) {
alert("로그인이 필요합니다.");
navigate("/login");
navigate(ROUTE_PATHS_MAP.login);
}
}, [user?.accessToken, navigate]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import TravelogueMultiImageUpload from "@components/pages/travelogueRegister/Tra
import { useTravelDays } from "@hooks/pages/useTravelDays";
import useUser from "@hooks/useUser";

import { ROUTE_PATHS_MAP } from "@constants/route";

import * as S from "./TravelogueRegisterPage.styled";

const MAX_TITLE_LENGTH = 20;
Expand Down Expand Up @@ -77,9 +79,9 @@ const TravelogueRegisterPage = () => {
handleRegisterTravelogue(
{ title, thumbnail, days: travelDays },
{
onSuccess: ({ data }) => {
onSuccess: ({ data: { id } }) => {
handleCloseBottomSheet();
navigate(`/travelogue/${data.id}`);
navigate(ROUTE_PATHS_MAP.travelogue(id));
},
},
);
Expand All @@ -92,7 +94,7 @@ const TravelogueRegisterPage = () => {
useEffect(() => {
if (!user?.accessToken) {
alert("로그인이 필요합니다.");
navigate("/login");
navigate(ROUTE_PATHS_MAP.login);
}
}, [user?.accessToken, navigate]);

Expand Down
8 changes: 8 additions & 0 deletions frontend/src/constants/endpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const API_ENDPOINT_MAP = {
loginOauth: (code: string) => `/login/oauth/kakao?code=${code}`,
travelogue: (id: number) => `/travelogues/${id}`,
travelPlan: (id: number) => `travel-plans/${id}`,
travelogues: "/travelogues",
travelPlans: "/travel-plans",
image: "/image",
} as const;
7 changes: 7 additions & 0 deletions frontend/src/constants/httpStatusCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const HTTP_STATUS_CODE_MAP = {
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
} as const;
10 changes: 10 additions & 0 deletions frontend/src/constants/queryKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const QUERY_KEYS_MAP = {
travelogue: {
all: ["travelogues"],
detail: (id: string) => [...QUERY_KEYS_MAP.travelogue.all, id],
},
travelPlan: {
all: ["travel-plans"],
detail: (id: string) => [...QUERY_KEYS_MAP.travelPlan.all, id],
},
};
9 changes: 5 additions & 4 deletions frontend/src/constants/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export const ROUTE_PATHS = {
export const ROUTE_PATHS_MAP = {
back: -1,
root: "/",
travelogue: "/travelogue/:id",
travelogue: (id?: number) => (id ? `/travelogue/${id}` : "/travelogue/:id"),
travelPlan: (id?: number) => (id ? `/travel-plan/${id}` : "/travel-plan/:id"),
travelogueRegister: "/travelogue/register",
travelPlans: "/travel-plans/:id",
travelPlansRegister: "/travel-plans/register",
travelPlanRegister: "/travel-plan/register",
login: "/login",
loginCallback: "/oauth",
loginOauth: "/login/oauth/kakao",
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/constants/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const STORAGE_KEYS_MAP = {
user: "tourootUser",
} as const;
4 changes: 3 additions & 1 deletion frontend/src/contexts/TravelTransformDetailProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import useUser from "@hooks/useUser";

import { ROUTE_PATHS_MAP } from "@constants/route";

const TravelogueContext = createContext<TravelTransformDetail | null>(null);
const SaveTravelogueContext = createContext<(travelogue: TravelTransformDetail) => void>(() => {});

Expand All @@ -28,7 +30,7 @@
);
};

export const useTravelTransformDetailContext = () => {

Check warning on line 33 in frontend/src/contexts/TravelTransformDetailProvider.tsx

View workflow job for this annotation

GitHub Actions / frontend-ci

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components
const transformDetail = useContext(TravelogueContext);
const saveTransformDetail = useContext(SaveTravelogueContext);

Expand All @@ -41,7 +43,7 @@
) => {
if (isEmptyObject(user ?? {})) {
alert("로그인 후 이용이 가능합니다.");
navigate("/login");
navigate(ROUTE_PATHS_MAP.login);
} else if (travelTransformDetail) {
saveTransformDetail(travelTransformDetail);
navigate(redirectUrl);
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/contexts/UserProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { createContext, useState } from "react";

import type { User } from "@type/domain/user";

import { STORAGE_KEYS_MAP } from "@constants/storage";

export interface UserContextProps {
user: User | null;
}
Expand All @@ -15,11 +17,11 @@ export const SaveUserContext = createContext({} as SaveUserContextProps);

const UserProvider = ({ children }: React.PropsWithChildren) => {
const [user, setUser] = useState<User | null>(
() => JSON.parse(localStorage.getItem("tourootUser") ?? "{}") ?? null,
() => JSON.parse(localStorage.getItem(STORAGE_KEYS_MAP.user) ?? "{}") ?? null,
);

const saveUser = (user: User) => {
localStorage.setItem("tourootUser", JSON.stringify(user ?? {}));
localStorage.setItem(STORAGE_KEYS_MAP.user, JSON.stringify(user ?? {}));
setUser(user);
};
return (
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/queries/useGetTravelPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import { Travelogue } from "@type/domain/travelogue";

import { authClient } from "@apis/client";

import { API_ENDPOINT_MAP } from "@constants/endpoint";
import { QUERY_KEYS_MAP } from "@constants/queryKey";

export const useGetTravelPlan = (id: string) => {
return useQuery<AxiosResponse<Travelogue>>({
queryKey: [`travel-plans/${id}`],
queryFn: async () => authClient.get(`travel-plans/${id}`),
queryKey: QUERY_KEYS_MAP.travelPlan.detail(id),
queryFn: async () => authClient.get(API_ENDPOINT_MAP.travelPlan(Number(id))),
});
};
7 changes: 5 additions & 2 deletions frontend/src/queries/useGetTravelogue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import type { Travelogue } from "@type/domain/travelogue";

import { client } from "@apis/client";

import { API_ENDPOINT_MAP } from "@constants/endpoint";
import { QUERY_KEYS_MAP } from "@constants/queryKey";

export const useGetTravelogue = (id: string) => {
return useQuery<Travelogue>({
queryKey: [`travelogues/${id}`],
queryKey: QUERY_KEYS_MAP.travelogue.detail(id),
queryFn: async () => {
const { data } = await client.get(`/travelogues/${id}`);
const { data } = await client.get(API_ENDPOINT_MAP.travelogue(Number(id)));

return data;
},
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/queries/useInfiniteTravelogues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { useInfiniteQuery } from "@tanstack/react-query";

import { client } from "@apis/client";

import { API_ENDPOINT_MAP } from "@constants/endpoint";
import { QUERY_KEYS_MAP } from "@constants/queryKey";

export const getTravelogues = async ({ page, size }: { page: number; size: number }) => {
try {
const response = await client.get("/travelogues", {
const response = await client.get(API_ENDPOINT_MAP.travelogues, {
params: { page, size },
});
return response.data;
Expand All @@ -19,7 +22,7 @@ const useInfiniteTravelogues = () => {
const DATA_LOAD_COUNT = 5;

const { data, status, error, fetchNextPage, isFetchingNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ["travelogues"],
queryKey: QUERY_KEYS_MAP.travelogue.all,
queryFn: ({ pageParam = INITIAL_PAGE }) => {
const page = pageParam;
const size = DATA_LOAD_COUNT;
Expand Down
Loading
Loading