diff --git a/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.module.css b/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.module.css
index b13f7cb..62b370d 100644
--- a/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.module.css
+++ b/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.module.css
@@ -8,6 +8,13 @@
.cardWrapper {
position: relative;
+ transition: opacity 0.15s;
+}
+
+/* 서버 요청 진행 중: 카드를 흐리게 표시하고 추가 인터랙션 차단 */
+.cardPending {
+ opacity: 0.5;
+ pointer-events: none;
}
/* 드래그 중인 아이템: TodoCard와 동일한 border-radius(12px)로 테두리 플레이스홀더 표시 */
diff --git a/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.tsx b/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.tsx
index 01a9809..c320184 100644
--- a/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.tsx
+++ b/src/app/(root)/[teamid]/_domain/components/Kanban/KanbanItem.tsx
@@ -105,7 +105,7 @@ function KanbanItem({
>
{isEditing ? (
diff --git a/src/app/(root)/[teamid]/_domain/components/Team/SidebarWrapper.tsx b/src/app/(root)/[teamid]/_domain/components/Team/SidebarWrapper.tsx
deleted file mode 100644
index 0156e21..0000000
--- a/src/app/(root)/[teamid]/_domain/components/Team/SidebarWrapper.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { Sidebar } from '@/components/sidebar';
-import ProfileImage from '@/components/profile-img/ProfileImage';
-import { useCurrentUserQuery } from '@/shared/queries/user/useCurrentUserQuery';
-import TeamSidebarDropdown from './TeamSidebarDropdown';
-
-export default function SidebarWrapper() {
- const { data: currentUser } = useCurrentUserQuery();
- const router = useRouter();
-
- return (
-
}
- isLoggedIn={!!currentUser}
- profileImage={
-
- }
- profileName={currentUser?.nickname}
- profileTeam={currentUser?.email}
- onProfileClick={() => router.push('/mypage')}
- />
- );
-}
diff --git a/src/app/(root)/[teamid]/_domain/components/Team/TeamNavClient.tsx b/src/app/(root)/[teamid]/_domain/components/Team/TeamNavClient.tsx
deleted file mode 100644
index 96cf5eb..0000000
--- a/src/app/(root)/[teamid]/_domain/components/Team/TeamNavClient.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-'use client';
-
-import { useState } from 'react';
-import { useRouter } from 'next/navigation';
-
-import { MobileHeader, MobileDrawer } from '@/components/sidebar';
-import ProfileImage from '@/components/profile-img/ProfileImage';
-import { useCurrentUserQuery } from '@/shared/queries/user/useCurrentUserQuery';
-import TeamTabletHeader from './TeamTabletHeader';
-import TeamSidebarDropdown from './TeamSidebarDropdown';
-import styles from './TeamNavClient.module.css';
-
-export default function TeamNavClient() {
- const [isDrawerOpen, setIsDrawerOpen] = useState(false);
- const { data: currentUser } = useCurrentUserQuery();
- const router = useRouter();
-
- const openDrawer = () => setIsDrawerOpen(true);
- const closeDrawer = () => setIsDrawerOpen(false);
- const handleProfileClick = () => router.push('/mypage');
-
- return (
- <>
- {/* 태블릿 헤더 */}
-
-
-
-
- {/* 모바일 헤더 */}
-
-
- }
- onMenuClick={openDrawer}
- onProfileClick={handleProfileClick}
- />
-
-
- {/* 태블릿/모바일 공통 사이드바 드로어 */}
-
-
-
- >
- );
-}
diff --git a/src/app/(root)/[teamid]/_domain/hooks/useKanbanTasks.ts b/src/app/(root)/[teamid]/_domain/hooks/useKanbanTasks.ts
index 6ec06b6..227e88c 100644
--- a/src/app/(root)/[teamid]/_domain/hooks/useKanbanTasks.ts
+++ b/src/app/(root)/[teamid]/_domain/hooks/useKanbanTasks.ts
@@ -131,9 +131,18 @@ export function useKanbanTasks(
}),
);
+ // 2초 이상 응답이 없을 때만 pending 표시 (빠른 응답 시 깜빡임 방지)
+ const pendingTimer = window.setTimeout(() => {
+ setTasks((prev) =>
+ prev.map((task) => (task.id === taskId ? { ...task, pending: true } : task)),
+ );
+ }, 2000);
+
try {
await updateTask(groupId, taskListId, Number(itemId), { done: checked });
} finally {
+ // 타이머가 남아있으면 취소 (pending 노출 전에 완료된 경우)
+ clearTimeout(pendingTimer);
// 성공/실패 관계없이 서버 상태와 동기화
await queryClient.invalidateQueries({ queryKey });
}
diff --git a/src/app/(root)/[teamid]/_domain/interfaces/team.ts b/src/app/(root)/[teamid]/_domain/interfaces/team.ts
index 8e04562..a9c847d 100644
--- a/src/app/(root)/[teamid]/_domain/interfaces/team.ts
+++ b/src/app/(root)/[teamid]/_domain/interfaces/team.ts
@@ -18,6 +18,8 @@ export interface KanbanTask {
title: string;
items: TaskItem[];
status: KanbanStatus;
+ /** 서버 요청 진행 중 여부 (Soft Optimistic UI용) */
+ pending?: boolean;
}
export interface MockTeam {
diff --git a/src/app/(root)/[teamid]/page.module.css b/src/app/(root)/[teamid]/page.module.css
index 6ea7c63..6cb330a 100644
--- a/src/app/(root)/[teamid]/page.module.css
+++ b/src/app/(root)/[teamid]/page.module.css
@@ -13,7 +13,6 @@
min-width: 0;
width: 100%; /* Explicitly set width to 100% */
box-sizing: border-box; /* Ensure padding is included in the width */
- margin-left: 24px;
}
/* Apply max-width to direct children of mainContents to prevent overflow */
@@ -26,8 +25,9 @@
.desktopSidebar {
display: block; /* Show desktop sidebar */
/* fixed 포지션 사이드바가 flex 흐름에서 공간을 차지하지 않으므로, spacer 역할을 위해 너비 명시 */
- width: 270px;
- min-width: 270px;
+ /* 루트 레이아웃 main의 margin-left: 72px를 이미 반영하므로 270 - 72 = 198px */
+ width: 198px;
+ min-width: 198px;
flex-shrink: 0;
}
/* Tablet styles */
diff --git a/src/app/(root)/addteam/_domain/components/AddTeamSidebarWrapper.tsx b/src/app/(root)/addteam/_domain/components/AddTeamSidebarWrapper.tsx
index 35227aa..5ec4639 100644
--- a/src/app/(root)/addteam/_domain/components/AddTeamSidebarWrapper.tsx
+++ b/src/app/(root)/addteam/_domain/components/AddTeamSidebarWrapper.tsx
@@ -9,6 +9,11 @@ export default function AddTeamSidebarWrapper() {
const { data: currentUser } = useCurrentUserQuery();
const router = useRouter();
+ const handleLogout = async () => {
+ await fetch('/api/auth/logout', { method: 'POST' });
+ router.push('/login');
+ };
+
return (
router.push('/mypage')}
+ onLogout={handleLogout}
/>
);
}