Skip to content

Commit ed7c8ae

Browse files
committed
feat: 프로필 페이지, 공고 상세 페이지 (사장님, 알바생) ProtectedRoute 적용
1 parent bafd93b commit ed7c8ae

File tree

5 files changed

+99
-41
lines changed

5 files changed

+99
-41
lines changed

src/Router.tsx

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import profileLoader from "./pages/ProfilePage/loader/profileLoader";
88

99
import NoticeDetailSkeleton from "./components/NoticeDetailSkeleton";
1010
import PageErrorElement from "./components/PageErrorElement";
11+
import ProtectedRoute from "./components/ProtectedRoute";
12+
import { loginProtectCondition } from "./constants/router";
1113
import { ROUTES } from "./constants/router";
1214
import AuthLayout from "./layouts/AuthLayout";
1315
import MainLayout from "./layouts/MainLayout";
@@ -45,77 +47,116 @@ const NotFoundPage = lazy(() => import("@/pages/NotFoundPage"));
4547
const authRoutes: RouteObject[] = [
4648
{
4749
path: ROUTES.AUTH.SIGNUP,
48-
Component: SignupPage,
50+
element: <SignupPage />,
4951
},
5052
{
5153
path: ROUTES.AUTH.SIGNIN,
52-
Component: SigninPage,
54+
element: <SigninPage />,
5355
},
5456
];
5557

5658
const shopRoutes: RouteObject[] = [
5759
{
5860
path: ROUTES.SHOP.ROOT,
59-
Component: ShopPage,
61+
element: <ShopPage />,
6062
},
6163
{
6264
path: ROUTES.SHOP.REGISTER,
63-
Component: ShopRegisterPage,
65+
element: <ShopRegisterPage />,
6466
handle: { hideFooter: true },
6567
},
6668
{
6769
path: ROUTES.SHOP.EDIT,
68-
Component: ShopEditPage,
70+
element: <ShopEditPage />,
6971
handle: { hideFooter: true },
7072
},
7173
];
7274

7375
const profileRoutes: RouteObject[] = [
7476
{
7577
path: ROUTES.PROFILE.ROOT,
76-
Component: ProfilePage,
78+
element: (
79+
<ProtectedRoute
80+
conditions={({ isLoggedIn, user }) => [
81+
loginProtectCondition(isLoggedIn),
82+
{
83+
isPass: user?.type === "employee",
84+
redirectPath: ROUTES.SHOP.ROOT,
85+
message: "알바생 계정으로만 이용 가능한 기능입니다.",
86+
},
87+
]}
88+
>
89+
<ProfilePage />
90+
</ProtectedRoute>
91+
),
7792
loader: profileLoader,
7893
},
7994
{
8095
path: ROUTES.PROFILE.REGISTER,
81-
Component: ProfileRegisterPage,
96+
element: <ProfileRegisterPage />,
8297
handle: { hideFooter: true },
8398
},
8499
{
85100
path: ROUTES.PROFILE.EDIT,
86-
Component: ProfileEditPage,
101+
element: <ProfileEditPage />,
87102
handle: { hideFooter: true },
88103
},
89104
];
90105

91106
const noticeRoutes: RouteObject[] = [
92107
{
93108
path: ROUTES.NOTICE.ROOT,
94-
Component: NoticeListPage,
109+
element: <NoticeListPage />,
95110
},
96111
{
97112
path: ROUTES.NOTICE.SEARCH,
98-
Component: NoticeSearchPage,
113+
element: <NoticeSearchPage />,
99114
},
100115
{
101116
path: ROUTES.NOTICE.REGISTER,
102-
Component: NoticeRegisterPage,
117+
element: <NoticeRegisterPage />,
103118
handle: { hideFooter: true },
104119
},
105120
{
106121
path: ROUTES.NOTICE.EDIT,
107-
Component: NoticeEditPage,
122+
element: <NoticeEditPage />,
108123
handle: { hideFooter: true },
109124
},
110125
{
111126
path: ROUTES.NOTICE.NOTICE_ID.EMPLOYER,
112-
Component: NoticeEmployerPage,
127+
element: (
128+
<ProtectedRoute
129+
conditions={({ isLoggedIn, user }) => [
130+
loginProtectCondition(isLoggedIn),
131+
{
132+
isPass: user?.type === "employer",
133+
redirectPath: ROUTES.PROFILE.ROOT,
134+
message: "사장님 계정으로만 이용 가능한 기능입니다.",
135+
},
136+
]}
137+
>
138+
<NoticeEmployerPage />
139+
</ProtectedRoute>
140+
),
113141
loader: noticeEmployerLoader,
114142
hydrateFallbackElement: <NoticeDetailSkeleton />,
115143
},
116144
{
117145
path: ROUTES.NOTICE.NOTICE_ID.EMPLOYEE,
118-
Component: NoticeEmployeePage,
146+
element: (
147+
<ProtectedRoute
148+
conditions={({ isLoggedIn, user }) => [
149+
loginProtectCondition(isLoggedIn),
150+
{
151+
isPass: user?.type === "employee",
152+
redirectPath: ROUTES.SHOP.ROOT,
153+
message: "알바생 계정으로만 이용 가능한 기능입니다.",
154+
},
155+
]}
156+
>
157+
<NoticeEmployeePage />
158+
</ProtectedRoute>
159+
),
119160
loader: noticeEmployeeLoader,
120161
hydrateFallbackElement: <NoticeDetailSkeleton />,
121162
},
@@ -125,12 +166,12 @@ const appRoutes: RouteObject[] = [
125166
...shopRoutes,
126167
...profileRoutes,
127168
...noticeRoutes,
128-
{ path: "*", Component: NotFoundPage },
169+
{ path: "*", element: <NotFoundPage /> },
129170
];
130171

131172
export const router = createBrowserRouter([
132173
{
133-
Component: AuthLayout,
174+
element: <AuthLayout />,
134175
children: [
135176
{
136177
children: authRoutes,
@@ -139,7 +180,7 @@ export const router = createBrowserRouter([
139180
],
140181
},
141182
{
142-
Component: MainLayout,
183+
element: <MainLayout />,
143184
children: [
144185
{
145186
children: appRoutes,

src/constants/router.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const ROUTES = {
1+
export const ROUTES = {
22
AUTH: {
33
SIGNUP: "/signup",
44
SIGNIN: "/signin",
@@ -26,4 +26,9 @@ const ROUTES = {
2626
notFound: "*",
2727
} as const;
2828

29-
export { ROUTES };
29+
export const loginProtectCondition = (isLoggedIn: boolean) =>
30+
({
31+
isPass: isLoggedIn,
32+
redirectPath: ROUTES.AUTH.SIGNIN,
33+
message: "로그인 후에 이용 가능한 기능입니다.",
34+
}) as const;

src/pages/ProfilePage/ProfilePage.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import useUserApplications from "./hooks/useUserApplications";
77

88
import EmptyStateCard from "@/components/EmptyStateCard";
99
import { ROUTES } from "@/constants/router";
10-
import { UserApplicationList } from "@/types/application";
1110
import { UserItem } from "@/types/user";
1211

1312
const LIMIT = 5;
@@ -16,14 +15,17 @@ const PAGE_LIMIT = 7;
1615
export default function ProfilePage() {
1716
const { userInfo } = useLoaderData<{
1817
userInfo: UserItem;
19-
count: number;
20-
userApplications: UserApplicationList[];
2118
}>();
19+
2220
const navigate = useNavigate();
2321
const { isLoading, totalCount, userApplications } = useUserApplications({
24-
userId: userInfo.id,
22+
userId: userInfo?.id,
2523
});
2624

25+
if (!userInfo) {
26+
return null;
27+
}
28+
2729
return (
2830
<>
2931
<section>

src/pages/ProfilePage/hooks/useUserApplications.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,31 @@ const useUserApplications = ({
2424
>([]);
2525
const page = Number(searchParams.get("page")) || 1;
2626

27-
const fetchUserApplication = async () => {
28-
setIsLoading(true);
29-
const userApplications = await getUserApplications(
30-
userId,
31-
(page - 1) * offset,
32-
limit,
33-
);
34-
35-
const nextUserApplications = userApplications.data.items.map(
36-
({ item }) => item,
37-
);
38-
39-
setTotalCount(userApplications.data.count);
40-
setUserApplications(nextUserApplications);
41-
setIsLoading(false);
42-
};
43-
4427
useEffect(() => {
28+
if (!userId) return;
29+
30+
const fetchUserApplication = async () => {
31+
try {
32+
setIsLoading(true);
33+
const userApplications = await getUserApplications(
34+
userId,
35+
(page - 1) * offset,
36+
limit,
37+
);
38+
39+
const nextUserApplications = userApplications.data.items.map(
40+
({ item }) => item,
41+
);
42+
43+
setTotalCount(userApplications.data.count);
44+
setUserApplications(nextUserApplications);
45+
} finally {
46+
setIsLoading(false);
47+
}
48+
};
49+
4550
fetchUserApplication();
46-
}, [page]);
51+
}, [userId, page, offset, limit]); // 의존성 보완
4752

4853
return { userApplications, isLoading, totalCount };
4954
};

src/pages/ProfilePage/loader/profileLoader.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { useUserStore } from "@/hooks/useUserStore";
33

44
const profileLoader = async () => {
55
const userId = useUserStore.getState().user?.id;
6+
7+
if (!userId) {
8+
return {};
9+
}
10+
611
const userInfo = await getUser(userId ?? "");
712

813
if (userInfo.status === 200) {

0 commit comments

Comments
 (0)