Wetier am Cahstity game gebasterln
This commit is contained in:
@@ -113,6 +113,78 @@
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
/* Task Vote Section */
|
||||
.task-vote-section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.task-vote-section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.task-vote-card {
|
||||
background: var(--color-card);
|
||||
border: 1px solid rgba(52,152,219,0.35);
|
||||
border-radius: 10px;
|
||||
padding: 0.85rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.task-vote-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.task-vote-lockee {
|
||||
font-weight: 600;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.task-vote-expires {
|
||||
font-size: 0.78rem;
|
||||
color: var(--color-muted);
|
||||
}
|
||||
.task-vote-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.task-vote-btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: rgba(52,152,219,0.08);
|
||||
border: 1px solid rgba(52,152,219,0.25);
|
||||
border-radius: 7px;
|
||||
padding: 0.45rem 0.7rem;
|
||||
cursor: pointer;
|
||||
color: var(--color-text);
|
||||
text-align: left;
|
||||
font-size: 0.85rem;
|
||||
transition: background 0.15s, border-color 0.15s;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.task-vote-btn:hover:not(:disabled) {
|
||||
background: rgba(52,152,219,0.22);
|
||||
border-color: rgba(52,152,219,0.5);
|
||||
}
|
||||
.task-vote-btn.my-vote {
|
||||
border-color: var(--color-primary);
|
||||
background: rgba(52,152,219,0.18);
|
||||
}
|
||||
.task-vote-btn:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
.task-vote-count {
|
||||
font-size: 0.78rem;
|
||||
color: var(--color-muted);
|
||||
white-space: nowrap;
|
||||
margin-left: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
color: var(--color-muted);
|
||||
font-size: 0.9rem;
|
||||
@@ -133,7 +205,16 @@
|
||||
<div class="content">
|
||||
|
||||
<div class="page-title">Community Votes</div>
|
||||
<div class="page-subtitle">Verifikationen - stimme ab</div>
|
||||
<div class="page-subtitle">Verifikationen & Aufgaben-Abstimmungen</div>
|
||||
|
||||
<!-- Aktive Aufgaben-Abstimmungen -->
|
||||
<div class="task-vote-section" id="taskVoteSection" style="display:none;">
|
||||
<div class="task-vote-section-title">🃏 Aufgaben-Abstimmungen</div>
|
||||
<div id="taskVoteList"></div>
|
||||
</div>
|
||||
|
||||
<div class="page-title" style="font-size:1rem;margin-bottom:0.25rem;">Verifikationen</div>
|
||||
<div class="page-subtitle" style="margin-bottom:0.75rem;">Stimme ab, ob die Verifikation gültig ist</div>
|
||||
|
||||
<div class="vote-grid" id="voteGrid"></div>
|
||||
<div class="load-spinner" id="loadSpinner" style="display:none;">Lädt…</div>
|
||||
@@ -146,6 +227,83 @@
|
||||
<script src="/js/sidebar.js"></script>
|
||||
<script src="/js/social-sidebar.js"></script>
|
||||
<script>
|
||||
// ── Aufgaben-Abstimmungen ──────────────────────────────────────────────────
|
||||
|
||||
function esc(s) {
|
||||
return String(s || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
function fmtDateTime(isoStr) {
|
||||
return new Date(isoStr).toLocaleString('de-DE', {day:'2-digit',month:'2-digit',year:'numeric',hour:'2-digit',minute:'2-digit'});
|
||||
}
|
||||
|
||||
async function loadTaskVotes() {
|
||||
try {
|
||||
const res = await fetch('/task-card/community/votes');
|
||||
if (!res.ok) return;
|
||||
const votes = await res.json();
|
||||
const section = document.getElementById('taskVoteSection');
|
||||
const list = document.getElementById('taskVoteList');
|
||||
list.innerHTML = '';
|
||||
if (votes.length === 0) {
|
||||
section.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
section.style.display = '';
|
||||
votes.forEach(vote => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'task-vote-card';
|
||||
card.dataset.voteSessionId = vote.voteSessionId;
|
||||
|
||||
let optionsHtml = '';
|
||||
(vote.tasks || []).forEach((t, i) => {
|
||||
const count = (vote.voteCounts || [])[i] || 0;
|
||||
const isMyVote = vote.myVote === i;
|
||||
const alreadyVoted = vote.myVote !== null && vote.myVote !== undefined;
|
||||
const desc = t.description ? `<div style="font-size:0.75rem;color:var(--color-muted);margin-top:0.1rem;">${esc(t.description)}</div>` : '';
|
||||
const mins = t.minutes > 0 ? ` <span style="font-size:0.75rem;color:var(--color-muted);">⏱ ${t.minutes} Min.</span>` : '';
|
||||
optionsHtml += `<button class="task-vote-btn ${isMyVote ? 'my-vote' : ''}"
|
||||
id="tvbtn-${vote.voteSessionId}-${i}"
|
||||
${alreadyVoted ? 'disabled' : ''}
|
||||
onclick="castTaskVote('${vote.voteSessionId}', ${i})">
|
||||
<div style="flex:1;min-width:0;">
|
||||
<div style="font-weight:600;">${esc(t.title)}${mins}</div>
|
||||
${desc}
|
||||
</div>
|
||||
<span class="task-vote-count" id="tvcount-${vote.voteSessionId}-${i}">${count} Stimme${count !== 1 ? 'n' : ''}</span>
|
||||
</button>`;
|
||||
});
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="task-vote-header">
|
||||
<span class="task-vote-lockee">🔒 ${esc(vote.lockeeName)}</span>
|
||||
<span class="task-vote-expires">Endet: ${fmtDateTime(vote.expiresAt)}</span>
|
||||
</div>
|
||||
<div class="task-vote-options">${optionsHtml}</div>`;
|
||||
list.appendChild(card);
|
||||
});
|
||||
} catch(e) { console.error(e); }
|
||||
}
|
||||
|
||||
async function castTaskVote(voteSessionId, taskIndex) {
|
||||
// Disable all buttons for this vote immediately
|
||||
document.querySelectorAll(`[id^="tvbtn-${voteSessionId}-"]`).forEach(btn => btn.disabled = true);
|
||||
|
||||
const res = await fetch(`/task-card/community/votes/${voteSessionId}/vote/${taskIndex}`, { method: 'POST' });
|
||||
if (res.ok || res.status === 204) {
|
||||
const countEl = document.getElementById(`tvcount-${voteSessionId}-${taskIndex}`);
|
||||
if (countEl) {
|
||||
const current = parseInt(countEl.textContent) || 0;
|
||||
const next = current + 1;
|
||||
countEl.textContent = `${next} Stimme${next !== 1 ? 'n' : ''}`;
|
||||
}
|
||||
const btn = document.getElementById(`tvbtn-${voteSessionId}-${taskIndex}`);
|
||||
if (btn) btn.classList.add('my-vote');
|
||||
}
|
||||
}
|
||||
|
||||
// ── Verifikations-Votes ───────────────────────────────────────────────────
|
||||
|
||||
let page = 0;
|
||||
let loading = false;
|
||||
let exhausted = false;
|
||||
@@ -243,6 +401,7 @@
|
||||
}, { rootMargin: '200px' });
|
||||
observer.observe(document.getElementById('sentinel'));
|
||||
|
||||
loadTaskVotes();
|
||||
loadPage();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user