Skip to content

Commit 360dd25

Browse files
authored
Merge pull request #109 from part3-4team-Taskify/feature/Gnb
[Feat, Style, Refactor] 비로그인 상태에서 페이지 접근 시 화면 깜빡임 현상 수정, 로딩 스피너 추가
2 parents 0c118e7 + dd4e94c commit 360dd25

File tree

7 files changed

+64
-43
lines changed

7 files changed

+64
-43
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react";
2+
3+
const LoadingSpinner = () => {
4+
return (
5+
<div className="flex justify-center items-center w-full h-screen bg-white">
6+
<div className="w-12 h-12 border-6 border-[var(--primary)] border-solid rounded-full animate-spin border-t-transparent" />
7+
</div>
8+
);
9+
};
10+
11+
export default LoadingSpinner;

src/components/gnb/HeaderDashboard.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
145145
</div>
146146

147147
<div className="flex items-center">
148-
{/*관리 버튼*/}
149148
<div
150149
className={`flex gap-[6px] md:gap-[16px] ${variant === "mydashboard" ? "pr-[22px] md:pr-[32px]" : ""}`}
151150
>
@@ -172,20 +171,25 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
172171
/>
173172
<span className="text-sm md:text-base text-gray1">관리</span>
174173
</button>
174+
175175
{/*초대하기 버튼*/}
176-
<button
177-
onClick={openInviteModal}
178-
className="flex items-center justify-center w-[73px] h-[30px] md:w-[109px] md:h-[36px] lg:w-[116px] lg:h-[40px] rounded-[8px] border border-[#D9D9D9] gap-[10px] cursor-pointer"
179-
>
180-
<Image
181-
src="/svgs/add-box.svg"
182-
alt="초대하기 아이콘"
183-
width={20}
184-
height={20}
185-
className="hidden md:block"
186-
/>
187-
<span className="text-sm md:text-base text-gray1">초대하기</span>
188-
</button>
176+
{variant !== "mydashboard" && (
177+
<button
178+
onClick={openInviteModal}
179+
className="flex items-center justify-center w-[73px] h-[30px] md:w-[109px] md:h-[36px] lg:w-[116px] lg:h-[40px] rounded-[8px] border border-[#D9D9D9] gap-[10px] cursor-pointer"
180+
>
181+
<Image
182+
src="/svgs/add-box.svg"
183+
alt="초대하기 아이콘"
184+
width={20}
185+
height={20}
186+
className="hidden md:block"
187+
/>
188+
<span className="text-sm md:text-base text-gray1">
189+
초대하기
190+
</span>
191+
</button>
192+
)}
189193
{isModalOpen && <InviteDashboard onClose={closeInviteModal} />}
190194
</div>
191195

src/components/gnb/MemberListMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const MemberListMenu: React.FC<MemberListMenuProps> = ({
3030
{members.map((member) => (
3131
<li
3232
key={member.id}
33-
className="px-4 py-2 flex items-center gap-2 hover:bg-gray-100"
33+
className="px-4 py-2 flex items-center gap-2 hover:bg-[#f9f9f9]"
3434
>
3535
<UserAvatars user={member} />
3636
<span className="text-black3 text-sm md:text-base">

src/components/gnb/UserMenu.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ interface UserMenuProps {
1111
setIsMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
1212
}
1313

14+
const dropdownButtonStyles =
15+
"flex justify-center md:justify-start items-center w-full px-3 py-3 gap-3 font-16r text-black3 hover:text-[var(--primary)] hover:bg-[#f9f9f9] cursor-pointer";
16+
1417
const UserMenu: React.FC<UserMenuProps> = ({ isMenuOpen, setIsMenuOpen }) => {
1518
const { clearUser } = useUserStore();
1619
const router = useRouter();
@@ -36,23 +39,20 @@ const UserMenu: React.FC<UserMenuProps> = ({ isMenuOpen, setIsMenuOpen }) => {
3639
>
3740
<button
3841
onClick={() => router.push("/mypage")}
39-
className="flex justify-center items-center w-full pt-3 pb-2 font-16r text-black3 hover:bg-[var(--color-gray5)]"
42+
className={dropdownButtonStyles}
4043
>
41-
<User size={20} className="md:hidden" />
44+
<User size={20} />
4245
<span className="hidden md:block">내 정보</span>
4346
</button>
4447
<button
4548
onClick={() => router.push("/mydashboard")}
46-
className="flex justify-center items-center w-full pt-2 pb-2 font-16r text-black3 hover:bg-[var(--color-gray5)]"
49+
className={dropdownButtonStyles}
4750
>
48-
<FolderPen size={20} className="md:hidden" />
51+
<FolderPen size={20} />
4952
<span className="hidden md:block">내 대시보드</span>
5053
</button>
51-
<button
52-
onClick={handleLogout}
53-
className="flex justify-center items-center w-full pt-2 pb-3 font-16r text-black3 hover:bg-[var(--color-gray5)]"
54-
>
55-
<LogOut size={20} className="md:hidden" />
54+
<button onClick={handleLogout} className={dropdownButtonStyles}>
55+
<LogOut size={20} />
5656
<span className="hidden md:block">로그아웃</span>
5757
</button>
5858
</div>

src/hooks/useAuthGuard.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// 로그아웃 상태에서 인증 필수 페이지 접근 시, 로그인 페이지로 이동
1+
// 로그아웃 상태에서 인증 필수 페이지 접근 시, 로그인 페이지로 이동시키는 역할
2+
// 각 페이지에 import 해서 실행 함수 추가해 줘야 작동함
23
import { useEffect } from "react";
34
import { useRouter } from "next/router";
45
import useUserStore from "@/store/useUserStore";
@@ -30,7 +31,7 @@ export const useAuthGuard = (redirectTo: string = "/login") => {
3031
restoreUser();
3132
}, [user, redirectTo, setUser, router]);
3233

33-
// 로그아웃 상태에서 인증 페이지 접근 시 로그인 페이지로 이동
34+
// 직접 로그아웃한 게 아닐 때만 로그인 페이지로 이동
3435
useEffect(() => {
3536
const isLoggingOut = localStorage.getItem("isLoggingOut");
3637

src/pages/_app.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
import "@/styles/globals.css";
22
import type { AppProps } from "next/app";
3+
import { NextPage } from "next";
34
import { useEffect } from "react";
45
import { useRouter } from "next/router";
56
import useUserStore from "@/store/useUserStore";
67
import HeaderDefault from "@/components/gnb/HeaderDefault";
78
import { getUserInfo } from "@/api/users";
89
import { TEAM_ID } from "@/constants/team";
910

11+
type NextPageWithLayout = NextPage & {
12+
hideHeader?: boolean;
13+
};
14+
15+
type AppPropsWithLayout = AppProps & {
16+
Component: NextPageWithLayout;
17+
};
18+
1019
// 토큰 만료 설정
1120
function isTokenExpired() {
1221
const expiresAt = localStorage.getItem("expiresAt");
1322
if (!expiresAt) return true;
1423
return new Date().getTime() > parseInt(expiresAt, 10);
1524
}
1625

17-
export default function App({ Component, pageProps }: AppProps) {
26+
export default function App({ Component, pageProps }: AppPropsWithLayout) {
1827
useEffect(() => {
1928
const initializeUser = async () => {
2029
const token = localStorage.getItem("accessToken");
@@ -42,7 +51,7 @@ export default function App({ Component, pageProps }: AppProps) {
4251
// 헤더 숨길 페이지
4352
const noHeaderRoutes = ["/login", "/signup", "/mydashboard", "/mypage"];
4453
const isHeaderHidden =
45-
(Component as any).hideHeader ||
54+
Component.hideHeader ||
4655
noHeaderRoutes.includes(pathname) ||
4756
isDashboardPage;
4857

src/pages/mydashboard.tsx

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import DashboardAddButton from "@/components/button/DashboardAddButton";
99
import { getDashboards } from "@/api/dashboards";
1010
import { useRouter } from "next/router";
1111
import { useAuthGuard } from "@/hooks/useAuthGuard";
12+
import LoadingSpinner from "@/components/common/LoadingSpinner";
1213

1314
interface Dashboard {
1415
id: number;
@@ -29,21 +30,6 @@ export default function MyDashboardPage() {
2930
const [isModalOpen, setIsModalOpen] = useState(false);
3031
const itemsPerPage = 6;
3132

32-
useEffect(() => {
33-
if (isInitialized && user) {
34-
fetchDashboards();
35-
}
36-
}, [isInitialized, user]);
37-
38-
// 로그인 여부 파악 전 렌더링 X, 로딩 중 표시
39-
if (!isInitialized) {
40-
return (
41-
<div className="flex justify-center items-center h-screen">
42-
로딩 중...
43-
</div>
44-
);
45-
}
46-
4733
const totalPages = Math.ceil((dashboardList.length + 1) / itemsPerPage);
4834
const startIndex = (currentPage - 1) * itemsPerPage;
4935

@@ -69,6 +55,12 @@ export default function MyDashboardPage() {
6955
}
7056
};
7157

58+
useEffect(() => {
59+
if (isInitialized && user) {
60+
fetchDashboards();
61+
}
62+
}, [isInitialized, user]);
63+
7264
const handlePrevPage = () => {
7365
if (currentPage > 1) setCurrentPage((prev) => prev - 1);
7466
};
@@ -77,6 +69,10 @@ export default function MyDashboardPage() {
7769
if (currentPage < totalPages) setCurrentPage((prev) => prev + 1);
7870
};
7971

72+
if (!isInitialized || !user) {
73+
return <LoadingSpinner />;
74+
}
75+
8076
return (
8177
<div className="flex h-screen overflow-hidden">
8278
<SideMenu teamId={teamId} dashboardList={dashboardList} />

0 commit comments

Comments
 (0)