{% extends "base.html" %} {% block title %}Aktywnosc Uzytkownikow - Admin - Norda Biznes Partner{% endblock %} {% block extra_css %} {% endblock %} {% block content %}

Aktywnosc uzytkownikow

Dane z ostatnich 30 dni (bez botow)

{{ summary.total_sessions }}
Sesje
{{ summary.unique_users }}
Unikalni uzytkownicy
{{ summary.avg_duration_min }} min
Sredni czas sesji
{{ summary.total_pageviews }}
Odslony stron

Aktywni uzytkownicy dziennie

{% for day in daily_active %}
{% if day.count > 0 %}{{ day.count }}{% endif %} {% if day.event %} 📅({{ day.event.attendees }}) {% endif %}
{{ day.label }}
{% endfor %}

Ostatnie logowania

{% if recent_sessions %}
{% for s in recent_sessions %} {% endfor %}
Użytkownik Data Urządzenie Przeglądarka Czas (min) Odsłony
{{ s.user_name }} {{ s.started_at|local_time('%d.%m.%Y %H:%M') if s.started_at else '-' }} {% set dt = s.device_type|lower %} {{ s.device_type }} {{ s.browser }}{% if s.is_pwa %} PWA{% endif %} {{ s.duration_min }} {{ s.page_views_count }}
{% else %}

Brak danych o sesjach w ostatnich 30 dniach.

{% endif %}

Najbardziej aktywni uzytkownicy

{% if active_users %}
{% for u in active_users %} {% endfor %}
# Użytkownik Sesje Łączny czas (min) Odsłony Ostatnie logowanie
{{ loop.index }} {{ u.name }} {{ u.session_count }} {{ u.total_time_min }} {{ u.total_pages }} {{ u.last_login|local_time('%d.%m.%Y %H:%M') if u.last_login else '-' }}
{% else %}

Brak danych o aktywnosci uzytkownikow.

{% endif %}
{% endblock %} {% block extra_js %} /* --- Logins table: sorting + grouping --- */ (function() { var table = document.getElementById('logins-table'); if (!table) return; var tbody = table.querySelector('tbody'); var rows = Array.from(tbody.querySelectorAll('tr')); /* Column sorting */ table.querySelectorAll('th.sortable').forEach(function(th) { th.addEventListener('click', function() { var col = parseInt(th.dataset.col); var type = th.dataset.type; var isDesc = th.classList.contains('sort-desc'); var dir = isDesc ? 1 : -1; table.querySelectorAll('th.sortable').forEach(function(h) { h.classList.remove('sort-asc', 'sort-desc'); }); th.classList.add(isDesc ? 'sort-asc' : 'sort-desc'); rows.sort(function(a, b) { var aCell = a.cells[col], bCell = b.cells[col]; var aVal, bVal; if (type === 'date') { aVal = aCell.dataset.sortValue || '0'; bVal = bCell.dataset.sortValue || '0'; } else if (type === 'number') { aVal = parseFloat(aCell.textContent) || 0; bVal = parseFloat(bCell.textContent) || 0; return (aVal - bVal) * dir; } else { aVal = aCell.textContent.trim().toLowerCase(); bVal = bCell.textContent.trim().toLowerCase(); } return aVal < bVal ? dir : aVal > bVal ? -dir : 0; }); rows.forEach(function(r) { tbody.appendChild(r); }); }); }); /* Group tabs */ var detailDiv = document.getElementById('logins-detail'); var summaryDiv = document.getElementById('logins-summary'); var summaryHeader = document.getElementById('summary-header'); var summaryBody = document.getElementById('summary-body'); document.querySelectorAll('.group-tab').forEach(function(tab) { tab.addEventListener('click', function() { document.querySelectorAll('.group-tab').forEach(function(t) { t.classList.remove('active'); }); tab.classList.add('active'); var group = tab.dataset.group; if (group === 'all') { detailDiv.style.display = ''; summaryDiv.style.display = 'none'; return; } detailDiv.style.display = 'none'; summaryDiv.style.display = ''; var labels = { user: 'Użytkownik', device: 'Urządzenie', browser: 'Przeglądarka' }; var cols = [ { key: 'name', label: labels[group], type: 'string' }, { key: 'count', label: 'Sesje', type: 'number' }, { key: 'duration', label: 'Łączny czas (min)', type: 'number' }, { key: 'views', label: 'Łączne odsłony', type: 'number' } ]; summaryHeader.innerHTML = ''; cols.forEach(function(c, i) { var th = document.createElement('th'); th.textContent = c.label; th.className = 'sortable' + (i === 1 ? ' sort-desc' : ''); th.dataset.skey = c.key; th.dataset.stype = c.type; th.addEventListener('click', function() { sortSummary(th); }); summaryHeader.appendChild(th); }); var grouped = {}; rows.forEach(function(r) { var key = r.dataset[group] || '-'; if (!grouped[key]) grouped[key] = { name: key, count: 0, duration: 0, views: 0 }; grouped[key].count++; grouped[key].duration += parseFloat(r.cells[4].textContent) || 0; grouped[key].views += parseInt(r.cells[5].textContent) || 0; }); var summaryData = Object.values(grouped); renderSummary(summaryData, 'count', -1); function sortSummary(th) { var key = th.dataset.skey; var type = th.dataset.stype; var wasDesc = th.classList.contains('sort-desc'); summaryHeader.querySelectorAll('th').forEach(function(h) { h.classList.remove('sort-asc','sort-desc'); }); var desc = !wasDesc; th.classList.add(desc ? 'sort-desc' : 'sort-asc'); var dir = desc ? -1 : 1; renderSummary(summaryData, key, dir); } function renderSummary(data, sortKey, dir) { data.sort(function(a, b) { var av = a[sortKey], bv = b[sortKey]; if (typeof av === 'string') { av = av.toLowerCase(); bv = bv.toLowerCase(); } return av < bv ? dir : av > bv ? -dir : 0; }); summaryBody.innerHTML = ''; data.forEach(function(g) { var tr = document.createElement('tr'); tr.innerHTML = '' + g.name + '' + '' + g.count + '' + '' + g.duration.toFixed(1) + '' + '' + g.views + ''; summaryBody.appendChild(tr); }); } }); }); })(); /* --- Active users table: sorting --- */ (function() { var table = document.getElementById('active-users-table'); if (!table) return; var tbody = table.querySelector('tbody'); var rows = Array.from(tbody.querySelectorAll('tr')); table.querySelectorAll('th.sortable').forEach(function(th) { th.addEventListener('click', function() { var col = parseInt(th.dataset.col); var type = th.dataset.type; var isDesc = th.classList.contains('sort-desc'); var dir = isDesc ? 1 : -1; table.querySelectorAll('th.sortable').forEach(function(h) { h.classList.remove('sort-asc', 'sort-desc'); }); th.classList.add(isDesc ? 'sort-asc' : 'sort-desc'); rows.sort(function(a, b) { var aCell = a.cells[col], bCell = b.cells[col]; if (type === 'date') { var av = aCell.dataset.sortValue || '0'; var bv = bCell.dataset.sortValue || '0'; return av < bv ? dir : av > bv ? -dir : 0; } else if (type === 'number') { return (parseFloat(aCell.textContent) - parseFloat(bCell.textContent)) * dir; } else { var av = aCell.textContent.trim().toLowerCase(); var bv = bCell.textContent.trim().toLowerCase(); return av < bv ? dir : av > bv ? -dir : 0; } }); rows.forEach(function(r) { tbody.appendChild(r); }); }); }); })(); {% endblock %}