Skip to content

Commit 2303e02

Browse files
author
ozen0718
committed
담당자 드롭다운 프로필이미지
1 parent 74770ef commit 2303e02

File tree

9 files changed

+95
-66
lines changed

9 files changed

+95
-66
lines changed

src/api/members.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,47 @@
11
import axiosInstance from "./axiosInstance";
22
import { apiRoutes } from "./apiRoutes";
33

4-
// 대시보드 멤버 목록 조회
5-
export const getMembers = async ({ dashboardId }: { dashboardId: number }) => {
4+
// 멤버 타입 정의
5+
export interface Member {
6+
id: number;
7+
userId: number;
8+
email: string;
9+
nickname: string;
10+
profileImageUrl: string | null;
11+
isOwner: boolean;
12+
createdAt?: string;
13+
updatedAt?: string;
14+
}
15+
16+
// 🔹 대시보드 멤버 목록 조회
17+
export const getMembers = async ({
18+
dashboardId,
19+
}: {
20+
dashboardId: number;
21+
}): Promise<Member[]> => {
622
if (!dashboardId) {
7-
console.error("dashboardID가 없습니다.");
23+
console.error("dashboardId가 없습니다.");
24+
return [];
25+
}
26+
27+
try {
28+
const response = await axiosInstance.get(apiRoutes.members(), {
29+
params: {
30+
dashboardId,
31+
},
32+
});
33+
34+
const members: Member[] = response.data.members || [];
35+
36+
console.log("✅ getMembers 응답 데이터:", members); // 디버깅용 로그
37+
return members;
38+
} catch (error) {
39+
console.error("🚨 getMembers API 실패:", error);
840
return [];
941
}
10-
const response = await axiosInstance.get(apiRoutes.members(), {
11-
params: {
12-
dashboardId,
13-
},
14-
});
15-
return response.data.members || [];
1642
};
1743

18-
// 대시보드 멤버 삭제
44+
// 🔹 대시보드 멤버 삭제
1945
export const deleteMembers = async (memberId: number) => {
2046
const response = await axiosInstance.delete(apiRoutes.memberDetail(memberId));
2147
return response.data;

src/components/columnCard/Column.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ export default function Column({
4646
const [isCardDetailModalOpen, setIsCardDetailModalOpen] = useState(false);
4747
const [selectedCard, setSelectedCard] = useState<CardDetailType | null>(null);
4848
const [members, setMembers] = useState<
49-
{ id: number; userId: number; nickname: string }[]
49+
{
50+
id: number;
51+
userId: number;
52+
nickname: string;
53+
profileImageUrl: string | null;
54+
}[]
5055
>([]);
5156

5257
const maxColumnTitleLength = 15;
@@ -64,6 +69,7 @@ export default function Column({
6469
id: m.id,
6570
userId: m.userId,
6671
nickname: m.nickname || m.email,
72+
profileImageUrl: m.profileImageUrl,
6773
}));
6874

6975
setMembers(parsed);

src/components/modalDashboard/CardDetailModal.tsx

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useRef } from "react";
21
import clsx from "clsx";
32
import { MoreVertical, X } from "lucide-react";
43
import CardDetail from "./CardDetail";
@@ -12,6 +11,7 @@ import { TEAM_ID } from "@/constants/team";
1211
import { useDashboardPermission } from "@/hooks/useDashboardPermission";
1312
import { useCardDetailState } from "@/hooks/useCardDetailState";
1413
import { useCardDetail } from "@/hooks/useCardDetail";
14+
import { getCardDetail } from "@/api/card";
1515
import type { CardDetailType } from "@/types/cards";
1616

1717
interface CardDetailModalProps {
@@ -162,24 +162,16 @@ export default function CardDetailPage({
162162
dashboardId={dashboardId}
163163
members={members}
164164
onClose={() => setIsEditModalOpen(false)}
165-
onSubmit={(updatedData) => {
166-
onChangeCard?.();
167-
setCardData((prev) => ({
168-
...prev,
169-
title: updatedData.title,
170-
description: updatedData.description,
171-
dueDate: updatedData.deadline ?? "",
172-
tags: updatedData.tags,
173-
imageUrl: updatedData.image ?? "",
174-
assignee: {
175-
...prev.assignee,
176-
nickname: updatedData.assignee,
177-
},
178-
columnId:
179-
columns.find((col) => col.title === updatedData.status)?.id ??
180-
prev.columnId,
181-
}));
182-
setIsEditModalOpen(false);
165+
onSubmit={async () => {
166+
try {
167+
const updatedCard = await getCardDetail(cardData.id);
168+
setCardData(updatedCard);
169+
onChangeCard?.();
170+
} catch (error) {
171+
toast.error("카드 정보를 불러오는 데 실패했습니다.");
172+
} finally {
173+
setIsEditModalOpen(false);
174+
}
183175
}}
184176
initialData={{
185177
status: columnName,

src/components/modalDashboard/CardProfileIcon.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const ProfileIcon: React.FC<ProfileIconProps> = ({
2121
<>
2222
{profileImageUrl ? (
2323
<Image
24+
key={profileImageUrl}
2425
src={profileImageUrl}
2526
alt="유저 프로필 아이콘"
2627
width={26}

src/components/modalDashboard/Representative.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const Representative = ({ card }: RepresentativeProps) => {
2020
<p className="font-12sb text-black3 mb-[4px]">담당자</p>
2121
<div className="flex items-center gap-2">
2222
<ProfileIcon
23+
key={card.assignee.profileImageUrl}
2324
userId={card.assignee.id}
2425
nickname={card.assignee.nickname}
2526
profileImageUrl={card.assignee.profileImageUrl ?? ""}

src/components/modalInput/AssigneeSelect.tsx

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { useState } from "react";
2-
import RandomProfile from "@/components/common/RandomProfile";
32

43
interface User {
54
id: number;
6-
name: string;
5+
userId: number;
6+
nickname: string;
7+
profileImageUrl: string | null;
78
}
89

910
interface AssigneeSelectProps {
@@ -23,11 +24,10 @@ export default function AssigneeSelect({
2324
}: AssigneeSelectProps) {
2425
const [isOpen, setIsOpen] = useState(false);
2526
const [filter, setFilter] = useState("");
26-
const selectedUser = users.find((u) => u.name === value);
2727

28-
// 유저 필터링
28+
const selectedUser = users.find((u) => u.nickname === value);
2929
const filtered = users.filter((user) =>
30-
user.name.toLowerCase().includes(filter.toLowerCase())
30+
user.nickname.toLowerCase().includes(filter.toLowerCase())
3131
);
3232

3333
return (
@@ -40,21 +40,25 @@ export default function AssigneeSelect({
4040
)}
4141

4242
<div className="relative w-full">
43-
{/* 선택된 담당자 */}
43+
{/* 선택된 담당자 표시 */}
4444
<div
4545
className="flex items-center justify-between h-[48px] px-4 border border-[var(--color-gray3)] rounded-md cursor-pointer focus-within:border-[var(--primary)]"
4646
onClick={() => setIsOpen(!isOpen)}
4747
>
4848
<div className="flex items-center gap-2">
49-
{value ? (
49+
{selectedUser ? (
5050
<>
51-
<RandomProfile
52-
name={value}
53-
userId={selectedUser?.id ?? 0}
54-
className="w-[26px] h-[26px]"
55-
/>
51+
{selectedUser.profileImageUrl ? (
52+
<img
53+
src={selectedUser.profileImageUrl}
54+
alt={`${selectedUser.nickname} 프로필`}
55+
className="w-[26px] h-[26px] rounded-full object-cover"
56+
/>
57+
) : (
58+
<div className="w-[26px] h-[26px] rounded-full bg-gray-300" />
59+
)}
5660
<span className="font-normal text-[14px] sm:text-[16px]">
57-
{value}
61+
{selectedUser.nickname}
5862
</span>
5963
</>
6064
) : (
@@ -65,35 +69,34 @@ export default function AssigneeSelect({
6569
</div>
6670
</div>
6771

68-
{/* 드롭다운 */}
72+
{/* 드롭다운 목록 */}
6973
{isOpen && (
70-
<ul
71-
className="absolute z-10 top-full left-0 mt-1
72-
w-full max-h-[200px] overflow-y-auto
73-
bg-white border border-[var(--color-gray3)] rounded-md shadow-lg"
74-
>
75-
{filtered.map((user, idx) => (
74+
<ul className="absolute z-10 top-full left-0 mt-1 w-full max-h-[200px] overflow-y-auto bg-white border border-[var(--color-gray3)] rounded-md shadow-lg">
75+
{filtered.map((user) => (
7676
<li
77-
key={idx}
77+
key={user.userId}
7878
onClick={() => {
79-
onChange(user.name);
79+
onChange(user.nickname);
8080
setIsOpen(false);
8181
setFilter("");
8282
}}
83-
className="flex items-center justify-between
84-
px-4 py-2 cursor-pointer hover:bg-gray-100"
83+
className="flex items-center justify-between px-4 py-2 cursor-pointer hover:bg-gray-100"
8584
>
8685
<div className="flex items-center gap-2">
87-
<RandomProfile
88-
name={user.name}
89-
userId={user.id}
90-
className="w-[26px] h-[26px]"
91-
/>
86+
{user.profileImageUrl ? (
87+
<img
88+
src={user.profileImageUrl}
89+
alt={`${user.nickname} 프로필`}
90+
className="w-[26px] h-[26px] rounded-full object-cover"
91+
/>
92+
) : (
93+
<div className="w-[26px] h-[26px] rounded-full bg-gray-300" />
94+
)}
9295
<span className="font-normal text-black3 sm:text-[16px] text-[14px]">
93-
{user.name}
96+
{user.nickname}
9497
</span>
9598
</div>
96-
{value === user.name && (
99+
{value === user.nickname && (
97100
<span className="text-[var(--primary)]"></span>
98101
)}
99102
</li>

src/components/modalInput/TaskModal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface TaskModalProps {
1717
id: number;
1818
userId: number;
1919
nickname: string;
20+
profileImageUrl: string | null;
2021
}[];
2122
columnId: number;
2223
dashboardId: number;
@@ -60,7 +61,7 @@ export default function TaskModal({
6061
onClose,
6162
onSubmit,
6263
});
63-
64+
console.log("🔍 members in TaskModal", members);
6465
return (
6566
<div className="fixed inset-0 flex items-center justify-center bg-black/35 z-50">
6667
<div className="sm:w-[584px] w-[327px] h-[calc(var(--vh)_*_90)] rounded-lg bg-white p-4 sm:p-8 shadow-lg flex flex-col gap-4 sm:gap-8 overflow-y-auto">
@@ -69,6 +70,7 @@ export default function TaskModal({
6970
</h2>
7071

7172
<div className="flex flex-col gap-4 sm:gap-8">
73+
{/* 상태 및 담당자 */}
7274
<div className="flex flex-col sm:flex-row gap-4 text-black3 font-normal text-[14px] sm:text-[16px]">
7375
<StatusSelect
7476
label="상태"
@@ -81,7 +83,7 @@ export default function TaskModal({
8183
label="담당자"
8284
value={formData.assignee}
8385
required
84-
users={members.map((m) => ({ id: m.id, name: m.nickname }))}
86+
users={members} // ✅ 전체 멤버 데이터 전달
8587
onChange={(value) => handleChange("assignee", value)}
8688
/>
8789
</div>

src/hooks/useCardDetail.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// src/hooks/useCardDetail.ts
2-
import { useState, useRef, useMemo } from "react";
1+
import { useState, useRef } from "react";
32
import { useMutation, useQueryClient } from "@tanstack/react-query";
43
import { deleteCard } from "@/api/card";
54
import { toast } from "react-toastify";

src/hooks/useTaskForm.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export function useTaskForm({
2727
initialData,
2828
members,
2929
dashboardId,
30-
columnId,
3130
cardId,
3231
updatedColumnId,
3332
onClose,

0 commit comments

Comments
 (0)