Skip to content
Merged

Dev #20

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions src/components/dashboard/ErrorList.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from '@tanstack/react-query';
import { fetchProjectDashboard } from '../../api/dashboardAPI';
import { Warning, Person, AccessTime } from '@mui/icons-material';
import { useNavigate } from 'react-router-dom';

function ErrorList({ selectedProjectId }) {
const { data: dashboardData, isLoading, error } = useQuery({
Expand All @@ -9,11 +10,18 @@ function ErrorList({ selectedProjectId }) {
enabled: !!selectedProjectId,
});

const navigate = useNavigate();
const priorities = dashboardData?.data?.priorities?.priority || [];

const errorPriorities = dashboardData?.data?.errorPriorities || {};

// WARNING 우선순위만 필터링 (에러로 간주)
const errorTasks = priorities.find(p => p.priority === 'WARNING')?.priorityDataList || [];

// 이슈 클릭 핸들러
const handleIssueClick = (issueId) => {
navigate(`/api/issues/${issueId}`);
};

if (isLoading) {
return (
<div className="bg-white p-6 rounded-xl shadow-sm">
Expand Down Expand Up @@ -74,15 +82,18 @@ function ErrorList({ selectedProjectId }) {
</div>
<div className="flex items-center gap-1">
<AccessTime className="w-3 h-3" />
<span>즉시 처리 필요</span>
<span>{errorPriorities.endDate || '즉시 처리 필요'}</span>
</div>
</div>
</div>
</div>

{/* 액션 버튼 */}
<div className="mt-3 flex gap-2">
<button className="text-xs bg-red-600 text-white px-3 py-1 rounded hover:bg-red-700 transition-colors">
<button
className="text-xs bg-red-600 text-white px-3 py-1 rounded hover:bg-red-700 transition-colors cursor-pointer"
onClick={() => handleIssueClick(task.id)}
>
상세보기
</button>
<button className="text-xs border border-red-300 text-red-700 px-3 py-1 rounded hover:bg-red-50 transition-colors">
Expand Down
106 changes: 81 additions & 25 deletions src/components/dashboard/PriorityTasks.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useQuery } from '@tanstack/react-query';
import { fetchProjectDashboard } from '../../api/dashboardAPI';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';

function PriorityTasks({ selectedProjectId }) {
const { data: dashboardData, isLoading, error } = useQuery({
Expand All @@ -8,52 +10,90 @@ function PriorityTasks({ selectedProjectId }) {
enabled: !!selectedProjectId,
});

const navigate = useNavigate();
const priorities = dashboardData?.data?.priorities?.priority || [];

// 각 우선순위별로 표시할 항목 수를 관리하는 상태
const [visibleItems, setVisibleItems] = useState({});

// 우선순위별 색상 매핑
const getPriorityConfig = (priority) => {
switch (priority) {
case 'LOW':
return {
dotColor: 'bg-green-500',
label: '낮음',
bgColor: 'bg-gray-50'
bgColor: 'bg-green-50',
borderColor: 'border-green-200'
};
case 'NORMAL':
return {
dotColor: 'bg-yellow-500',
label: '보통',
bgColor: 'bg-gray-50'
bgColor: 'bg-yellow-50',
borderColor: 'border-yellow-200'
};
case 'HIGH':
return {
dotColor: 'bg-red-500',
label: '높음',
bgColor: 'bg-gray-50'
bgColor: 'bg-red-50',
borderColor: 'border-red-200'
};
case 'WARNING':
return {
dotColor: 'bg-red-600',
label: '긴급',
bgColor: 'bg-gray-50'
bgColor: 'bg-red-100',
borderColor: 'border-red-300'
};
default:
return {
dotColor: 'bg-gray-500',
label: priority,
bgColor: 'bg-gray-50'
bgColor: 'bg-gray-50',
borderColor: 'border-gray-200'
};
}
};

// 우선순위 정렬 함수
const getPriorityOrder = (priority) => {
switch (priority) {
case 'HIGH': return 1;
case 'NORMAL': return 2;
case 'LOW': return 3;
case 'WARNING': return 0; // WARNING은 가장 높은 우선순위
default: return 4;
}
};

// 이슈 클릭 핸들러
const handleIssueClick = (issueId) => {
navigate(`/api/issues/${issueId}`);
};

// 더 보기 클릭 핸들러
const handleShowMore = (priority) => {
setVisibleItems(prev => ({
...prev,
[priority]: (prev[priority] || 3) + 3
}));
};

// 더 적게 보기 클릭 핸들러
const handleShowLess = (priority) => {
setVisibleItems(prev => ({
...prev,
[priority]: 3
}));
};

if (isLoading) {
return (
<div className="bg-white p-6 rounded-xl shadow-sm">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-gray-900">우선순위 작업</h3>
<button className="text-sm text-blue-500 hover:text-blue-600">
칸반보드로 이동
</button>
</div>
<div className="flex items-center justify-center h-48">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
Expand All @@ -67,9 +107,6 @@ function PriorityTasks({ selectedProjectId }) {
<div className="bg-white p-6 rounded-xl shadow-sm">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-gray-900">우선순위 작업</h3>
<button className="text-sm text-blue-500 hover:text-blue-600">
칸반보드로 이동
</button>
</div>
<div className="flex items-center justify-center h-48 text-gray-500">
{!selectedProjectId ? '프로젝트를 선택해주세요' : '데이터를 불러올 수 없습니다'}
Expand All @@ -79,38 +116,45 @@ function PriorityTasks({ selectedProjectId }) {
}

// WARNING 우선순위는 제외 (에러 리스트 컴포넌트에서 표시)
const filteredPriorities = priorities.filter(p => p.priority !== 'WARNING');
const filteredPriorities = priorities
.filter(p => p.priority !== 'WARNING')
.sort((a, b) => getPriorityOrder(a.priority) - getPriorityOrder(b.priority));

return (
<div className="bg-white p-6 rounded-xl shadow-sm">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-gray-900">우선순위 작업</h3>
<button className="text-sm text-blue-500 hover:text-blue-600">
칸반보드로 이동
</button>
</div>

<div className="space-y-3">
{filteredPriorities.map((priorityGroup) => {
const config = getPriorityConfig(priorityGroup.priority);
const currentVisibleItems = visibleItems[priorityGroup.priority] || 3;
const totalItems = priorityGroup.priorityDataList.length;
const hasMoreItems = totalItems > currentVisibleItems;
const hasLessItems = currentVisibleItems > 3;

return (
<div key={priorityGroup.priority} className="space-y-2">
{/* 우선순위 헤더 */}
{/* 우선순위 헤더 - 기존처럼 배경색 없이 */}
<div className="flex items-center gap-3">
<div className={`w-3 h-3 rounded-full ${config.dotColor}`}></div>
<span className="text-sm font-medium text-gray-700">
{config.label}
</span>
<span className="text-sm text-gray-500">
({priorityGroup.priorityDataList.length}개)
({totalItems}개)
</span>
</div>

{/* 작업 목록 */}
{/* 작업 목록 - 우선순위별 배경색 적용 */}
<div className="space-y-2 ml-6">
{priorityGroup.priorityDataList.slice(0, 3).map((task) => (
<div key={task.id} className={`p-3 rounded-lg ${config.bgColor} hover:bg-gray-100 transition-colors cursor-pointer`}>
{priorityGroup.priorityDataList.slice(0, currentVisibleItems).map((task) => (
<div
key={task.id}
className={`p-3 rounded-lg ${config.bgColor} border ${config.borderColor} hover:opacity-80 transition-opacity cursor-pointer`}
onClick={() => handleIssueClick(task.id)}
>
<div className="flex items-center justify-between">
<div className="flex-1 min-w-0">
<div className="text-sm text-gray-900 truncate mb-1">
Expand All @@ -127,10 +171,22 @@ function PriorityTasks({ selectedProjectId }) {
</div>
))}

{/* 더 많은 항목이 있을 경우 */}
{priorityGroup.priorityDataList.length > 3 && (
<div className="text-xs text-gray-400 text-center py-1">
+{priorityGroup.priorityDataList.length - 3}개 더
{/* 더 보기/더 적게 보기 버튼 */}
{hasMoreItems && (
<div
className="text-xs text-blue-500 text-center py-1 cursor-pointer hover:text-blue-600 transition-colors"
onClick={() => handleShowMore(priorityGroup.priority)}
>
+{totalItems - currentVisibleItems}개 더 보기
</div>
)}

{hasLessItems && (
<div
className="text-xs text-gray-500 text-center py-1 cursor-pointer hover:text-gray-600 transition-colors"
onClick={() => handleShowLess(priorityGroup.priority)}
>
접기
</div>
)}
</div>
Expand All @@ -151,4 +207,4 @@ function PriorityTasks({ selectedProjectId }) {
);
}

export default PriorityTasks;
export default PriorityTasks;
Loading