mirror of
https://github.com/QwIT-Development/firka-extension.git
synced 2026-06-12 03:41:39 +02:00
New layout for absences
This commit is contained in:
@@ -239,66 +239,200 @@ body {
|
||||
}
|
||||
|
||||
|
||||
.absences-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.absence-group {
|
||||
background: var(--card-card);
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
animation: fadeIn 0.3s ease;
|
||||
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.absence-date {
|
||||
padding: 16px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.absence-count {
|
||||
margin-left: auto;
|
||||
background: var(--accent-accent);
|
||||
color: var(--button-secondaryFill);
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.absence-list {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.absence-item {
|
||||
.stats-overview {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
background: var(--accent-15);
|
||||
border-radius: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: var(--card-card);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.absence-item:hover {
|
||||
transform: translateX(4px);
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.absence-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
.stat-number {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: var(--accent-accent);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.absences-container {
|
||||
background: var(--card-card);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0px 1px var(--shadow-blur) 0px var(--accent-shadow);
|
||||
}
|
||||
|
||||
.absences-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
background: var(--accent-15);
|
||||
border-bottom: 1px solid var(--accent-30);
|
||||
}
|
||||
|
||||
.table-header th {
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
border-bottom: 1px solid var(--accent-15);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.table-row:hover {
|
||||
background: var(--accent-10);
|
||||
}
|
||||
|
||||
.table-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
padding: 16px;
|
||||
color: var(--text-primary);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.date-cell {
|
||||
font-weight: 600;
|
||||
color: var(--accent-accent);
|
||||
}
|
||||
|
||||
.lesson-cell {
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.subject-cell {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.topic-cell {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status-cell {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.status-badge.justified {
|
||||
background: var(--grades-4-bg);
|
||||
color: var(--grades-4);
|
||||
}
|
||||
|
||||
.status-badge.unjustified {
|
||||
background: var(--grades-1-bg);
|
||||
color: var(--grades-1);
|
||||
}
|
||||
|
||||
.status-badge.pending {
|
||||
background: var(--grades-3-bg);
|
||||
color: var(--grades-3);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.absences-table {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.table-header th,
|
||||
.table-cell {
|
||||
padding: 12px 8px;
|
||||
}
|
||||
|
||||
.topic-cell {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.stats-overview {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.absences-table,
|
||||
.table-header,
|
||||
.table-row {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--accent-15);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
background: var(--card-card);
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid var(--accent-15);
|
||||
}
|
||||
|
||||
.table-cell:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.table-cell::before {
|
||||
content: attr(data-label);
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.stats-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.absence-details {
|
||||
|
||||
@@ -116,39 +116,67 @@ async function transformAbsencesPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-overview">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">${absences.length}</div>
|
||||
<div class="stat-label">${LanguageManager.t('absences.total_absences')}</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">${absences.filter(a => a.justificationStatus === 'justified').length}</div>
|
||||
<div class="stat-label">${LanguageManager.t('absences.justified')}</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">${absences.filter(a => a.justificationStatus === 'unjustified').length}</div>
|
||||
<div class="stat-label">${LanguageManager.t('absences.unjustified')}</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">${absences.filter(a => a.justificationStatus === 'pending').length}</div>
|
||||
<div class="stat-label">${LanguageManager.t('absences.pending')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="absences-container">
|
||||
${Object.entries(groupedAbsences).map(([date, dayAbsences]) => `
|
||||
<div class="absence-group" data-date="${date}">
|
||||
<div class="absence-date">
|
||||
<span class="material-icons-round">event</span>
|
||||
${date}
|
||||
<span class="absence-count">${dayAbsences.length} ${LanguageManager.t('absences.hours')}</span>
|
||||
</div>
|
||||
<div class="absence-list">
|
||||
${dayAbsences.map(absence => `
|
||||
<div class="absence-item"
|
||||
data-subject="${absence.subject}"
|
||||
data-justified="${absence.justified}">
|
||||
<div class="absence-time">
|
||||
<span class="material-icons-round">schedule</span>
|
||||
${absence.lesson}. ${LanguageManager.t('absences.lesson').toLowerCase()}
|
||||
</div>
|
||||
<div class="absence-details">
|
||||
<div class="absence-subject">${absence.subject}</div>
|
||||
<div class="absence-topic">${absence.topic}</div>
|
||||
</div>
|
||||
<div class="absence-status ${absence.justificationStatus}">
|
||||
<table class="absences-table">
|
||||
<thead class="table-header">
|
||||
<tr>
|
||||
<th>${LanguageManager.t('absences.date')}</th>
|
||||
<th>${LanguageManager.t('absences.lesson')}</th>
|
||||
<th>${LanguageManager.t('absences.subject')}</th>
|
||||
<th>${LanguageManager.t('absences.topic')}</th>
|
||||
<th>${LanguageManager.t('absences.status')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${absences.map(absence => `
|
||||
<tr class="table-row"
|
||||
data-subject="${absence.subject}"
|
||||
data-justified="${absence.justified}"
|
||||
data-date="${absence.date}">
|
||||
<td class="table-cell date-cell" data-label="${LanguageManager.t('absences.date')}">
|
||||
${absence.date}
|
||||
</td>
|
||||
<td class="table-cell lesson-cell" data-label="${LanguageManager.t('absences.lesson')}">
|
||||
${absence.lesson}.
|
||||
</td>
|
||||
<td class="table-cell subject-cell" data-label="${LanguageManager.t('absences.subject')}">
|
||||
${absence.subject}
|
||||
</td>
|
||||
<td class="table-cell topic-cell" data-label="${LanguageManager.t('absences.topic')}" title="${absence.topic}">
|
||||
${absence.topic}
|
||||
</td>
|
||||
<td class="table-cell status-cell" data-label="${LanguageManager.t('absences.status')}">
|
||||
<span class="status-badge ${absence.justificationStatus}">
|
||||
${absence.justificationStatus === 'justified' ?
|
||||
`${LanguageManager.t('absences.justified')} <span class="material-icons-round">check_circle</span>` :
|
||||
`<span class="material-icons-round">check_circle</span> ${LanguageManager.t('absences.justified')}` :
|
||||
absence.justificationStatus === 'unjustified' ?
|
||||
`${LanguageManager.t('absences.unjustified')} <span class="material-icons-round">cancel</span>` :
|
||||
`${LanguageManager.t('absences.pending')} <span class="material-icons-round">pending</span>`}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
`<span class="material-icons-round">cancel</span> ${LanguageManager.t('absences.unjustified')}` :
|
||||
`<span class="material-icons-round">pending</span> ${LanguageManager.t('absences.pending')}`}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
@@ -188,8 +216,8 @@ function setupFilters() {
|
||||
const justified = filters.justified.value;
|
||||
const selectedDate = dateFilterValue ? new Date(dateFilterValue) : null;
|
||||
|
||||
document.querySelectorAll('.absence-group').forEach(group => {
|
||||
const dateStr = group.dataset.date;
|
||||
document.querySelectorAll('.table-row').forEach(row => {
|
||||
const dateStr = row.dataset.date;
|
||||
const dateParts = dateStr.split('.');
|
||||
|
||||
if (dateParts.length < 3) {
|
||||
@@ -206,37 +234,32 @@ function setupFilters() {
|
||||
return;
|
||||
}
|
||||
|
||||
const groupDate = new Date(parsedYear, parsedMonth, parsedDay);
|
||||
const rowDate = new Date(parsedYear, parsedMonth, parsedDay);
|
||||
|
||||
let showGroup = true;
|
||||
let showRow = true;
|
||||
|
||||
if (selectedDate) {
|
||||
if (groupDate.getFullYear() !== selectedDate.getFullYear() ||
|
||||
groupDate.getMonth() !== selectedDate.getMonth() ||
|
||||
groupDate.getDate() !== selectedDate.getDate()) {
|
||||
showGroup = false;
|
||||
if (rowDate.getFullYear() !== selectedDate.getFullYear() ||
|
||||
rowDate.getMonth() !== selectedDate.getMonth() ||
|
||||
rowDate.getDate() !== selectedDate.getDate()) {
|
||||
showRow = false;
|
||||
}
|
||||
}
|
||||
|
||||
const absenceItems = group.querySelectorAll('.absence-item');
|
||||
let visibleItems = 0;
|
||||
if (subject && row.dataset.subject !== subject) {
|
||||
showRow = false;
|
||||
}
|
||||
|
||||
absenceItems.forEach(item => {
|
||||
let showItem = true;
|
||||
if (subject && item.dataset.subject !== subject) showItem = false;
|
||||
|
||||
if (justified) {
|
||||
const statusElement = item.querySelector('.absence-status');
|
||||
const hasStatus = statusElement.classList.contains(justified);
|
||||
if (!hasStatus) showItem = false;
|
||||
}
|
||||
if (justified) {
|
||||
const statusElement = row.querySelector('.status-badge');
|
||||
const hasStatus = statusElement.classList.contains(justified);
|
||||
if (!hasStatus) showRow = false;
|
||||
}
|
||||
|
||||
item.style.display = showItem ? '' : 'none';
|
||||
if (showItem) visibleItems++;
|
||||
});
|
||||
|
||||
group.style.display = (showGroup && visibleItems > 0) ? '' : 'none';
|
||||
row.style.display = showRow ? '' : 'none';
|
||||
});
|
||||
|
||||
updateStatistics();
|
||||
} catch (err) {
|
||||
|
||||
console.error('Error during filtering absences:', err);
|
||||
@@ -270,6 +293,27 @@ function setupFilters() {
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
try {
|
||||
const visibleRows = document.querySelectorAll('.table-row:not([style*="display: none"])');
|
||||
const totalVisible = visibleRows.length;
|
||||
const justifiedVisible = Array.from(visibleRows).filter(row =>
|
||||
row.querySelector('.status-badge.justified')).length;
|
||||
const unjustifiedVisible = Array.from(visibleRows).filter(row =>
|
||||
row.querySelector('.status-badge.unjustified')).length;
|
||||
const pendingVisible = Array.from(visibleRows).filter(row =>
|
||||
row.querySelector('.status-badge.pending')).length;
|
||||
|
||||
const statCards = document.querySelectorAll('.stat-card');
|
||||
if (statCards[0]) statCards[0].querySelector('.stat-number').textContent = totalVisible;
|
||||
if (statCards[1]) statCards[1].querySelector('.stat-number').textContent = justifiedVisible;
|
||||
if (statCards[2]) statCards[2].querySelector('.stat-number').textContent = unjustifiedVisible;
|
||||
if (statCards[3]) statCards[3].querySelector('.stat-number').textContent = pendingVisible;
|
||||
} catch (err) {
|
||||
console.error('Error updating statistics:', err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (window.location.href.includes('/Hianyzas/Hianyzasok')) {
|
||||
transformAbsencesPage().catch(error => {
|
||||
|
||||
@@ -155,7 +155,10 @@
|
||||
"current_month": "Current month",
|
||||
"last_month": "Last month",
|
||||
"current_semester": "Current semester",
|
||||
"last_30_days": "Last 30 days"
|
||||
"last_30_days": "Last 30 days",
|
||||
"total_absences": "Total absences",
|
||||
"topic": "Topic",
|
||||
"status": "Status"
|
||||
},
|
||||
"profile": {
|
||||
"title": "Profile",
|
||||
|
||||
@@ -155,7 +155,10 @@
|
||||
"current_month": "Aktuális hónap",
|
||||
"last_month": "Előző hónap",
|
||||
"current_semester": "Aktuális félév",
|
||||
"last_30_days": "Utolsó 30 nap"
|
||||
"last_30_days": "Utolsó 30 nap",
|
||||
"total_absences": "Összes hiányzás",
|
||||
"topic": "Téma",
|
||||
"status": "Állapot"
|
||||
},
|
||||
"profile": {
|
||||
"title": "Profil",
|
||||
|
||||
Reference in New Issue
Block a user