Skip to content

Commit ee5e935

Browse files
authored
Merge pull request #199 from part3-4team-Taskify/minji
[Style, Refactor] edit: 내부 컴포넌트 정렬 통일 / NewDashboard: 대시보드 이름 30자 제한 / InviteRecords: 초대 내역 즉시 반영
2 parents 1e65c25 + 79ea49d commit ee5e935

File tree

10 files changed

+338
-221
lines changed

10 files changed

+338
-221
lines changed

src/components/modal/ChangeBebridge.tsx

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from "react";
1+
import { useState, useEffect, ChangeEvent } from "react";
22
import { useRouter } from "next/router";
33
import Input from "../input/Input";
44
import Image from "next/image";
@@ -18,8 +18,10 @@ const ChangeBebridge = ({ onUpdate }: ChangeBebridgeProps) => {
1818
{}
1919
);
2020
const [title, setTitle] = useState("");
21+
const [titleLength, setTitleLength] = useState<number>(0);
2122
const [selected, setSelected] = useState<number | null>(null);
2223
const colors = ["#7ac555", "#760DDE", "#FF9800", "#76A5EA", "#E876EA"];
24+
const maxTitleLength = 30;
2325

2426
/* 대시보드 이름 데이터 */
2527
useEffect(() => {
@@ -40,18 +42,26 @@ const ChangeBebridge = ({ onUpdate }: ChangeBebridgeProps) => {
4042
}
4143
} catch (error) {
4244
console.error("대시보드 상세내용 불러오는데 오류 발생:", error);
45+
toast.error("대시보드를 불러오는 데 실패했습니다.");
4346
}
4447
};
4548
if (dashboardId) {
4649
fetchDashboardTitle();
4750
}
4851
}, [dashboardId]);
4952

50-
/* 대시보드 이름 변경 버튼 */
51-
const handleUpdate = async () => {
52-
const dashboardIdNumber = Number(dashboardId);
53+
/* 대시보드 이름 글자수 제한 */
54+
const handleTitleChange = async (value: string) => {
55+
if (value.length <= maxTitleLength) {
56+
setTitle(value);
57+
setTitleLength(value.length);
58+
}
59+
};
60+
61+
const handleSubmit = async () => {
5362
if (!dashboardId || selected === null) return;
5463

64+
const dashboardIdNumber = Number(dashboardId);
5565
const payload = {
5666
title,
5767
color: colors[selected],
@@ -68,7 +78,7 @@ const ChangeBebridge = ({ onUpdate }: ChangeBebridgeProps) => {
6878
color: colors[selected],
6979
}));
7080

71-
toast.success("대시보드가 변경되었습니다!");
81+
toast.success("대시보드가 변경되었습니다.");
7282
if (onUpdate) onUpdate();
7383
} catch (error) {
7484
console.error("대시보드 변경 실패:", error);
@@ -77,48 +87,68 @@ const ChangeBebridge = ({ onUpdate }: ChangeBebridgeProps) => {
7787
};
7888

7989
return (
80-
<div className="lg:w-[620px] lg:h-[344px] sm:w-[544px] sm:h-[344px] w-[284px] h-[312px] bg-white rounded-[12px] p-[24px] flex flex-col">
81-
<h2 className="text-black3 text-[20px] sm:text-[24px] font-bold">
82-
{dashboardDetail.title}
83-
</h2>
84-
<Input
85-
type="text"
86-
onChange={setTitle}
87-
label="대시보드 이름"
88-
labelClassName="text-black3 text-[16px] sm:text-[18px] font-medium mt-6"
89-
placeholder="뉴프로젝트"
90-
className="max-w-[620px] mb-1"
91-
/>
90+
<div className="min-h-[312px] lg:w-[620px] sm:w-[544px] w-[284px] bg-white rounded-[12px] p-[24px] flex flex-col">
91+
<div className="w-full flex justify-center">
92+
{/* 내부 아이템 컨테이너 */}
93+
<div className="flex flex-col lg:w-[564px] md:w-[488px] w-[252px]">
94+
{/* 헤더 */}
95+
<h2 className="text-left text-black3 font-bold sm:text-[24px] text-[20px]">
96+
{dashboardDetail.title}
97+
</h2>
9298

93-
<div className="flex mt-3">
94-
{colors.map((color, index) => (
95-
<div key={index} className="relative">
96-
<button
97-
className="cursor-pointer w-[30px] h-[30px] rounded-[15px] mr-2 transition-all duration-200
98-
hover:opacity-70 hover:scale-110"
99-
style={{ backgroundColor: color }}
100-
onClick={() => setSelected(index)} // 색상 선택 시 selected 업데이트
99+
{/* 변경할 제목 입력창 */}
100+
<div className="relative w-full mt-6">
101+
<Input
102+
type="text"
103+
onChange={handleTitleChange}
104+
value={title}
105+
label="대시보드 이름"
106+
labelClassName="text-left text-black3 font-medium sm:text-[18px] text-[16px] mb-1"
107+
placeholder="변경할 이름을 입력해 주세요"
108+
className="max-w-none mb-1 pr-[52px] placeholder:text-[14px] placeholder:sm:text-[16px]"
101109
/>
102-
{selected === index && (
103-
<Image
104-
src="/svgs/check.svg"
105-
alt="선택됨"
106-
width={23}
107-
height={23}
108-
className="cursor-pointer absolute top-4 left-3.5 transform -translate-x-1/2 -translate-y-1/2"
109-
/>
110-
)}
110+
<span className="absolute right-3 bottom-1 top-4/6 -translate-y-2/6 font-light text-[12px] sm:text-[14px] text-[var(--color-gray1)] sm:pr-1.5">
111+
{titleLength} / {maxTitleLength}
112+
</span>
111113
</div>
112-
))}
113-
</div>
114-
<div className="mt-8 flex">
115-
<button
116-
onClick={handleUpdate}
117-
disabled={selected === null} // color가 없으면 버튼 비활성화
118-
className={`cursor-pointer sm:w-[572px] sm:h-[54px] w-[252px] h-[54px] rounded-[8px] border border-[var(--color-gray3)] bg-[var(--primary)] text-[var(--color-white)] ${selected === null ? "bg-gray-300 cursor-not-allowed" : "bg-[var(--primary)]"}`}
119-
>
120-
변경
121-
</button>
114+
115+
{/* 컬러칩 선택 */}
116+
<div className="flex mt-3">
117+
{colors.map((color, index) => (
118+
<div key={index} className="relative">
119+
<button
120+
className="cursor-pointer w-[30px] h-[30px] rounded-[15px] mr-2 transition-all duration-200
121+
hover:opacity-70 hover:scale-110"
122+
style={{ backgroundColor: color }}
123+
onClick={() => setSelected(index)} // 색상 선택 시 selected 업데이트
124+
/>
125+
{selected === index && (
126+
<Image
127+
src="/svgs/check.svg"
128+
alt="선택됨"
129+
width={23}
130+
height={23}
131+
className="cursor-pointer absolute top-4 left-3.5 transform -translate-x-1/2 -translate-y-1/2"
132+
/>
133+
)}
134+
</div>
135+
))}
136+
</div>
137+
138+
{/* 변경 버튼 */}
139+
<div className="flex mt-6">
140+
<button
141+
onClick={handleSubmit}
142+
disabled={selected === null} // color가 없으면 버튼 비활성화
143+
className={`cursor-pointer w-full sm:h-[54px] h-[54px]
144+
rounded-[8px] border border-[var(--color-gray3)] bg-[var(--primary)]
145+
text-[var(--color-white)] font-semibold text-[14px] sm:text-[16px]
146+
${selected === null ? "bg-gray-300 cursor-not-allowed" : "bg-[var(--primary)]"}`}
147+
>
148+
변경
149+
</button>
150+
</div>
151+
</div>
122152
</div>
123153
</div>
124154
);

src/components/modal/InviteDashboard.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import { AxiosError } from "axios";
88
import { toast } from "react-toastify";
99
import "react-toastify/dist/ReactToastify.css";
1010

11-
export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
11+
export default function InviteDashboard({
12+
onClose,
13+
onUpdate,
14+
}: {
15+
onClose?: () => void;
16+
onUpdate?: () => void;
17+
}) {
1218
const [email, setEmail] = useState("");
1319
const router = useRouter();
1420
const { dashboardId } = router.query;
@@ -32,6 +38,9 @@ export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
3238
},
3339
}
3440
);
41+
42+
if (onUpdate) onUpdate();
43+
3544
if (res.data && Array.isArray(res.data.invitations)) {
3645
// 초대내역 리스트
3746
const inviteData = res.data.invitations.map(
@@ -67,6 +76,7 @@ export default function InviteDashboard({ onClose }: { onClose?: () => void }) {
6776
});
6877

6978
toast.success("멤버 초대에 성공했습니다.");
79+
onUpdate?.();
7080
onClose?.();
7181
} catch (error) {
7282
if (error instanceof AxiosError) {

src/components/modal/NewDashboard.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,19 @@ export default function NewDashboard({ onClose, onCreate }: NewDashboardProps) {
2424
const [title, setTitle] = useState("");
2525
const [selected, setSelected] = useState<number | null>(null);
2626
const [loading, setLoading] = useState(false);
27+
const [titleLength, setTitleLength] = useState<number>(0);
2728

29+
const maxTitleLength = 30;
2830
const colors = ["#7ac555", "#760DDE", "#FF9800", "#76A5EA", "#E876EA"];
2931

32+
/* 대시보드 이름 글자수 제한 */
33+
const handleTitleChange = async (value: string) => {
34+
if (value.length <= maxTitleLength) {
35+
setTitle(value);
36+
setTitleLength(value.length);
37+
}
38+
};
39+
3040
const handleSubmit = async () => {
3141
const payload = {
3242
title,
@@ -38,6 +48,7 @@ export default function NewDashboard({ onClose, onCreate }: NewDashboardProps) {
3848
const response = await createDashboard(payload);
3949
onCreate?.(response.data);
4050
onClose?.();
51+
toast.success("대시보드가 생성되었습니다.");
4152
} catch (error) {
4253
console.error("대시보드 생성 실패:", error);
4354
toast.error("대시보드 생성에 실패했습니다.");
@@ -50,14 +61,20 @@ export default function NewDashboard({ onClose, onCreate }: NewDashboardProps) {
5061
<div className="fixed inset-0 flex items-center justify-center bg-black/35 z-50">
5162
<div className="bg-white p-6 rounded-lg shadow-lg w-[327px] sm:w-[584px] sm:h-[344px]">
5263
<h2 className="text-sm sm:text-[24px] font-bold">새로운 대시보드</h2>
53-
<Input
54-
type="text"
55-
onChange={setTitle}
56-
label="대시보드 이름"
57-
labelClassName="text-lg sm:text-base text-black3 mt-6"
58-
placeholder="뉴프로젝트"
59-
className="max-w-[620px] mb-1"
60-
/>
64+
<div className="relative w-full">
65+
<Input
66+
type="text"
67+
value={title}
68+
onChange={handleTitleChange}
69+
label="대시보드 이름"
70+
labelClassName="text-lg sm:text-base text-black3 mt-6"
71+
placeholder="뉴 프로젝트"
72+
className="max-w-[620px] mb-1 sm:pr-0 pr-14"
73+
/>
74+
<span className="absolute right-3 top-4/6 -translate-y-1/5 font-light text-[12px] sm:text-[14px] text-[var(--color-gray1)] sm:pr-1.5">
75+
{titleLength} / {maxTitleLength}
76+
</span>
77+
</div>
6178

6279
<div className="mt-3 flex relative">
6380
{colors.map((color, index) => (

src/components/modalInput/ModalInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function ModalInput({
3636
defaultValue ? new Date(defaultValue) : null
3737
);
3838
const [titleLength, setTitleLength] = useState<number>(0);
39-
const maxTitleLength = 70;
39+
const maxTitleLength = 50;
4040

4141
useEffect(() => {
4242
if (label === "태그" && defaultValueArray.length > 0) {

0 commit comments

Comments
 (0)