From d1a71ae1a0d764caba213e21b7dd91b726590324 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:21:34 +0900 Subject: [PATCH 01/41] =?UTF-8?q?=F0=9F=AB=A7modify:=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98=20=EC=9D=BC=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/edit/DeleteDashboardButton.tsx | 6 +- .../dashboard/components/edit/EditInfo.tsx | 15 +- .../components/edit/EditInvitation.tsx | 8 +- .../dashboard/components/edit/EditMember.tsx | 146 ++++++++---------- .../components/common/header/UserDropdown.tsx | 4 +- .../common/modal/CreateInvitationModal.tsx | 4 +- 6 files changed, 77 insertions(+), 106 deletions(-) diff --git a/src/app/features/dashboard/components/edit/DeleteDashboardButton.tsx b/src/app/features/dashboard/components/edit/DeleteDashboardButton.tsx index c190631..fee63aa 100644 --- a/src/app/features/dashboard/components/edit/DeleteDashboardButton.tsx +++ b/src/app/features/dashboard/components/edit/DeleteDashboardButton.tsx @@ -15,9 +15,7 @@ export default function DeleteDashboardButton({ const router = useRouter() const [isDeleting, setIsDeleting] = useState(false) - console.log('DeleteDashboardButton 렌더됨:', dashboardId) - - const handleDelete = async () => { + async function handleDelete() { const confirmed = confirm( '정말로 이 대시보드를 삭제하시겠습니까? 삭제 후 되돌릴 수 없습니다.', ) @@ -43,7 +41,7 @@ export default function DeleteDashboardButton({ error.response?.data?.message || '대시보드 삭제 중 오류가 발생했습니다.' console.error('대시보드 삭제 오류:', message) - alert(message) // 또는 showError(message) 등으로 사용자에게 표시 + alert(message) } else { console.error('대시보드 삭제 오류:', error) alert('알 수 없는 오류가 발생했습니다.') diff --git a/src/app/features/dashboard/components/edit/EditInfo.tsx b/src/app/features/dashboard/components/edit/EditInfo.tsx index 4b6b5c3..0f61c63 100644 --- a/src/app/features/dashboard/components/edit/EditInfo.tsx +++ b/src/app/features/dashboard/components/edit/EditInfo.tsx @@ -34,7 +34,7 @@ export default function EditInfo() { }, [selectedDashboard]) // 입력값 변경 핸들러 - const handleChange = (e: React.ChangeEvent) => { + function handleChange(e: React.ChangeEvent) { const { name, value } = e.target setFormData((prev) => ({ ...prev, @@ -43,12 +43,12 @@ export default function EditInfo() { } // 색상 선택 핸들러 - const handleColorSelect = (color: string) => { + function handleColorSelect(color: string) { setFormData((prev) => ({ ...prev, color })) } // 제출 핸들러 - const handleSubmit = async (e: React.FormEvent) => { + async function handleSubmit(e: React.FormEvent) { e.preventDefault() if (!formData.title || !formData.color) return @@ -67,13 +67,9 @@ export default function EditInfo() { const data = response.data - // 1. 상태 업데이트 (헤더, 수정정보 실시간 반영) setSelectedDashboard(data) - - // 2. react-query 캐시 무효화 → Sidebar 목록 재요청 유도 await queryClient.invalidateQueries({ queryKey: ['dashboards'] }) - // 성공 시 상세 페이지 이동 router.push(`/dashboard/${data.id}/edit`) } catch (error: unknown) { if (axios.isAxiosError(error)) { @@ -93,14 +89,12 @@ export default function EditInfo() { return (
- {/* 컨테이너 */}

{selectedDashboard?.title || '대시보드 편집'}

- {/* 제목 입력 */}
- {/* 색상 선택 */}
{DASHBOARD_COLORS.map((color) => ( @@ -129,7 +122,6 @@ export default function EditInfo() { style={{ backgroundColor: color }} aria-label={`색상 ${color}`} > - {/* 선택된 색상에 체크 표시 */} {formData.color === color && (
- {/* 하단 버튼 */}
- + +
+ + setEmail(e.target.value)} + placeholder="초대 이메일을 입력해주세요." + className="Border-section w-full rounded-8 px-12 py-10 text-16 outline-none" + required + />
-
- - -
- {paginationMembers.map((member, index) => { - // 해당 페이지 중 마지막 요소인 경우 border-bottom 미적용 - const isLast = index === paginationMembers.length - 1 - return ( -
- - -
- ) - })} +
+ +
diff --git a/src/app/shared/components/common/header/UserDropdown.tsx b/src/app/shared/components/common/header/UserDropdown.tsx index 434da2e..cb3d527 100644 --- a/src/app/shared/components/common/header/UserDropdown.tsx +++ b/src/app/shared/components/common/header/UserDropdown.tsx @@ -11,11 +11,11 @@ export default function UserDropdown() { const router = useRouter() const { logout } = useAuth() - const goToMypage = () => { + function goToMypage() { router.push('/mypage') } - const handleLogout = () => { + function handleLogout() { logout() router.push('/') } diff --git a/src/app/shared/components/common/modal/CreateInvitationModal.tsx b/src/app/shared/components/common/modal/CreateInvitationModal.tsx index c4dbc0c..bcf60fe 100644 --- a/src/app/shared/components/common/modal/CreateInvitationModal.tsx +++ b/src/app/shared/components/common/modal/CreateInvitationModal.tsx @@ -13,13 +13,13 @@ export default function CreateInvitationModal() { const [email, setEmail] = useState('') const { id: dashboardId } = useParams() - const handleBackdropClick = (e: React.MouseEvent) => { + function handleBackdropClick(e: React.MouseEvent) { if (e.target === e.currentTarget) { closeModal() } } - const handleSubmit = async (e: React.FormEvent) => { + async function handleSubmit(e: React.FormEvent) { e.preventDefault() if (!email) return From 191b9e1fc8739db84f75f772d1f4476ab340e1c9 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:22:39 +0900 Subject: [PATCH 02/41] =?UTF-8?q?=F0=9F=AB=A7modify:=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=20=EB=84=98=EB=B2=84=EB=AA=85=20=EA=B5=AC=EC=B2=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/header/Collaborator/CollaboratorList.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx b/src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx index 1543cf6..5d6d088 100644 --- a/src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx +++ b/src/app/shared/components/common/header/Collaborator/CollaboratorList.tsx @@ -25,9 +25,9 @@ type CollaboratorListProps = { export default function CollaboratorList({ collaborators = mockCollaborators, // 전달된 협업자가 없을 경우 mock 데이터 사용 }: CollaboratorListProps) { - const MAX_VISIBLE = 4 // 최대 표시 협업자 수 - const visibleCollaborators = collaborators.slice(0, MAX_VISIBLE) // 앞에서부터 4명만 추출 - const extraCount = collaborators.length - MAX_VISIBLE // 초과 인원 계산 + const MAX_COLLABS = 4 // 최대 표시 협업자 수 + const visibleCollaborators = collaborators.slice(0, MAX_COLLABS) // 앞에서부터 4명만 추출 + const extraCount = collaborators.length - MAX_COLLABS // 초과 인원 계산 return (
From 1dba3aac816c045b596a207044d0f10e68217881 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:24:04 +0900 Subject: [PATCH 03/41] =?UTF-8?q?=F0=9F=AB=A7modify:=20=EB=AF=B8=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/dashboard/[id]/edit/page.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/app/dashboard/[id]/edit/page.tsx b/src/app/dashboard/[id]/edit/page.tsx index 43864a9..b25daff 100644 --- a/src/app/dashboard/[id]/edit/page.tsx +++ b/src/app/dashboard/[id]/edit/page.tsx @@ -3,7 +3,6 @@ import EditInfo from '@dashboard/components/edit/EditInfo' import EditInvitation from '@dashboard/components/edit/EditInvitation' import EditMember from '@dashboard/components/edit/EditMember' -import { showError, showSuccess } from '@lib/toast' import Image from 'next/image' import { useParams } from 'next/navigation' import { useRouter } from 'next/navigation' @@ -14,14 +13,6 @@ export default function DashBoardEditPage() { const { id } = useParams() const router = useRouter() - const handleSuccess = () => { - showSuccess('대시보드가 성공적으로 수정되었습니다.') - } - - const handleError = () => { - showError('수정 중 오류가 발생했습니다.') - } - return (
- ))} -
-
- -
- -
- +
) diff --git a/src/app/shared/components/common/modal/CreateDashboardModal.tsx b/src/app/shared/components/common/modal/CreateDashboardModal.tsx index e80c28a..f257a06 100644 --- a/src/app/shared/components/common/modal/CreateDashboardModal.tsx +++ b/src/app/shared/components/common/modal/CreateDashboardModal.tsx @@ -3,12 +3,13 @@ import { DASHBOARD_COLORS } from '@constants/colors' import authHttpClient from '@lib/axios' import { useModalStore } from '@store/useModalStore' -import Image from 'next/image' import { useRouter } from 'next/navigation' import React, { useEffect, useState } from 'react' import { CreateDashboardRequest } from '@/types/dashboard' +import DashboardForm from '../../dashboard/DashboardForm' + export default function CreateDashboardModal() { const router = useRouter() const { modalType, closeModal } = useModalStore() @@ -92,75 +93,16 @@ export default function CreateDashboardModal() { {/* 모달 컨테이너 */}

새로운 대시보드

- -
- {/* 제목 입력 */} -
- - -
- - {/* 색상 선택 */} -
-
- {DASHBOARD_COLORS.map((color) => ( - - ))} -
-
- - {/* 하단 버튼 */} -
- - -
-
+
) diff --git a/src/app/shared/components/dashboard/DashboardForm.tsx b/src/app/shared/components/dashboard/DashboardForm.tsx new file mode 100644 index 0000000..56c138c --- /dev/null +++ b/src/app/shared/components/dashboard/DashboardForm.tsx @@ -0,0 +1,105 @@ +'use client' + +import Image from 'next/image' +import React from 'react' + +import { DASHBOARD_COLORS } from '@/app/shared/constants/colors' + +type DashboardFormProps = { + formData: { title: string; color: string } + onChange: (e: React.ChangeEvent) => void + onColorSelect: (color: string) => void + onSubmit: (e: React.FormEvent) => void + isSubmitting: boolean + submitText: string + submitButtonWidth?: string + showCancelButton?: boolean + onCancel?: () => void +} + +export default function DashboardForm({ + formData, + onChange, + onColorSelect, + onSubmit, + isSubmitting, + submitText, + submitButtonWidth = 'w-256', + showCancelButton = false, + onCancel, +}: DashboardFormProps) { + return ( +
+ {/* 제목 */} +
+ + +
+ + {/* 색상 */} +
+
+ {DASHBOARD_COLORS.map((color) => ( + + ))} +
+
+ + {/* 버튼 */} +
+ {showCancelButton && ( + + )} + +
+
+ ) +} From 72cad000d6dfc5115d253487ad0fe7a2463ea8f6 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:40:43 +0900 Subject: [PATCH 05/41] =?UTF-8?q?=F0=9F=8E=A8style:=20=EB=8F=99=EC=9D=BC?= =?UTF-8?q?=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/images/management.png | Bin 844 -> 0 bytes .../components/common/header/RightHeaderNav.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 public/images/management.png diff --git a/public/images/management.png b/public/images/management.png deleted file mode 100644 index 19907286762cf70c79ac7bf2e1090fc6eee43981..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 844 zcmV-S1GD^zP)Vl&|00001b5ch_0Itp) z=>Px&21!IgR9FeMSL<=xFbviR*`OXF8#E(igJuKkLec`=AJ$z=vj3b7G(twu2pPd6 zWQ6p6Xoy3xs)1n>k_dM0~EHx0v24 zv*sSs!agQFAl)TAeI^WvsvG<9?qrSq95(iFN#{nqJeDMMGiP`WgL)Ws z`aRwq}(VoT-loO0^En$k2^B6i)? z%0Y$lSaS4fV`R=k@hD}IsNXqHNQlckHUo_$tU7eVIYwe`&nNl9 z0kh*S$1#tjP{3XuiVTOKgWO+CGCuErXlW10aDS~d6l(WX1NoOZ>S2$A zNj_PGsgr`^l@ukAE}r=g35hi%McIy5RAeD6tuU^z4KA7s>~1Jg8j3@qA`L`rNU(#+ zcsz&b=Y5|}-+ZHC4I@IEWe?P?6o<}N`9aGa3L@)$E5th#ZaFd<|40z_`((u$l7v}x z8n(dEfVrqT2+n{wKvIkbb6Fh6%sE4=sBl0&2IX>}M_cEjZ@;y5=F0fkx4_Z0v<0T~ z{L~!d=5b(hPOG!;Rs$b$YfU|Jv!a$DWo^1=`fka6%e?Q~u?h5HhoN_R24&Vul>7yt W9}It0Kq=t>0000 From d7573fff0663b98891302cd935c0f15b6334888b Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:04:42 +0900 Subject: [PATCH 06/41] =?UTF-8?q?=F0=9F=AB=A7modify:=20=EC=9D=B4=EC=A0=84?= =?UTF-8?q?=20=EB=A9=A4=EB=B2=84=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/components/edit/EditMember.tsx | 146 ++++++++++-------- 1 file changed, 81 insertions(+), 65 deletions(-) diff --git a/src/app/features/dashboard/components/edit/EditMember.tsx b/src/app/features/dashboard/components/edit/EditMember.tsx index a6bddef..b0d72f7 100644 --- a/src/app/features/dashboard/components/edit/EditMember.tsx +++ b/src/app/features/dashboard/components/edit/EditMember.tsx @@ -1,83 +1,99 @@ -'use client' - -import { inviteUser } from '@dashboard/api/invitation' -import { useModalStore } from '@store/useModalStore' -import { AxiosError } from 'axios' -import { useParams } from 'next/navigation' +import Image from 'next/image' +import React from 'react' import { useState } from 'react' -import { showError, showSuccess } from '@/app/shared/lib/toast' +import { UserInfo } from '@/app/shared/components/common/UserInfo' -export default function CreateInvitationModal() { - const { modalType, closeModal } = useModalStore() - const [email, setEmail] = useState('') - const { id: dashboardId } = useParams() +import { mockMembers } from './mockMember' - function handleBackdropClick(e: React.MouseEvent) { - if (e.target === e.currentTarget) { - closeModal() - } - } +const PAGE_SIZE = 4 // 페이지당 표시할 구성원 수 - async function handleSubmit(e: React.FormEvent) { - e.preventDefault() - if (!email) return +export default function EditMember() { + const [currentPage, setCurrentPage] = useState(1) + const totalPages = Math.ceil(mockMembers.length / PAGE_SIZE) - try { - if (!dashboardId) { - throw new Error('대시보드 ID가 없습니다.') - } - await inviteUser({ email, dashboardId: Number(dashboardId) }) - showSuccess('초대가 완료되었습니다.') - closeModal() - } catch (err: unknown) { - const error = err as AxiosError<{ message: string }> - showError(error?.response?.data?.message || '초대에 실패하였습니다.') + const startIndex = (currentPage - 1) * PAGE_SIZE + const paginationMembers = mockMembers.slice( + startIndex, + startIndex + PAGE_SIZE, + ) + + function handlePrev() { + if (currentPage > 1) { + setCurrentPage((prev) => prev - 1) } } - if (!modalType) return null + function handleNext() { + if (currentPage < totalPages) { + setCurrentPage((prev) => prev + 1) + } + } return ( -
-
-

초대하기

- -
-
- - setEmail(e.target.value)} - placeholder="초대 이메일을 입력해주세요." - className="Border-section w-full rounded-8 px-12 py-10 text-16 outline-none" - required - /> -
+
+ {/* 컨테이너 */} +
+
+

구성원

-
- -
+
+ + + +
+ {paginationMembers.map((member, index) => { + // 해당 페이지 중 마지막 요소인 경우 border-bottom 미적용 + const isLast = index === paginationMembers.length - 1 + return ( +
+ + +
+ ) + })} +
From ed4b3a4fafeff1482a4848d75d85ddd1bfb6a154 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:05:26 +0900 Subject: [PATCH 07/41] =?UTF-8?q?=F0=9F=AB=A7modify:=20pathname=20?= =?UTF-8?q?=EB=AF=B8=EC=82=AC=EC=9A=A9=20=EB=B0=8F=20cn=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/components/edit/EditInvitation.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/app/features/dashboard/components/edit/EditInvitation.tsx b/src/app/features/dashboard/components/edit/EditInvitation.tsx index b127978..64d85f7 100644 --- a/src/app/features/dashboard/components/edit/EditInvitation.tsx +++ b/src/app/features/dashboard/components/edit/EditInvitation.tsx @@ -1,7 +1,6 @@ import { UserInfo } from '@components/common/UserInfo' import { cn } from '@lib/cn' import Image from 'next/image' -import { usePathname } from 'next/navigation' import React from 'react' import { useModalStore } from '@/app/shared/store/useModalStore' @@ -11,7 +10,6 @@ import { mockMembers } from './mockMember' const PAGE_SIZE = 5 export default function EditInvitation() { - const pathname = usePathname() const { openModal } = useModalStore() const [currentPage, setCurrentPage] = React.useState(1) const totalPages = Math.ceil(mockMembers.length / PAGE_SIZE) @@ -69,10 +67,7 @@ export default function EditInvitation() { + + {children &&
{children}
} +
+
+ ) +} From cda1787b79e9aadde2e95bedb2e4710a9134e171 Mon Sep 17 00:00:00 2001 From: yujin Jeon <101913688+yuj2n@users.noreply.github.com> Date: Fri, 20 Jun 2025 21:39:19 +0900 Subject: [PATCH 11/41] =?UTF-8?q?=E2=9C=A8feat:=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20=ED=9B=85=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/edit/EditInvitation.tsx | 98 ++++++------------- .../dashboard/components/edit/EditMember.tsx | 85 +++++----------- 2 files changed, 55 insertions(+), 128 deletions(-) diff --git a/src/app/features/dashboard/components/edit/EditInvitation.tsx b/src/app/features/dashboard/components/edit/EditInvitation.tsx index 64d85f7..baa586d 100644 --- a/src/app/features/dashboard/components/edit/EditInvitation.tsx +++ b/src/app/features/dashboard/components/edit/EditInvitation.tsx @@ -1,85 +1,49 @@ -import { UserInfo } from '@components/common/UserInfo' +'use client' + import { cn } from '@lib/cn' import Image from 'next/image' import React from 'react' +import { UserInfo } from '@/app/shared/components/common/UserInfo' +import { usePagination } from '@/app/shared/hooks/usePagination' import { useModalStore } from '@/app/shared/store/useModalStore' import { mockMembers } from './mockMember' +import { PaginationHeader } from './PaginationHeader' -const PAGE_SIZE = 5 +const INVITATION_SIZE = 5 // 페이지 당 표시 초대 내역 export default function EditInvitation() { const { openModal } = useModalStore() - const [currentPage, setCurrentPage] = React.useState(1) - const totalPages = Math.ceil(mockMembers.length / PAGE_SIZE) - const startIndex = (currentPage - 1) * PAGE_SIZE - const paginationMembers = mockMembers.slice( - startIndex, - startIndex + PAGE_SIZE, - ) - - function handlePrev() { - if (currentPage > 1) { - setCurrentPage((prev) => prev - 1) - } - } - function handleNext() { - if (currentPage < totalPages) { - setCurrentPage((prev) => prev + 1) - } - } + const { + currentPage, + totalPages, + currentItems: paginationMembers, + handlePrev, + handleNext, + } = usePagination(mockMembers, INVITATION_SIZE) return (
-
-

초대 내역

- -
-

- {totalPages} 페이지 중 {currentPage} -

- - - -
-
+ + +