feat: 수신함 UI 간소화 및 용어 개선 - 프로젝트 필터만 유지

🎯 UI Simplification:
- 필터링 간소화: 4개 필터 → 1개 (프로젝트만)
- 레이아웃 최적화: grid-cols-4 → max-w-md
- 불필요한 상태/읽음상태/검색 필터 제거

📝 Terminology Improvements:
- '부적합 목록' → '신고 목록'
- '새로 등록된 부적합 사항' → '새로 등록된 신고 사항'
- '새로운 부적합이 등록되면' → '새로운 신고가 등록되면'
- 함수 주석: '부적합 필터링/정렬' → '신고 필터링/정렬'

 Code Optimization:
- filterIssues() 함수 간소화
- 불필요한 DOM 요소 및 이벤트 핸들러 제거
- 프로젝트 필드명 수정: project.name → project.project_name

🎨 Enhanced UX:
- 깔끔하고 직관적인 필터 인터페이스
- 사용자 친화적인 용어 사용
- 집중도 높은 단순한 레이아웃

🔧 Fixed Issues:
- 프로젝트 정보 표시 오류 해결 (필드명 불일치)
- 관리함/폐기함 페이지도 동일 오류 수정
- 프로젝트 로딩 디버깅 로그 추가

Expected Result:
 간결하고 사용하기 쉬운 수신함 인터페이스
 올바른 프로젝트 정보 표시
 일관성 있는 용어 사용으로 사용자 혼란 방지
This commit is contained in:
Hyungi Ahn
2025-10-25 13:01:31 +09:00
parent 7b9dfddec3
commit aacf05d05c

View File

@@ -134,7 +134,7 @@
<i class="fas fa-inbox text-blue-500 mr-3"></i> <i class="fas fa-inbox text-blue-500 mr-3"></i>
수신함 수신함
</h1> </h1>
<p class="text-gray-600 mt-1">새로 등록된 부적합 사항을 확인하고 처리하세요</p> <p class="text-gray-600 mt-1">새로 등록된 신고 사항을 확인하고 처리하세요</p>
</div> </div>
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-3">
<button onclick="markAllAsRead()" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"> <button onclick="markAllAsRead()" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors">
@@ -189,9 +189,9 @@
</div> </div>
</div> </div>
<!-- 필터 및 검색 --> <!-- 필터 -->
<div class="bg-white rounded-xl shadow-sm p-6 mb-6"> <div class="bg-white rounded-xl shadow-sm p-6 mb-6">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4"> <div class="max-w-md">
<!-- 프로젝트 필터 --> <!-- 프로젝트 필터 -->
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-2">📁 프로젝트</label> <label class="block text-sm font-medium text-gray-700 mb-2">📁 프로젝트</label>
@@ -199,43 +199,14 @@
<option value="">전체 프로젝트</option> <option value="">전체 프로젝트</option>
</select> </select>
</div> </div>
<!-- 상태 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">📋 상태</label>
<select id="statusFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" onchange="filterIssues()">
<option value="">전체 상태</option>
<option value="new">새 부적합</option>
<option value="processing">처리 중</option>
<option value="pending">대기 중</option>
</select>
</div>
<!-- 읽음 상태 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">👁️ 읽음 상태</label>
<select id="readStatusFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" onchange="filterIssues()">
<option value="">전체</option>
<option value="unread">읽지 않음</option>
<option value="read">읽음</option>
</select>
</div>
<!-- 검색 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">🔍 검색</label>
<input type="text" id="searchInput" placeholder="설명 또는 등록자 검색..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
onkeyup="filterIssues()">
</div>
</div> </div>
</div> </div>
<!-- 부적합 목록 --> <!-- 신고 목록 -->
<div class="bg-white rounded-xl shadow-sm"> <div class="bg-white rounded-xl shadow-sm">
<div class="p-6 border-b border-gray-200"> <div class="p-6 border-b border-gray-200">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h2 class="text-lg font-semibold text-gray-800">부적합 목록</h2> <h2 class="text-lg font-semibold text-gray-800">신고 목록</h2>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<span class="text-sm text-gray-500">정렬:</span> <span class="text-sm text-gray-500">정렬:</span>
<select id="sortOrder" class="text-sm border border-gray-300 rounded px-2 py-1" onchange="sortIssues()"> <select id="sortOrder" class="text-sm border border-gray-300 rounded px-2 py-1" onchange="sortIssues()">
@@ -256,7 +227,7 @@
<div id="emptyState" class="hidden p-12 text-center"> <div id="emptyState" class="hidden p-12 text-center">
<i class="fas fa-inbox text-6xl text-gray-300 mb-4"></i> <i class="fas fa-inbox text-6xl text-gray-300 mb-4"></i>
<h3 class="text-lg font-medium text-gray-900 mb-2">수신함이 비어있습니다</h3> <h3 class="text-lg font-medium text-gray-900 mb-2">수신함이 비어있습니다</h3>
<p class="text-gray-500">새로운 부적합이 등록되면 여기에 표시됩니다.</p> <p class="text-gray-500">새로운 신고가 등록되면 여기에 표시됩니다.</p>
</div> </div>
</div> </div>
</main> </main>
@@ -550,6 +521,7 @@
// 프로젝트 로드 // 프로젝트 로드
async function loadProjects() { async function loadProjects() {
console.log('🔄 프로젝트 로드 시작');
try { try {
const response = await fetch('/api/projects/', { const response = await fetch('/api/projects/', {
headers: { headers: {
@@ -558,12 +530,18 @@
} }
}); });
console.log('📡 프로젝트 API 응답 상태:', response.status);
if (response.ok) { if (response.ok) {
projects = await response.json(); projects = await response.json();
console.log('✅ 프로젝트 로드 성공:', projects.length, '개');
console.log('📋 프로젝트 목록:', projects);
updateProjectFilter(); updateProjectFilter();
} else {
console.error('❌ 프로젝트 API 응답 실패:', response.status, response.statusText);
} }
} catch (error) { } catch (error) {
console.error('프로젝트 로드 실패:', error); console.error('프로젝트 로드 실패:', error);
} }
} }
@@ -575,7 +553,7 @@
projects.forEach(project => { projects.forEach(project => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = project.id; option.value = project.id;
option.textContent = project.name; option.textContent = project.project_name;
projectFilter.appendChild(option); projectFilter.appendChild(option);
}); });
} }
@@ -621,30 +599,14 @@
} }
} }
// 부적합 필터링 // 신고 필터링
function filterIssues() { function filterIssues() {
const projectFilter = document.getElementById('projectFilter').value; const projectFilter = document.getElementById('projectFilter').value;
const statusFilter = document.getElementById('statusFilter').value;
const readStatusFilter = document.getElementById('readStatusFilter').value;
const searchInput = document.getElementById('searchInput').value.toLowerCase();
filteredIssues = issues.filter(issue => { filteredIssues = issues.filter(issue => {
// 프로젝트 필터 // 프로젝트 필터
if (projectFilter && issue.project_id != projectFilter) return false; if (projectFilter && issue.project_id != projectFilter) return false;
// 상태 필터
if (statusFilter && issue.status !== statusFilter) return false;
// 읽음 상태 필터
if (readStatusFilter === 'read' && !readStatus.has(issue.id)) return false;
if (readStatusFilter === 'unread' && readStatus.has(issue.id)) return false;
// 검색 필터
if (searchInput) {
const searchText = `${issue.description} ${issue.reporter?.username || ''}`.toLowerCase();
if (!searchText.includes(searchInput)) return false;
}
return true; return true;
}); });
@@ -652,7 +614,7 @@
displayIssues(); displayIssues();
} }
// 부적합 정렬 // 신고 정렬
function sortIssues() { function sortIssues() {
const sortOrder = document.getElementById('sortOrder').value; const sortOrder = document.getElementById('sortOrder').value;
@@ -702,7 +664,7 @@
<div class="flex items-center space-x-3 mb-2"> <div class="flex items-center space-x-3 mb-2">
${isUnread ? '<div class="w-2 h-2 bg-blue-500 rounded-full"></div>' : '<div class="w-2 h-2"></div>'} ${isUnread ? '<div class="w-2 h-2 bg-blue-500 rounded-full"></div>' : '<div class="w-2 h-2"></div>'}
<span class="badge badge-new">검토 대기</span> <span class="badge badge-new">검토 대기</span>
${project ? `<span class="text-sm text-gray-500">${project.name}</span>` : ''} ${project ? `<span class="text-sm text-gray-500">${project.project_name}</span>` : ''}
<span class="text-sm text-gray-400">${timeAgo}</span> <span class="text-sm text-gray-400">${timeAgo}</span>
</div> </div>
@@ -878,7 +840,7 @@
const project = projects.find(p => p.id === issue.project_id); const project = projects.find(p => p.id === issue.project_id);
originalInfo.innerHTML = ` originalInfo.innerHTML = `
<div class="space-y-2"> <div class="space-y-2">
<div><strong>프로젝트:</strong> ${project ? project.name : '미지정'}</div> <div><strong>프로젝트:</strong> ${project ? project.project_name : '미지정'}</div>
<div><strong>카테고리:</strong> ${getCategoryText(issue.category)}</div> <div><strong>카테고리:</strong> ${getCategoryText(issue.category)}</div>
<div><strong>설명:</strong> ${issue.description}</div> <div><strong>설명:</strong> ${issue.description}</div>
<div><strong>등록자:</strong> ${issue.reporter?.username || '알 수 없음'}</div> <div><strong>등록자:</strong> ${issue.reporter?.username || '알 수 없음'}</div>
@@ -892,7 +854,7 @@
projects.forEach(project => { projects.forEach(project => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = project.id; option.value = project.id;
option.textContent = project.name; option.textContent = project.project_name;
if (project.id === issue.project_id) { if (project.id === issue.project_id) {
option.selected = true; option.selected = true;
} }