/** =============================================================================== FILE: modules/web_api/static/js/tasks.js ROLE: Управление боковой панелью задач (Drawer), фильтрация и рендеринг карточек. AI-CONTEXT-ANCHORS: - ANCHOR[DRAWER_TOGGLE]: Открытие и закрытие выезжающей панели. - ANCHOR[TASKS_FILTER]: Фильтрация списка (ALL, IN_PROGRESS, BACKLOG, COMPLETED). - ANCHOR[TASKS_LOAD_FETCH]: Асинхронная загрузка задач через /api/v1/tasks. - ANCHOR[TASKS_RENDER_DOM]: Генерация HTML-карточек в боковом меню. =============================================================================== */ let currentFilter = 'ALL'; let allTasks = []; // --- [SECTION 1: DRAWER TOGGLE] --- # ANCHOR[DRAWER_TOGGLE] function toggleDrawer() { if (typeof IS_GUEST !== 'undefined' && IS_GUEST) return; const drawer = document.getElementById("task-drawer"); const backdrop = document.getElementById("drawer-backdrop"); if (!drawer) return; const isHidden = drawer.classList.contains("translate-x-full"); if (isHidden) { drawer.classList.remove("translate-x-full"); if (backdrop) backdrop.classList.remove("hidden"); loadTasks(); } else { drawer.classList.add("translate-x-full"); if (backdrop) backdrop.classList.add("hidden"); } } // --- [SECTION 2: FILTER CONTROL] --- # ANCHOR[TASKS_FILTER] function setFilter(status) { currentFilter = status; ["ALL", "IN_PROGRESS", "BACKLOG", "COMPLETED"].forEach(f => { const btn = document.getElementById(`filter-${f}`); if (btn) { btn.className = (f === status) ? "px-3 py-1.5 rounded-t-lg border-b-2 border-indigo-600 text-indigo-600 font-bold whitespace-nowrap" : "px-3 py-1.5 rounded-t-lg border-b-2 border-transparent whitespace-nowrap"; } }); renderTasks(); } // --- [SECTION 3: ASYNC DATA FETCH] --- # ANCHOR[TASKS_LOAD_FETCH] async function loadTasks() { const badge = document.getElementById("task-count-badge"); const container = document.getElementById("tasks-container"); const token = typeof API_TOKEN !== 'undefined' && API_TOKEN ? API_TOKEN : localStorage.getItem("scud_api_auth_token"); const isGuest = typeof IS_GUEST !== 'undefined' ? IS_GUEST : (localStorage.getItem("scud_is_guest") === "true"); if (isGuest || !token) { if (badge) badge.innerText = "0"; return; } try { const res = await fetch("/api/v1/tasks", { headers: { "Authorization": "Bearer " + token, "Content-Type": "application/json" } }); if (res.status === 401) { if (typeof logout === 'function') logout(); return; } if (!res.ok) { throw new Error(`HTTP error! status: ${res.status}`); } const data = await res.json(); if (Array.isArray(data)) { allTasks = data; } else if (data && Array.isArray(data.tasks)) { allTasks = data.tasks; } else if (data && typeof data === 'object') { allTasks = Object.values(data).find(val => Array.isArray(val)) || []; } else { allTasks = []; } if (badge) { badge.innerText = allTasks.length.toString(); } renderTasks(); } catch (err) { console.error("[Tasks Error]", err); if (badge) badge.innerText = "0"; if (container) { container.innerHTML = `
Ошибка обработки списка задач
`; } } } // --- [SECTION 4: DOM RENDERING] --- # ANCHOR[TASKS_RENDER_DOM] function renderTasks() { const container = document.getElementById("tasks-container"); if (!container) return; if (!Array.isArray(allTasks)) { allTasks = []; } const filtered = allTasks.filter(t => currentFilter === "ALL" || t.status === currentFilter); if (filtered.length === 0) { container.innerHTML = `
Нет задач с выбранным фильтром
`; return; } container.innerHTML = filtered.map(t => { let statusBadge = "bg-slate-100 text-slate-600 border-slate-200"; let statusLabel = "В планах"; let cardBg = "bg-white"; if (t.status === "COMPLETED") { statusBadge = "bg-emerald-50 text-emerald-700 border-emerald-300 font-semibold"; statusLabel = "Завершено"; cardBg = "bg-emerald-50/20"; } else if (t.status === "IN_PROGRESS") { statusBadge = "bg-amber-50 text-amber-700 border-amber-300 font-bold"; statusLabel = "В работе"; cardBg = "bg-amber-50/20 border-amber-200"; } let priorityBadge = "text-slate-500 bg-slate-100 border-slate-200"; if (t.priority === "HIGH") priorityBadge = "text-red-700 bg-red-50 border-red-200 font-bold"; let dueDateHtml = t.due_date ? `
Срок: ${t.due_date}
` : ""; return `
${t.task_id || t.id || 'TASK'} ${t.priority || 'MEDIUM'}
${statusLabel}

${t.title || t.description || ''}

${t.module || 'General'}
${dueDateHtml}
`; }).join(""); }