first commit
This commit is contained in:
+151
@@ -0,0 +1,151 @@
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// ISSUES PAGE — Kanban + List view for issue management
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
let _issueView = 'kanban'; // 'kanban' | 'list'
|
||||
|
||||
function renderIssuesPage() {
|
||||
const filtered = getFilteredIssues();
|
||||
if (_issueView === 'kanban') renderKanbanView(filtered);
|
||||
else renderListView(filtered);
|
||||
}
|
||||
|
||||
function applyIssueFilters() {
|
||||
renderIssuesPage();
|
||||
}
|
||||
|
||||
function switchIssueView(view) {
|
||||
_issueView = view;
|
||||
document.getElementById('kanban-view-btn').classList.toggle('active', view === 'kanban');
|
||||
document.getElementById('list-view-btn').classList.toggle('active', view === 'list');
|
||||
renderIssuesPage();
|
||||
}
|
||||
|
||||
function getFilteredIssues() {
|
||||
const search = (document.getElementById('issues-search')?.value || '').toLowerCase().trim();
|
||||
const program = document.getElementById('issues-filter-program')?.value || 'all';
|
||||
const severity= document.getElementById('issues-filter-severity')?.value || 'all';
|
||||
|
||||
return APP_STATE.issues.filter(i => {
|
||||
const matchSearch = !search || i.judul.toLowerCase().includes(search) || i.daerah.toLowerCase().includes(search) || i.provinsi.toLowerCase().includes(search) || i.id.toLowerCase().includes(search);
|
||||
const matchProg = program === 'all' || i.programId === program;
|
||||
const matchSev = severity === 'all' || i.severity === severity;
|
||||
return matchSearch && matchProg && matchSev;
|
||||
});
|
||||
}
|
||||
|
||||
// ─── KANBAN VIEW ─────────────────────────────────────────────────
|
||||
function renderKanbanView(issues) {
|
||||
const cols = [
|
||||
{ key: 'open', label: 'Terbuka', icon: '🔴', color: 'var(--red)' },
|
||||
{ key: 'in_progress', label: 'Diproses', icon: '🔵', color: 'var(--blue)' },
|
||||
{ key: 'resolved', label: 'Selesai', icon: '✅', color: 'var(--green)' }
|
||||
];
|
||||
document.getElementById('issues-body').innerHTML = `
|
||||
<div class="kanban-view">
|
||||
${cols.map(col => {
|
||||
const colIssues = issues.filter(i => i.status === col.key);
|
||||
return `
|
||||
<div class="kanban-col">
|
||||
<div class="kanban-col-header">
|
||||
<div class="kanban-col-title">
|
||||
<span>${col.icon}</span>
|
||||
<span>${col.label}</span>
|
||||
</div>
|
||||
<span class="col-count">${colIssues.length}</span>
|
||||
</div>
|
||||
<div class="kanban-cards">
|
||||
${colIssues.length === 0
|
||||
? `<div class="empty-state" style="padding:32px 16px;"><div class="empty-icon" style="font-size:24px;opacity:0.3;">📭</div><div class="empty-desc" style="font-size:11px;">Tidak ada issue</div></div>`
|
||||
: colIssues.map(i => renderIssueCard(i)).join('')
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderIssueCard(issue) {
|
||||
const prog = getProgramById(issue.programId);
|
||||
const survCount = issue.surveyIds.length;
|
||||
const escCount = issue.escalationIds.length;
|
||||
return `
|
||||
<div class="issue-card ${issue.severity}-card fade-in" onclick="openIssueDetail('${issue.id}')">
|
||||
<div class="ic-header">
|
||||
<span class="ic-id">${issue.id}</span>
|
||||
${getSevBadge(issue.severity)}
|
||||
</div>
|
||||
<div class="flex gap-2 items-center mb-2">
|
||||
${getProgramBadge(issue.programId)}
|
||||
<span style="font-size:10px;color:var(--text-3);">📍 ${issue.daerah}</span>
|
||||
</div>
|
||||
<div class="ic-title">${issue.judul}</div>
|
||||
<div class="ic-desc">${issue.deskripsi}</div>
|
||||
<div class="ic-footer">
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
${survCount > 0 ? `<span style="font-size:10px;color:var(--purple);">📋 ${survCount} survey</span>` : ''}
|
||||
${escCount > 0 ? `<span style="font-size:10px;color:var(--orange);">🔺 ${escCount} eskalasi</span>` : ''}
|
||||
</div>
|
||||
<div class="ic-meta">${formatDate(issue.createdAt)}</div>
|
||||
</div>
|
||||
<div style="margin-top:8px;padding-top:8px;border-top:1px solid var(--border);font-size:10px;color:var(--text-3);" class="truncate">
|
||||
👤 ${issue.assignee}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// ─── LIST / TABLE VIEW ────────────────────────────────────────────
|
||||
function renderListView(issues) {
|
||||
document.getElementById('issues-body').innerHTML = `
|
||||
<div class="list-view">
|
||||
${issues.length === 0
|
||||
? `<div class="empty-state"><div class="empty-icon">🔍</div><div class="empty-title">Tidak ada issue</div><div class="empty-desc">Tidak ada issue yang cocok dengan filter yang dipilih</div></div>`
|
||||
: `<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Judul Issue</th>
|
||||
<th>Program</th>
|
||||
<th>Daerah</th>
|
||||
<th>Keparahan</th>
|
||||
<th>Status</th>
|
||||
<th>Ditugaskan ke</th>
|
||||
<th>Tanggal</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${issues.map(i => `
|
||||
<tr style="cursor:pointer;" onclick="openIssueDetail('${i.id}')">
|
||||
<td><span style="font-family:monospace;font-size:11px;color:var(--text-3);">${i.id}</span></td>
|
||||
<td style="max-width:240px;">
|
||||
<div style="font-size:12px;font-weight:500;color:var(--text-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:220px;" title="${i.judul}">${i.judul}</div>
|
||||
</td>
|
||||
<td>${getProgramBadge(i.programId)}</td>
|
||||
<td>
|
||||
<div style="font-size:12px;font-weight:500;">${i.daerah}</div>
|
||||
<div class="td-muted">${i.provinsi}</div>
|
||||
</td>
|
||||
<td>${getSevBadge(i.severity)}</td>
|
||||
<td>${getStatBadge(i.status)}</td>
|
||||
<td class="td-muted truncate" style="max-width:140px;">${i.assignee}</td>
|
||||
<td class="td-muted">${formatDate(i.createdAt)}</td>
|
||||
<td>
|
||||
<div style="display:flex;gap:4px;">
|
||||
${i.surveyIds.length > 0 ? `<span title="${i.surveyIds.length} survey" style="font-size:12px;">📋</span>` : ''}
|
||||
${i.escalationIds.length > 0 ? `<span title="${i.escalationIds.length} eskalasi" style="font-size:12px;">🔺</span>` : ''}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
Reference in New Issue
Block a user