Skip to content

Commit 7c7efb2

Browse files
authored
Merge pull request #202 from part3-4team-Taskify/minji
[Style, Refactor] CardDetailModal: 전체적인 CSS 수정과 반응형 작업 / edit: 프로필 이미지 없이도 닉네임 변경
2 parents 6c0f5d8 + 96a37f4 commit 7c7efb2

File tree

14 files changed

+307
-177
lines changed

14 files changed

+307
-177
lines changed

src/components/card/Profile.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,22 @@ export const ProfileCard = () => {
5252
};
5353

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

5757
try {
58-
await updateProfile({ nickname, profileImageUrl: image });
58+
const payload: { nickname: string; profileImageUrl?: string } = {
59+
nickname,
60+
};
61+
if (image) {
62+
payload.profileImageUrl = image;
63+
}
64+
65+
await updateProfile(payload);
5966
updateNickname(nickname);
60-
updateProfileImage(image);
67+
68+
if (image) {
69+
updateProfileImage(image);
70+
}
6171
toast.success("프로필 변경이 완료되었습니다.");
6272
} catch (error) {
6373
console.error("프로필 변경 실패:", error);

src/components/modal/ChangeBebridge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect, ChangeEvent } from "react";
1+
import { useState, useEffect } from "react";
22
import { useRouter } from "next/router";
33
import Input from "../input/Input";
44
import Image from "next/image";

src/components/modalDashboard/CardDetail.tsx

Lines changed: 26 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Image from "next/image";
22
import { CardDetailType } from "@/types/cards";
3-
import { ProfileIcon } from "./profelicon";
3+
import { ColumnNameTag } from "../modalInput/chips/ColumnNameTag";
44
import ColorTagChip, {
55
getTagColor,
66
} from "@/components/modalInput/chips/ColorTagChip";
@@ -12,69 +12,33 @@ interface CardDetailProps {
1212

1313
export default function CardDetail({ card, columnName }: CardDetailProps) {
1414
return (
15-
<div className="p-4">
16-
{/* 담당자 정보 박스 */}
17-
<div className="absolute w-[181px] h-[155px] lg:[200px] top-20 right-10 rounded-lg p-3.5 bg-white border border-[#D9D9D9]">
18-
<div className="mb-3">
19-
<p className="text-sm font-semibold text-black3 mb-1">담당자</p>
20-
<div className="flex items-center gap-2">
21-
<ProfileIcon
22-
userId={card.assignee.id}
23-
nickname={card.assignee.nickname}
24-
profileImageUrl={card.assignee.profileImageUrl ?? ""}
25-
id={card.assignee.id}
26-
imgClassName="w-6 h-6"
27-
fontClassName="text-sm"
28-
/>
29-
<span className="text-sm text-black3">
30-
{card.assignee.nickname}
31-
</span>
32-
</div>
33-
34-
<div>
35-
<p className="text-sm font-semibold text-black3 mb-1 mt-3">
36-
마감일
37-
</p>
38-
<p className="text-sm text-black3">
39-
{new Date(card.dueDate).toLocaleString("ko-KR", {
40-
year: "numeric",
41-
month: "2-digit",
42-
day: "2-digit",
43-
hour: "2-digit",
44-
minute: "2-digit",
45-
})}
46-
</p>
47-
</div>
15+
<div className="flex flex-col gap-5 w-full">
16+
<div className="flex flex-wrap items-center gap-5">
17+
{/* 칼럼 이름 태그 */}
18+
<ColumnNameTag label={columnName} />
19+
{/* 구분선 */}
20+
<div className="w-[1px] h-[20px] bg-[var(--color-gray3)]" />
21+
{/* 카드 태그 */}
22+
<div className="flex flex-wrap gap-[6px]">
23+
{card.tags.map((tag, idx) => {
24+
const { textColor, bgColor } = getTagColor(idx);
25+
return (
26+
<ColorTagChip key={idx} className={`${textColor} ${bgColor}`}>
27+
{tag}
28+
</ColorTagChip>
29+
);
30+
})}
4831
</div>
4932
</div>
5033

51-
{/* 상태 + 태그 */}
52-
<div className="flex items-center gap-2 mb-2">
53-
<span
54-
className="rounded-full bg-violet-200 px-3 py-1 text-sm text-violet-800"
55-
title={`상태: ${columnName}`}
56-
>
57-
{columnName}
58-
</span>
59-
<span className="text-2xl font-extralight text-[#D9D9D9]">|</span>
60-
{card.tags.map((tag, idx) => {
61-
const { textColor, bgColor } = getTagColor(idx);
62-
return (
63-
<ColorTagChip key={idx} className={`${textColor} ${bgColor}`}>
64-
{tag}
65-
</ColorTagChip>
66-
);
67-
})}
68-
</div>
69-
70-
{/* 설명 */}
34+
{/* 내용 */}
7135
<p
7236
className="
73-
text-black3 p-2 overflow-auto
74-
w-full max-w-[470px] md:max-w-[349px]
37+
text-black font-normal sm:text-[14px] text-[12px] overflow-auto pr-1
38+
w-full lg:max-w-[445px] sm:max-w-[420px] max-w-[295px]
39+
min-h-0 sm:max-h-[100px] max-h-[80px]
7540
whitespace-pre-wrap word-break break-words
76-
h-[70px]
77-
"
41+
"
7842
>
7943
{card.description}
8044
</p>
@@ -85,9 +49,10 @@ export default function CardDetail({ card, columnName }: CardDetailProps) {
8549
<Image
8650
src={card.imageUrl}
8751
alt="카드 이미지"
88-
width={420}
89-
height={226}
90-
className="rounded-lg object-cover lg:w-[445px] lg:h-[260px] w-[420px] h-[246px]"
52+
width={290}
53+
height={168}
54+
className="rounded-lg object-cover
55+
lg:w-[445px] md:w-[420px]"
9156
/>
9257
</div>
9358
)}

src/components/modalDashboard/CardDetailModal.tsx

Lines changed: 104 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MoreVertical, X } from "lucide-react";
33
import CardDetail from "./CardDetail";
44
import CommentList from "./CommentList";
55
import CardInput from "@/components/modalInput/CardInput";
6+
import { Representative } from "@/components/modalDashboard/Representative";
67
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
78
import { createComment } from "@/api/comment";
89
import { deleteCard, EditCard } from "@/api/card";
@@ -95,78 +96,119 @@ export default function CardDetailPage({
9596

9697
return (
9798
<>
98-
<div className="fixed inset-0 bg-black/30 z-50 flex items-center justify-center px-4 sm:px-6">
99+
{/* 모달 고정 div */}
100+
<div
101+
className="fixed inset-0 bg-black/30 z-50
102+
flex items-center justify-center px-4 sm:px-6"
103+
>
104+
{/* 모달 컨테이너 */}
99105
<div
100-
className="
101-
relative bg-white rounded-lg shadow-lg flex flex-col
102-
w-[327px] h-[710px]
103-
md:w-[678px] md:h-[766px]
104-
lg:w-[730px] lg:h-[763px]
105-
"
106+
className="relative flex flex-col
107+
overflow-y-auto
108+
max-w-[730px] max-h-[calc(100vh-4rem)]
109+
lg:w-[730px] sm:w-[678px] w-[327px]
110+
bg-white rounded-lg shadow-lg"
106111
>
107-
<div className="flex justify-between items-center px-6 pt-6 pb-2">
108-
<h2 className="font-24sb">{cardData.title}</h2>
109-
<div className="flex items-center gap-3 relative" ref={popupRef}>
110-
<button
111-
onClick={() => setShowMenu((prev) => !prev)}
112-
className="w-7 h-7 flex items-center justify-center hover:cursor-pointer"
113-
title="수정하기"
114-
type="button"
115-
>
116-
<MoreVertical className="w-8 h-8 text-black cursor-pointer" />
117-
</button>
118-
{showMenu && (
119-
<div className="absolute right-0 top-10 p-2 w-27 bg-white border border-[#D9D9D9] z-40 rounded-lg">
112+
<div className="flex items-center justify-center px-6 pt-6 pb-2">
113+
{/* 내부 아이템 컨테이너 */}
114+
<div className="flex flex-col lg:w-[674px] sm:w-[614px] w-[295px]">
115+
{/* 헤더 */}
116+
<div className="flex justify-between sm:mb-4 mb-2">
117+
{/* 카드 제목 */}
118+
<h2 className="text-black3 font-bold sm:text-[24px] text-[20px]">
119+
{cardData.title}
120+
</h2>
121+
{/* 버튼 컨테이너 */}
122+
<div
123+
className="relative flex items-center sm:gap-[24px] gap-[16px]"
124+
ref={popupRef}
125+
>
126+
{/* 메뉴 버튼 */}
120127
<button
121-
className="block w-full px-4 py-2 text-base text-gray-800 hover:bg-[#F1EFFD] hover:text-[#5534DA] rounded-sm cursor-pointer"
128+
onClick={() => setShowMenu((prev) => !prev)}
129+
className="sm:w-[28px] sm:h-[28px] w-[20px] h-[20px]
130+
flex items-center justify-center hover:cursor-pointer"
131+
title="수정하기"
122132
type="button"
123-
onClick={() => {
124-
setIsEditModalOpen(true);
125-
setShowMenu(false);
126-
}}
127133
>
128-
수정하기
134+
<MoreVertical className="w-8 h-8 text-black3 cursor-pointer" />
129135
</button>
130-
<button
131-
className="block w-full px-4 py-2 text-base text-gray-800 hover:bg-[#F1EFFD] hover:text-[#5534DA] rounded-sm cursor-pointer"
132-
type="button"
133-
onClick={() => deleteCardMutate()}
134-
>
135-
삭제하기
136+
{showMenu && (
137+
<div
138+
className="absolute right-0 top-9.5 p-2 z-40
139+
sm:w-28 w-20
140+
bg-white border border-[#D9D9D9] rounded-lg"
141+
>
142+
<button
143+
className="w-full rounded-sm
144+
font-normal sm:text-[14px] text-[12px] text-black3
145+
hover:bg-[#F1EFFD] hover:text-[#5534DA]
146+
cursor-pointer"
147+
type="button"
148+
onClick={() => {
149+
setIsEditModalOpen(true);
150+
setShowMenu(false);
151+
}}
152+
>
153+
수정하기
154+
</button>
155+
<button
156+
className="w-full rounded-sm
157+
font-normal sm:text-[14px] text-[12px] text-black3
158+
hover:bg-[#F1EFFD] hover:text-[#5534DA]
159+
cursor-pointer"
160+
type="button"
161+
onClick={() => deleteCardMutate()}
162+
>
163+
삭제하기
164+
</button>
165+
</div>
166+
)}
167+
{/* 닫기 버튼 */}
168+
<button onClick={handleClose} title="닫기">
169+
<X
170+
className="sm:w-[28px] sm:h-[28px] w-[20px] h-[20px]
171+
flex items-center justify-center hover:cursor-pointer"
172+
/>
136173
</button>
137174
</div>
138-
)}
139-
<button onClick={handleClose} title="닫기">
140-
<X className="w-7 h-7 flex items-center justify-center hover:cursor-pointer" />
141-
</button>
142-
</div>
143-
</div>
175+
</div>
144176

145-
{/* 콘텐츠 (스크롤 없음) */}
146-
<div className="px-6 pb-4 flex flex-col gap-6 flex-1 overflow-hidden">
147-
{/* 카드 상세 */}
148-
<CardDetail card={cardData} columnName={columnName} />
149-
150-
{/* 댓글 입력 */}
151-
<div className="w-full max-w-[450px]">
152-
<p className="text-sm font-semibold mb-2">댓글</p>
153-
<CardInput
154-
hasButton
155-
small
156-
value={commentText}
157-
onTextChange={setCommentText}
158-
onButtonClick={handleCommentSubmit}
159-
placeholder="댓글 작성하기"
160-
/>
161-
</div>
177+
{/* 카드 내용 + 담당자 컨테이너 */}
178+
<div className="flex flex-col-reverse sm:flex-row gap-4">
179+
<CardDetail card={cardData} columnName={columnName} />
180+
<div>
181+
<Representative card={card} />
182+
</div>
183+
</div>
162184

163-
{/* 댓글 리스트 (스크롤 가능) */}
164-
<div className="w-full max-w-[450px] text-base max-h-[180px] overflow-y-auto scrollbar-hidden">
165-
<CommentList
166-
cardId={card.id}
167-
currentUserId={currentUserId}
168-
teamId={""}
169-
/>
185+
{/* 댓글 입력창 */}
186+
<div className="mt-4 w-full lg:max-w-[445px] md:max-w-[420px]">
187+
<p className="mb-1 text-black3 font-medium sm:text-[16px] text-[14px]">
188+
댓글
189+
</p>
190+
<CardInput
191+
hasButton
192+
small
193+
value={commentText}
194+
onTextChange={setCommentText}
195+
onButtonClick={handleCommentSubmit}
196+
placeholder="댓글 작성하기"
197+
/>
198+
</div>
199+
200+
{/* 댓글 목록 (스크롤 가능) */}
201+
<div
202+
className="w-full lg:max-w-[445px] md:max-w-[420px]
203+
sm:max-h-[140px] max-h-[70px]
204+
my-2 overflow-y-auto"
205+
>
206+
<CommentList
207+
cardId={card.id}
208+
currentUserId={currentUserId}
209+
teamId={""}
210+
/>
211+
</div>
170212
</div>
171213
</div>
172214
</div>

src/components/modalDashboard/CommentList.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,29 @@ export default function CommentList({
3737
data?.pages.flatMap((page) => page.comments) ?? [];
3838

3939
return (
40-
<div className="min-h-[80px] p-2 rounded bg-white shadow-sm">
41-
{allComments.map((comment) => (
42-
<div key={comment.id} className="p-2 last:border-b-0">
43-
<UpdateComment
44-
comment={comment}
45-
currentUserId={currentUserId}
46-
teamId={""}
47-
/>
48-
</div>
49-
))}
40+
<div
41+
className="min-h-[80px] sm:max-h-[240px] max-h-[215px] w-full
42+
rounded bg-white
43+
flex flex-col"
44+
>
45+
{allComments.length === 0 ? (
46+
<p
47+
className="sm:pt-8 pt-4 text-center text-[var(--color-gray1)]
48+
font-normal sm:text-[14px] text-[12px]"
49+
>
50+
작성된 댓글이 없습니다.
51+
</p>
52+
) : (
53+
allComments.map((comment) => (
54+
<div key={comment.id} className=" shrink-0 py-2 last:border-b-0">
55+
<UpdateComment
56+
comment={comment}
57+
currentUserId={currentUserId}
58+
teamId={""}
59+
/>
60+
</div>
61+
))
62+
)}
5063
<div ref={ref} />
5164
</div>
5265
);

src/components/modalDashboard/profelicon.tsx renamed to src/components/modalDashboard/ProfileIcon.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ export const ProfileIcon: React.FC<ProfileIconProps> = ({
1515
nickname,
1616
profileImageUrl,
1717
}) => (
18-
<div className="relative w-[34px] h-[34px] md:w-[38px] md:h-[38px] rounded-full overflow-hidden">
18+
<>
1919
{profileImageUrl ? (
2020
<Image
2121
src={profileImageUrl}
2222
alt="유저 프로필 아이콘"
23-
fill
24-
className="object-cover"
23+
width={34}
24+
height={34}
25+
className="object-cover w-[26px] h-[26px] rounded-full"
2526
/>
2627
) : (
2728
<RandomProfile name={nickname} />
2829
)}
29-
</div>
30+
</>
3031
);

0 commit comments

Comments
 (0)