{% extends "base.html" %} {% block title %}{% if is_edit %}Edytuj posiedzenie{% else %}Nowe posiedzenie{% endif %} - Strefa RADA{% endblock %} {% block extra_css %} {% endblock %} {% block content %}
Powrót do listy posiedzeń

{% if is_edit %}Edytuj posiedzenie {{ meeting.meeting_identifier }}{% else %}Nowe posiedzenie Rady Izby{% endif %}

{% if is_edit %}Zaktualizuj dane posiedzenia{% else %}Wypełnij dane programu i protokołu posiedzenia{% endif %}

Dane posiedzenia

Pracownik biura odpowiedzialny za sporządzenie protokołu

Program posiedzenia

Dodaj punkty programu z planowanymi godzinami.

Lista obecności

Kworum: Minimum 9 z 16 członków Rady (większość bezwzględna).
Kworum oblicza się automatycznie na podstawie listy obecności.
0/16

Dla każdego członka wybierz status obecności i wpisz inicjały do protokołu.

{% for member in board_members %} {% set member_attendance = form_data.get('attendance', {}).get(member.id|string, {}) %} {% set status = member_attendance.get('status', 'unknown') %}
{{ member.name or member.email.split('@')[0] }}
{% endfor %}

Przebieg posiedzenia i ustalenia

Dla każdego punktu programu opisz przebieg dyskusji i podjęte ustalenia.

Anuluj
{% endblock %} {% block extra_js %} // Anty double/triple-click — blokada wielokrotnego submitu (function() { const form = document.getElementById('meetingForm'); if (!form) return; form.addEventListener('submit', function(e) { const btns = form.querySelectorAll('button[type="submit"]'); if (Array.from(btns).some(function(b) { return b.disabled; })) { e.preventDefault(); return; } btns.forEach(function(b) { b.dataset.originalText = b.innerHTML; b.disabled = true; b.textContent = 'Wysyłanie...'; }); }); })(); // Tab switching document.querySelectorAll('.form-tab').forEach(tab => { tab.addEventListener('click', function() { document.querySelectorAll('.form-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); this.classList.add('active'); document.getElementById('tab-' + this.dataset.tab).classList.add('active'); }); }); // Agenda Items let agendaItems = {{ form_data.get('agenda_items', [])|tojson|safe }}; // Default items if empty if (agendaItems.length === 0) { agendaItems = [ { time_start: '16:00', time_end: '16:10', title: 'Otwarcie posiedzenia i akceptacja programu' }, { time_start: '16:10', time_end: '16:15', title: 'Zbieranie kworum' }, { time_start: '', time_end: '', title: '' }, { time_start: '', time_end: '', title: 'Wolne wnioski i sprawy różne' }, { time_start: '', time_end: '', title: 'Ustalenie daty kolejnego posiedzenia' }, { time_start: '', time_end: '', title: 'Zamknięcie posiedzenia' } ]; } function renderAgendaItems() { const list = document.getElementById('agendaItemsList'); list.innerHTML = ''; agendaItems.forEach((item, index) => { const div = document.createElement('div'); div.className = 'agenda-item'; div.innerHTML = ` `; list.appendChild(div); }); updateAgendaJson(); renderProceedings(); } function addAgendaItem() { agendaItems.push({ time_start: '', time_end: '', title: '' }); renderAgendaItems(); } function removeAgendaItem(index) { agendaItems.splice(index, 1); renderAgendaItems(); } function updateAgendaItem(index, field, value) { agendaItems[index][field] = value; updateAgendaJson(); if (field === 'title') { renderProceedings(); } } function updateAgendaJson() { document.getElementById('agendaItemsJson').value = JSON.stringify(agendaItems); } // Proceedings let proceedings = {{ form_data.get('proceedings', [])|tojson|safe }}; // Helper: convert array to text (one item per line) function arrayToText(arr) { if (!arr) return ''; if (typeof arr === 'string') return arr; if (Array.isArray(arr)) return arr.join('\n'); return ''; } // Helper: convert text to array (split by newlines, filter empty) function textToArray(text) { if (!text) return []; return text.split('\n').map(s => s.trim()).filter(s => s.length > 0); } // Helper: get discussion text (supports both field names) function getDiscussion(proc) { return proc.discussion || proc.discussed || ''; } function renderProceedings() { const list = document.getElementById('proceedingsList'); list.innerHTML = ''; agendaItems.forEach((item, index) => { if (!item.title) return; const proc = proceedings.find(p => p.agenda_item === index) || {}; const discussion = getDiscussion(proc); const decisionsText = arrayToText(proc.decisions); const tasksText = arrayToText(proc.tasks); const isFilled = discussion || decisionsText || tasksText; const div = document.createElement('div'); div.className = 'proceeding-item'; div.dataset.index = index; div.innerHTML = `
${index + 1} ${escapeHtml(item.title)} ${isFilled ? '' : ''}
Każda decyzja w osobnej linii
Każde zadanie w osobnej linii (osoba – opis – termin)
`; list.appendChild(div); }); } function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function toggleProceeding(header) { header.closest('.proceeding-item').classList.toggle('collapsed'); } function updateStatusIcon(textarea) { const item = textarea.closest('.proceeding-item'); const textareas = item.querySelectorAll('textarea'); const hasContent = Array.from(textareas).some(ta => ta.value.trim().length > 0); const icon = item.querySelector('.proceeding-status-icon'); if (hasContent) { icon.classList.remove('empty'); icon.classList.add('filled'); icon.innerHTML = ''; } else { icon.classList.remove('filled'); icon.classList.add('empty'); icon.innerHTML = ''; } } function updateProceeding(agendaIndex, field, value) { let proc = proceedings.find(p => p.agenda_item === agendaIndex); if (!proc) { proc = { agenda_item: agendaIndex, title: agendaItems[agendaIndex]?.title || '', discussion: '', decisions: [], tasks: [] }; proceedings.push(proc); } if (field === 'decisions' || field === 'tasks') { proc[field] = textToArray(value); } else { proc[field] = value; // Normalize old field name if (field === 'discussion') { delete proc.discussed; } } proc.title = agendaItems[agendaIndex]?.title || ''; updateProceedingsJson(); } function updateProceedingsJson() { document.getElementById('proceedingsJson').value = JSON.stringify(proceedings); } // Initialize renderAgendaItems(); // Attendance status management function setAttendanceStatus(memberId, status, button) { // Update hidden input const row = button.closest('.attendance-row'); row.querySelector('.attendance-status-input').value = status; // Update button states row.querySelectorAll('.status-btn').forEach(btn => btn.classList.remove('active')); button.classList.add('active'); // Recalculate quorum updateQuorumCount(); } function updateQuorumCount() { const presentCount = document.querySelectorAll('.status-btn.present.active').length; const totalMembers = 16; const quorumRequired = 9; const countEl = document.getElementById('quorumCount'); const infoEl = document.getElementById('quorumInfo'); countEl.textContent = presentCount + '/' + totalMembers; if (presentCount >= quorumRequired) { infoEl.classList.add('quorum-achieved'); countEl.innerHTML = presentCount + '/' + totalMembers + ' '; } else { infoEl.classList.remove('quorum-achieved'); } } // Initialize quorum count on page load updateQuorumCount(); // Update JSON before submit document.getElementById('meetingForm').addEventListener('submit', function() { updateAgendaJson(); updateProceedingsJson(); }); {% endblock %}