Skip to content

Commit 013b021

Browse files
authored
Merge pull request #188 from part3-4team-Taskify/minji
[Refactor, Style] Zustand 전역 상태 관리에 유저 정보 추가 / mypage: 프로필 변경 즉시 반영
2 parents bbc969c + 6150559 commit 013b021

File tree

8 files changed

+68
-72
lines changed

8 files changed

+68
-72
lines changed

src/api/users.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const signUp = async ({ payload }: { payload: SignUpRequest }) => {
2020
};
2121

2222
// 내 정보 조회 (GET)
23-
export const getUserInfo = async () => {
23+
export const getUserInfo = async (): Promise<UserType> => {
2424
const response = await axiosInstance.get<UserType>(apiRoutes.usersMe());
2525
return response.data;
2626
};

src/components/card/ChangePassword.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ export default function ChangePassword() {
4242
setNewPassword("");
4343
setCheckNewPassword("");
4444
setIsSubmitting(false);
45-
setTimeout(() => {
46-
router.reload();
47-
}, 1500);
4845
};
4946

5047
return (

src/components/card/Profile.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { useState, useEffect } from "react";
2-
import { useRouter } from "next/router";
2+
import useUserStore from "@/store/useUserStore";
33
import Image from "next/image";
44
import { getUserInfo, updateProfile, uploadProfileImage } from "@/api/users";
55
import Input from "@/components/input/Input";
66
import { toast } from "react-toastify";
77

8-
export default function ProfileCard() {
9-
const router = useRouter();
10-
const [image, setImage] = useState<string | null>(null);
11-
const [nickname, setNickname] = useState("");
8+
export const ProfileCard = () => {
9+
const { user, updateNickname, updateProfileImage } = useUserStore();
10+
const [image, setImage] = useState(user?.profileImageUrl);
11+
const [nickname, setNickname] = useState(user?.nickname);
1212
const [email, setEmail] = useState("");
1313
const [preview, setPreview] = useState<string | null>(null);
1414

@@ -46,28 +46,22 @@ export default function ProfileCard() {
4646
setImage(response.profileImageUrl); // 서버에서 받은 URL 저장
4747
} catch (error) {
4848
console.error("이미지 업로드 실패:", error);
49-
toast.error("이미지 업로드에 실패하였습니다.");
49+
toast.error("이미지 업로드에 실패했습니다.");
5050
}
5151
}
5252
};
5353

5454
const handleSave = async () => {
5555
if (!nickname || !image) return;
5656

57-
const userProfile = {
58-
nickname,
59-
profileImageUrl: image,
60-
};
61-
6257
try {
63-
await updateProfile(userProfile);
58+
await updateProfile({ nickname, profileImageUrl: image });
59+
updateNickname(nickname);
60+
updateProfileImage(image);
6461
toast.success("프로필 변경이 완료되었습니다.");
65-
setTimeout(() => {
66-
router.reload();
67-
}, 1500);
6862
} catch (error) {
6963
console.error("프로필 변경 실패:", error);
70-
toast.error("프로필 변경에 실패하였습니다.");
64+
toast.error("프로필 변경에 실패했습니다.");
7165
}
7266
};
7367

@@ -138,4 +132,4 @@ export default function ProfileCard() {
138132
</div>
139133
</div>
140134
);
141-
}
135+
};

src/components/gnb/HeaderDashboard.tsx

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React, { useState, useEffect } from "react";
22
import { useRouter } from "next/router";
3+
import useUserStore from "@/store/useUserStore";
34
import clsx from "clsx";
45
import Image from "next/image";
56
import SkeletonUser from "@/shared/skeletonUser";
6-
import { MemberType, UserType } from "@/types/users";
7+
import { MemberType } from "@/types/users";
78
import { getMembers } from "@/api/members";
8-
import { getUserInfo } from "@/api/users";
99
import { getDashboardById } from "@/api/dashboards";
1010
import { UserProfileIcon } from "@/components/gnb/ProfileIcon";
1111
import MembersProfileIconList from "@/components/gnb/MembersProfileIconList";
@@ -28,8 +28,10 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
2828
onToggleEditMode,
2929
}) => {
3030
const router = useRouter();
31+
const user = useUserStore((state) => state.user);
32+
const isUserLoading = !user;
33+
const nickname = useUserStore((state) => state.user?.nickname);
3134
const [isLoading, setIsLoading] = useState(true);
32-
const [user, setUser] = useState<UserType | null>(null);
3335
const [members, setMembers] = useState<MemberType[]>([]);
3436
const [isMenuOpen, setIsMenuOpen] = useState(false);
3537
const [isListOpen, setIsListOpen] = useState(false);
@@ -63,32 +65,12 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
6365
setIsLoading(false);
6466
}
6567
};
66-
if (
67-
(variant === "dashboard" || variant === "mypage" || variant === "edit") &&
68-
dashboardId
69-
) {
68+
if (variant === "mypage" || variant === "mydashboard") {
69+
setIsLoading(false);
70+
} else if ((variant === "dashboard" || variant === "edit") && dashboardId) {
7071
fetchMembers();
7172
}
72-
}, [dashboardId, variant]);
73-
74-
/*유저 정보 api 호출*/
75-
useEffect(() => {
76-
const fetchUser = async () => {
77-
try {
78-
const user = await getUserInfo();
79-
setUser(user);
80-
} catch (error) {
81-
console.error("유저 정보 불러오기 실패", error);
82-
setErrorMessage("유저 정보를 불러오지 못했습니다.");
83-
} finally {
84-
setIsLoading(false);
85-
}
86-
};
87-
const token = localStorage.getItem("accessToken");
88-
if (token) {
89-
fetchUser();
90-
}
91-
}, []);
73+
}, [variant, dashboardId]);
9274

9375
/*대시보드 api 호출*/
9476
useEffect(() => {
@@ -273,14 +255,14 @@ const HeaderDashboard: React.FC<HeaderDashboardProps> = ({
273255
setIsMenuOpen={setIsMenuOpen}
274256
/>
275257
{/*유저 프로필*/}
276-
{isLoading ? (
258+
{isUserLoading ? (
277259
<SkeletonUser />
278260
) : (
279261
user && (
280262
<>
281263
<UserProfileIcon user={user} />
282264
<span className="hidden md:block text-black3 md:text-base md:font-medium max-w-[90px] truncate whitespace-nowrap">
283-
{user.nickname}
265+
{nickname}
284266
</span>
285267
</>
286268
)

src/components/table/invited/InvitedDashBoard.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,15 @@ function InvitedList({
104104
)}
105105

106106
{/* 리스트 */}
107-
<div className="scroll-area h-[150vw] max-h-[570px] sm:max-h-[320px] lg:max-h-[280px] overflow-y-auto overflow-x-hidden">
107+
<div className="scroll-area h-[150vw] max-h-[380px] sm:max-h-[240px] lg:max-h-[280px] overflow-y-auto overflow-x-hidden">
108108
{filteredData.length > 0 ? (
109109
filteredData.map((invite, index) => (
110110
<div
111111
key={index}
112112
className="pb-5 mb-[20px] w-full max-w-[260px] sm:max-w-[504px] lg:max-w-[966px]
113113
h-auto sm:h-[50px] border-b border-[var(--color-gray4)]
114114
sm:grid sm:grid-cols-[3fr_2fr_3fr] sm:items-center
115+
text-black3 text-[14px] sm:text-[16px] font-normal
115116
flex flex-col gap-10"
116117
>
117118
{/* 모바일 레이아웃 */}
@@ -274,7 +275,7 @@ export default function InvitedDashBoard() {
274275
{invitationArray.length === 0 ? (
275276
<EmptyInvitations />
276277
) : (
277-
<div className="relative bg-white rounded-lg shadow-md w-[260px] sm:w-[504px] lg:w-[1022px] h-[770px] sm:h-[592px] lg:h-[500px] max-w-none">
278+
<div className="relative bg-white rounded-lg shadow-md w-[260px] sm:w-[504px] lg:w-[1022px] h-[550px] sm:h-[450px] lg:h-[500px] max-w-none">
278279
<div className="flex flex-col p-6 w-full h-[104px]">
279280
<div className="flex flex-col w-full sm:w-[448px] lg:w-[966px] gap-[24px]">
280281
<p className="text-black3 text-[16px] sm:text-[20px] font-bold">

src/pages/dashboard/[dashboardId]/edit.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ export default function EditDashboard() {
6464
<HeaderDashboardEdit variant="edit" dashboardId={dashboardId} />
6565

6666
<div
67-
className="overflow-auto flex-1 px-6 pt-6 pb-10"
67+
className="overflow-auto flex-1 pt-6 pb-10"
6868
style={{ backgroundColor: "#F5F2FC" }}
6969
>
70-
<BackButton />
71-
70+
<div className="sm:px-8 lg:px-6 px-2.5">
71+
<BackButton />
72+
</div>
7273
{/* 백버튼 아래 전체 아이템 컨테이너 */}
73-
<div className="flex flex-col items-center lg:items-start mt-6 gap-6">
74+
<div className="flex flex-col items-center lg:items-start px-6 mt-6 gap-6">
7475
<ChangeBebridge />
7576
{/* MemberList는 아래쪽에 배치 */}
7677
<MemberList dashboardId={dashboardId} />

src/pages/mypage.tsx

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,48 @@
11
import React, { useState, useEffect } from "react";
2-
import { useRouter } from "next/router";
32
import { useAuthGuard } from "@/hooks/useAuthGuard";
3+
import useUserStore from "@/store/useUserStore";
44
import HeaderMyPage from "@/components/gnb/HeaderDashboard";
55
import SideMenu from "@/components/sideMenu/SideMenu";
6-
import ProfileCard from "@/components/card/Profile";
6+
import { ProfileCard } from "@/components/card/Profile";
77
import ChangePassword from "@/components/card/ChangePassword";
88
import BackButton from "@/components/button/BackButton";
99
import { Dashboard, getDashboards } from "@/api/dashboards";
10+
import { getUserInfo } from "@/api/users";
1011
import { TEAM_ID } from "@/constants/team";
1112
import LoadingSpinner from "@/components/common/LoadingSpinner";
13+
import { toast } from "react-toastify";
1214

1315
export default function MyPage() {
1416
const { user, isInitialized } = useAuthGuard();
15-
const router = useRouter();
17+
const { setUser } = useUserStore();
1618
const [dashboards, setDashboards] = useState<Dashboard[]>([]);
1719

20+
// 사이드메뉴 대시보드 목록 api 호출
1821
const fetchDashboards = async () => {
1922
try {
2023
const res = await getDashboards({});
21-
setDashboards(res.dashboards); // 👉 정상 저장
24+
setDashboards(res.dashboards);
2225
} catch (error) {
2326
console.error("대시보드 불러오기 실패:", error);
27+
toast.error("대시보드를 불러오는 데 실패했습니다");
28+
}
29+
};
30+
31+
// 프로필 변경 섹션 유저 정보 api 호출
32+
const fetchUserData = async () => {
33+
try {
34+
const res = await getUserInfo();
35+
setUser(res);
36+
} catch (error) {
37+
console.error("유저 정보 불러오기 실패:", error);
38+
toast.error("유저 정보를 불러오는 데 실패했습니다.");
2439
}
2540
};
2641

2742
useEffect(() => {
2843
if (isInitialized && user) {
2944
fetchDashboards();
45+
fetchUserData();
3046
}
3147
}, [isInitialized, user]);
3248

@@ -43,10 +59,13 @@ export default function MyPage() {
4359
/>
4460
<div className="flex flex-col flex-1 overflow-hidden bg-[#F5F2FC]">
4561
<HeaderMyPage variant="mypage" />
46-
<div className="flex flex-col justify-start overflow-auto w-full px-6 mt-6 pb-10">
47-
<BackButton />
62+
<div className="flex flex-col justify-start overflow-auto w-full mt-6 pb-10">
63+
{/* 백버튼 여백 */}
64+
<div className="sm:px-8 lg:px-6 px-2.5">
65+
<BackButton />
66+
</div>
4867
{/* 백버튼 아래 전체 아이템 컨테이너 */}
49-
<div className="flex flex-col items-center lg:items-start mt-6 gap-6">
68+
<div className="flex flex-col items-center lg:items-start px-6 mt-6 gap-6">
5069
<ProfileCard />
5170
<ChangePassword />
5271
</div>

src/store/useUserStore.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
import { create } from "zustand";
2-
3-
interface UserInfo {
4-
id: number;
5-
email: string;
6-
nickname: string;
7-
profileImageUrl: string;
8-
}
2+
import { UserType } from "@/types/users";
93

104
interface UserState {
11-
user: UserInfo | null;
5+
user: UserType | null;
126
isInitialized: boolean;
13-
setUser: (user: UserInfo) => void;
7+
setUser: (user: UserType) => void;
148
clearUser: () => void;
9+
updateNickname: (nickname: string) => void;
10+
updateProfileImage: (url: string) => void;
1511
}
1612

1713
const useUserStore = create<UserState>((set) => ({
1814
user: null,
1915
isInitialized: false,
2016
setUser: (user) => set({ user, isInitialized: true }),
2117
clearUser: () => set({ user: null, isInitialized: true }),
18+
updateNickname: (nickname: string) =>
19+
set((state) => ({ user: state.user ? { ...state.user, nickname } : null })),
20+
updateProfileImage: (url: string) =>
21+
set((state) => ({
22+
user: state.user ? { ...state.user, profileImageUrl: url } : null,
23+
})),
2224
}));
2325

2426
export default useUserStore;

0 commit comments

Comments
 (0)