// ─────────────────────────────────────────────────────────── // Huio Control Panel — Activity Logs View (cp-activity-logs-view.jsx) // ─────────────────────────────────────────────────────────── if (!window.CP_STYLES) throw new Error('[cp-activity-logs-view] window.CP_STYLES not loaded'); // Static badge dictionary for O(1) lookup without branching overhead const LEVEL_BADGES = { success: 'hu-chip hu-chip-teal', warning: 'hu-chip hu-chip-ochre', system: 'hu-chip hu-chip-coral', }; const CAT_BADGES = { user: 'hu-chip hu-chip-sky', group: 'hu-chip hu-chip-green', financial: 'hu-chip hu-chip-terra', error: 'hu-chip hu-chip-coral', }; const CATEGORIES = ['all', 'user', 'group', 'member', 'financial', 'analytics', 'error']; function renderActivityLogs({ lang = 'vi', t: rawT, appStyles: rawAppStyles, logs: rawLogs = [], users: rawUsers = [], logsCategoryFilter = 'all', setLogsCategoryFilter, logsTypeFilter = 'all', logsSearchQuery = '', setLogsSearchQuery, logsCurrentPage = 1, setLogsCurrentPage, logsPerPage = 10, logsDateFilter = '', setLogsDateFilter, logsUserFilter = 'all', setLogsUserFilter, supabaseClient, loadRealtimeData, }) { const appStyles = rawAppStyles || window.CP_STYLES || {}; const t = typeof rawT === 'function' ? rawT : (k) => k; const logs = Array.isArray(rawLogs) ? rawLogs : []; const users = Array.isArray(rawUsers) ? rawUsers : []; // High-Load Performance: Pre-normalize filters outside iteration to eliminate repeated allocations const normalizedSearch = typeof logsSearchQuery === 'string' ? logsSearchQuery.trim().toLowerCase() : ''; const hasSearch = normalizedSearch.length > 0; const normalizedUserFilter = typeof logsUserFilter === 'string' ? logsUserFilter.trim().toLowerCase() : 'all'; const hasUserFilter = normalizedUserFilter !== 'all' && normalizedUserFilter.length > 0; // Zero-allocation pre-calculation of errors & warnings let errorLogsCount = 0; for (let i = 0; i < logs.length; i++) { const l = logs[i]; if (l && (l.type === 'system' || l.type === 'warning')) { errorLogsCount++; } } // Single-pass defensive filter const filteredLogs = logs.filter(log => { if (!log) return false; // Category filter if (logsCategoryFilter !== 'all' && log.category !== logsCategoryFilter) return false; // Log Type/Severity filter if (logsTypeFilter !== 'all' && log.type !== logsTypeFilter) return false; // Date filter if (logsDateFilter && log.date !== logsDateFilter) return false; // User filter if (hasUserFilter) { const userId = log.userId ? String(log.userId) : ''; const userName = typeof log.userName === 'string' ? log.userName.toLowerCase() : ''; const logText = typeof log.text === 'string' ? log.text.toLowerCase() : ''; const matchUser = (userId === logsUserFilter) || (userName && userName === normalizedUserFilter) || (logText && logText.includes(normalizedUserFilter)); if (!matchUser) return false; } // Search query if (hasSearch) { const text = typeof log.text === 'string' ? log.text.toLowerCase() : (log.text != null ? String(log.text).toLowerCase() : ''); if (!text.includes(normalizedSearch)) return false; } return true; }); // Safe pagination math with upper and lower boundary protection const totalItems = filteredLogs.length; const totalPages = Math.max(1, Math.ceil(totalItems / logsPerPage) || 1); const safeCurrentPage = Math.min(Math.max(1, logsCurrentPage), totalPages); const startIndex = (safeCurrentPage - 1) * logsPerPage; const endIndex = startIndex + logsPerPage; const paginatedLogs = filteredLogs.slice(startIndex, endIndex); return (
{lang === 'vi' ? 'Giám sát thời gian thực toàn bộ hoạt động của người dùng, tài chính và hệ thống.' : 'Real-time telemetry of user actions, transactions, and system diagnostics.'}
| {lang === 'vi' ? 'Thời gian' : 'Time'} | {lang === 'vi' ? 'Mức độ' : 'Level'} | {lang === 'vi' ? 'Phân loại' : 'Category'} | {lang === 'vi' ? 'Chi tiết hoạt động' : 'Operation Details'} |
|---|---|---|---|
| {lang === 'vi' ? 'Không tìm thấy nhật ký hoạt động nào.' : 'No activity logs found.'} | |||
|
{log.time || '--:--:--'}
{log.date || '----/--/--'}
|
{log.type === 'system' ? 'CRITICAL' : (log.type ? log.type.toUpperCase() : 'INFO')} | {log.category || 'system'} | {log.text || ''} |