Skip to content
8 changes: 5 additions & 3 deletions src/app/dashboard/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ export default function DashBoardEditPage() {
<Image src="/images/back.png" alt="돌아가기" width={6} height={4} />
<p className="text-14">돌아가기</p>
</button>
<div className="flex w-500 flex-col gap-16 p-16">

{/* 컨텐츠 박스: 기본 너비 500px, 화면 작으면 100% 최대 500px */}
<div className="mx-auto ml-16 flex flex-col gap-16 p-16 sm:max-w-full sm:px-4">
<EditInfo />
<EditMember />
<EditInvitation />
</div>

{/* 삭제 버튼 영역 */}
<div className="BG-white align-center Text-btn i8 ml-16 flex w-292 justify-center rounded-md px-64 py-6">
{/* 삭제 버튼 영역: 기본 너비 292px, 화면 작으면 100% 최대 292px, 좌측 margin 제거 */}
<div className="BG-white align-center Text-btn i8 ml-16 mt-8 flex max-w-292 justify-center rounded-md px-16 py-6">
<DeleteDashboardButton dashboardId={String(id)} />
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/app/features/auth/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export function useAuth() {
return {
updateAuthState,
logout,
setUser,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default function DeleteDashboardButton({
onClick={handleDelete}
// isLoading -> isPending으로 수정됨
disabled={mutation.isPending}
className={`Text-black my-8 rounded-8 font-semibold transition-opacity ${
className={`Text-black my-8 whitespace-nowrap rounded-8 font-semibold transition-opacity ${
mutation.isPending
? 'cursor-not-allowed opacity-50'
: 'hover:opacity-90'
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/dashboard/components/edit/EditInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function EditInfo() {

return (
<div>
<div className="BG-white h-300 w-584 rounded-16 px-32 py-24">
<div className="BG-white max-w-584 rounded-16 px-32 py-24">
<h2 className="Text-black mb-24 text-18 font-bold">
{selectedDashboard?.title || '대시보드 편집'}
</h2>
Expand Down
142 changes: 67 additions & 75 deletions src/app/features/dashboard/components/edit/EditInvitation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,85 +97,77 @@ export default function EditInvitation() {
: null

return (
<div>
<div className="BG-white max-h-[360px] w-584 overflow-y-auto rounded-16 px-32 py-24">
<PaginationHeader
currentPage={currentPage}
totalPages={totalPages}
title="초대 내역"
onPrev={handlePrev}
onNext={handleNext}
<div className="BG-white w-full max-w-584 overflow-x-auto whitespace-nowrap rounded-16 px-32 py-24">
<PaginationHeader
currentPage={currentPage}
totalPages={totalPages}
title="초대 내역"
onPrev={handlePrev}
onNext={handleNext}
>
<button
onClick={() => openModal('invite')}
className="BG-violet flex w-fit shrink-0 items-center gap-8 rounded-5 px-12 py-6"
>
<button
onClick={() => openModal('invite')}
className="BG-violet flex items-center gap-8 rounded-5 px-12 py-6"
>
<div className="relative flex size-12">
<Image src="/images/invitation-white.png" fill alt="초대 버튼" />
</div>
<p className="text-14 text-white">초대하기</p>
</button>
</PaginationHeader>

<form>
<label htmlFor="title" className="Text-black mb-8 block text-16">
이메일
</label>
<div className="flex flex-col gap-4">
{isLoading && (
<p className="Text-gray py-12 text-center">로딩 중...</p>
)}

{errorMessage && (
<p className="Text-blue py-12 text-center">{errorMessage}</p>
)}

{!isLoading && !errorMessage && currentItems.length === 0 && (
<p className="Text-gray py-12 text-center">
초대된 사용자가 없습니다.
</p>
)}

{!isLoading &&
!errorMessage &&
currentItems.map((member, index) => {
const isLast = index === currentItems.length - 1
return (
<div
key={member.id}
<div className="relative flex size-12 shrink-0">
<Image src="/images/invitation-white.png" fill alt="초대 버튼" />
</div>
<p className="text-14 text-white">초대하기</p>
</button>
</PaginationHeader>

<form className="overflow-x-auto">
<label htmlFor="title" className="Text-black mb-8 block text-16">
이메일
</label>
<div className="flex flex-col gap-4">
{isLoading && (
<p className="Text-gray py-12 text-center">로딩 중...</p>
)}

{errorMessage && (
<p className="Text-blue py-12 text-center">{errorMessage}</p>
)}

{!isLoading &&
!errorMessage &&
currentItems.map((member, index) => {
const isLast = index === currentItems.length - 1
return (
<div
key={member.id}
className={cn(
'flex items-center justify-between gap-12 py-4',
!isLast && 'Border-bottom',
)}
>
<div className="flex min-w-0 items-center gap-12">
<div className="flex min-w-0 flex-col">
<Tooltip content={member.invitee.nickname}>
<p className="Text-black max-w-[200px] cursor-help truncate text-13">
{member.invitee.email}
</p>
</Tooltip>
</div>
</div>

<button
type="button"
disabled={cancelMutation.isPending}
className={cn(
'flex items-center justify-between py-4',
!isLast && 'Border-bottom',
'Text-btn Border-btn w-fit shrink-0 rounded-md px-16 py-2',
cancelMutation.isPending &&
'cursor-not-allowed opacity-50',
)}
onClick={() => cancelMutation.mutate(member.id)}
>
<div className="flex items-center gap-12">
<div className="flex flex-col">
<Tooltip content={member.invitee.nickname}>
<p className="Text-black cursor-help text-13">
{member.invitee.email}
</p>
</Tooltip>
</div>
</div>

<button
type="button"
disabled={cancelMutation.isPending}
className={cn(
'Text-btn Border-btn rounded-md px-16 py-2',
cancelMutation.isPending &&
'cursor-not-allowed opacity-50',
)}
onClick={() => cancelMutation.mutate(member.id)}
>
{cancelMutation.isPending ? '취소 중...' : '취소'}
</button>
</div>
)
})}
</div>
</form>
</div>
{cancelMutation.isPending ? '취소 중...' : '취소'}
</button>
</div>
)
})}
</div>
</form>
</div>
)
}
2 changes: 1 addition & 1 deletion src/app/features/dashboard/components/edit/EditMember.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default function EditMember() {

return (
<div>
<div className="BG-white h-360 w-584 rounded-16 px-32 py-24">
<div className="BG-white max-w-584 rounded-16 px-32 py-24">
<PaginationHeader
currentPage={currentPage}
totalPages={totalPages}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export function PaginationHeader({
children,
}: PaginationHeaderProps) {
return (
<div className="mb-24 flex items-center justify-between">
<div className="mb-24 flex items-center justify-between whitespace-nowrap">
<h2 className="Text-black text-18 font-bold">{title}</h2>

<div className="flex items-center">
<p className="Text-gray mr-16 text-12">
<div className="flex shrink-0 items-center">
<p className="Text-gray mr-16 shrink-0 text-12">
{totalPages} 페이지 중 {currentPage}
</p>
<button onClick={onPrev} disabled={currentPage === 1}>
Expand Down
19 changes: 17 additions & 2 deletions src/app/features/mypage/components/ProfileEditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useRouter } from 'next/navigation'
import { useEffect, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'

import { useAuthStore } from '@/app/features/auth/store/useAuthStore'

import { useUpdateMyProfileMutation } from '../hook/useUpdateMyProfileMutation'
import { useUploadProfileImageMutation } from '../hook/useUploadProfileImageMutation'
import { useUserQuery } from '../hook/useUserQurey'
Expand Down Expand Up @@ -41,6 +43,9 @@ export default function ProfileEditForm() {
const { mutateAsync: uploadImage } = useUploadProfileImageMutation()
const { mutateAsync: updateProfile } = useUpdateMyProfileMutation()

// Zustand 상태 갱신 함수 가져오기
const setUser = useAuthStore((state) => state.setUser)

// 유저 정보가 비동기적으로 넘어오기 때문에 유저가 로딩된 시점에서 RHF을 초기화 하기 위함 (SSR 도입 시 변경 예정)
useEffect(() => {
if (user) {
Expand Down Expand Up @@ -69,8 +74,18 @@ export default function ProfileEditForm() {
profileImageUrl: imageUrl,
}

// 서버에 프로필 정보 수정 요청 (PUT)
await updateProfile(submitData)
// 서버에 프로필 수정 요청
const updatedUser = await updateProfile(submitData)

if (!user) return // user가 없으면 갱신하지 않음

// zustand 상태 갱신 (전역 사용자 정보 업데이트)
setUser({
...user,
nickname: updatedUser.nickname ?? data.nickname,
profileImageUrl: updatedUser.profileImageUrl ?? imageUrl,
// 필요 시 추가 필드도 넣기
})

// 사용자에게 성공 알림 + 컴포넌트 최신화
showSuccess('프로필 변경이 완료되었습니다.')
Expand Down
5 changes: 4 additions & 1 deletion src/app/mypage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ export default function Mypage() {
const router = useRouter()
return (
<>
<Header />
<div className="pl-300">
<Header />
</div>

<div className="BG-gray h-full">
{/* 사이드바 */}
<Sidebar />
Expand Down
4 changes: 3 additions & 1 deletion src/app/shared/components/common/UserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export function UserInfo({ nickname, imageUrl, size = 36 }: UserInfoProps) {
<div className="flex items-center gap-4">
{/* Avatar에 nickname, profileImageUrl 모두 넘겨줌 */}
<Avatar size={size} name={displayNickname} imageUrl={displayImage} />
<span className="ml-4 text-sm font-semibold">{displayNickname}</span>
<span className="ml-4 text-sm font-semibold tablet:hidden">
{displayNickname}
</span>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function CollaboratorList() {
const extraCount = members.length - MAX_COLLABS

return (
<div className="flex gap-4">
<div className="flex -space-x-10">
{visibleCollaborators.map((collab) => (
<Tooltip key={collab.id} content={collab.nickname}>
<div className="flex flex-col items-center text-xs">
Expand Down
8 changes: 5 additions & 3 deletions src/app/shared/components/common/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import UserDropdown from './UserDropdown'

export default function Header() {
return (
<header className="BG-white Border-bottom Text-black w-full overflow-x-hidden border-b px-48 py-10">
<header className="BG-white Border-bottom Text-black w-full overflow-x-auto border-b px-48 py-10">
<div className="flex w-full items-center justify-between pr-16">
{/* 좌측 대시보드명 */}
<LeftHeaderContent />
<div className="hidden lg:block">
<LeftHeaderContent />
</div>

{/* 우측 사용자 정보/다크모드 */}
<div className="flex gap-16">
<div className="flex gap-16 whitespace-nowrap">
<RightHeaderNav />
<CreateInvitationModal />
{/* 협업자 목록 */}
Expand Down
9 changes: 7 additions & 2 deletions src/app/shared/components/common/header/LeftHeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
'use client'
import Image from 'next/image'
import { usePathname } from 'next/navigation'

import { useSelectedDashboardStore } from '@/app/shared/store/useSelectedDashboardStore'

export default function LeftHeaderContent() {
const { selectedDashboard } = useSelectedDashboardStore()
const pathname = usePathname()

if (!selectedDashboard) return null

return (
<div className="flex shrink-0 items-center gap-8 pr-16">
<div className="whitespace-nowrap font-bold">
{selectedDashboard.title || '내 대시보드'}
{pathname === '/mypage'
? '계정관리'
: selectedDashboard.title || '내 대시보드'}
</div>
{selectedDashboard.createdByMe && (

{selectedDashboard.createdByMe && pathname !== '/mypage' && (
<div className="relative h-12 w-14 overflow-hidden">
<Image
src="/images/crown.png"
Expand Down
Loading