import { $, api, esc, sortByName, seatsLabel, showError, renderHeader } from './common.js'; renderHeader('gruppe'); let members = []; let points = []; const form = $('#member-form'); $('#member-hascar').addEventListener('change', (e) => { $('#member-seats-wrap').hidden = !e.target.checked; }); // Auswahl "fährt am liebsten mit bei" – alle anderen Mitglieder function fillRidesWith(selfId, selected) { $('#member-rideswith').innerHTML = '' + sortByName(members.filter((m) => m.id !== selfId)) .map((m) => ``).join(''); } // Auswahl Standard-Treffpunkt function fillMemberPoint(selected) { $('#member-point').innerHTML = '' + points.map((p) => ``).join(''); } function resetForm() { form.reset(); fillRidesWith(); fillMemberPoint(); $('#member-id').value = ''; $('#member-seats-wrap').hidden = true; $('#member-cancel').hidden = true; $('#member-form-title').textContent = 'Mitglied hinzufügen'; } $('#member-cancel').addEventListener('click', resetForm); form.addEventListener('submit', async (e) => { e.preventDefault(); const body = { name: $('#member-name').value.trim(), external: $('#member-external').checked, hasCar: $('#member-hascar').checked, seats: $('#member-seats').value, alwaysDrives: $('#member-always').checked, ridesWith: $('#member-rideswith').value || null, meetingPoint: $('#member-point').value || null, }; const id = $('#member-id').value; try { if (id) await api('PUT', `/members/${id}`, body); else await api('POST', '/members', body); resetForm(); await load(); } catch (err) { showError(err); } }); function edit(id) { const m = members.find((x) => x.id === id); $('#member-id').value = m.id; $('#member-name').value = m.name; $('#member-external').checked = !!m.external; fillMemberPoint(m.meetingPoint); $('#member-hascar').checked = m.hasCar; $('#member-seats').value = m.seats || 4; $('#member-always').checked = !!m.alwaysDrives; fillRidesWith(m.id, m.ridesWith); $('#member-seats-wrap').hidden = !m.hasCar; $('#member-cancel').hidden = false; $('#member-form-title').textContent = 'Mitglied bearbeiten'; $('#member-name').focus(); window.scrollTo({ top: 0, behavior: 'smooth' }); } async function remove(id) { const m = members.find((x) => x.id === id); if (!confirm(`${m.name} wirklich aus der Gruppe löschen?`)) return; try { await api('DELETE', `/members/${id}`); await load(); } catch (err) { showError(err); } } function render() { if (!$('#member-id').value) fillRidesWith(); const nameOf = (id) => members.find((m) => m.id === id)?.name; const pointOf = (id) => points.find((p) => p.id === id)?.name; $('#members-empty').hidden = members.length > 0; $('#members-list').innerHTML = sortByName(members).map((m) => `
  • ${esc(m.name)}${m.external ? ' Extern' : ''} ${m.hasCar && pointOf(m.meetingPoint) ? `ab ${esc(pointOf(m.meetingPoint))}` : ''} ${nameOf(m.ridesWith) ? `fährt gern bei ${esc(nameOf(m.ridesWith))} mit` : ''} ${m.hasCar ? `Auto · ${seatsLabel(m.seats)}${m.alwaysDrives ? ' · fährt immer' : ''}` : 'kein Auto'}
  • `).join(''); } $('#members-list').addEventListener('click', (e) => { if (e.target.dataset.edit) edit(e.target.dataset.edit); if (e.target.dataset.del) remove(e.target.dataset.del); }); $('#export-btn').addEventListener('click', () => { const blob = new Blob([JSON.stringify(members, null, 2)], { type: 'application/json' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'hcrb-gruppe.json'; a.click(); URL.revokeObjectURL(a.href); }); $('#import-file').addEventListener('change', async (e) => { const file = e.target.files[0]; e.target.value = ''; if (!file) return; let data; try { data = JSON.parse(await file.text()); if (!Array.isArray(data)) throw new Error(); } catch { alert('Die Datei konnte nicht gelesen werden.'); return; } if (!confirm(`${data.length} Mitglieder importieren? Die aktuelle Gruppe wird ersetzt.`)) return; try { await api('POST', '/members/import', data); await load(); } catch (err) { showError(err); } }); // ---------- Treffpunkte ---------- const pointForm = $('#point-form'); function resetPointForm() { pointForm.reset(); $('#point-id').value = ''; $('#point-cancel').hidden = true; $('#point-form-title').textContent = 'Treffpunkt hinzufügen'; } $('#point-cancel').addEventListener('click', resetPointForm); pointForm.addEventListener('submit', async (e) => { e.preventDefault(); const body = { name: $('#point-name').value.trim(), address: $('#point-address').value.trim() }; const id = $('#point-id').value; try { if (id) await api('PUT', `/meeting-points/${id}`, body); else await api('POST', '/meeting-points', body); resetPointForm(); await loadPoints(); } catch (err) { showError(err); } }); function renderPoints() { $('#points-empty').hidden = points.length > 0; $('#points-list').innerHTML = points.map((p) => `
  • ${esc(p.name)} ${esc(p.address)}
  • `).join(''); } $('#points-list').addEventListener('click', async (e) => { const { edit: editId, del } = e.target.dataset; if (editId) { const p = points.find((x) => x.id === editId); $('#point-id').value = p.id; $('#point-name').value = p.name; $('#point-address').value = p.address; $('#point-cancel').hidden = false; $('#point-form-title').textContent = 'Treffpunkt bearbeiten'; $('#point-name').focus(); } if (del) { const p = points.find((x) => x.id === del); if (!confirm(`Treffpunkt „${p.name}“ wirklich löschen?`)) return; try { await api('DELETE', `/meeting-points/${del}`); await loadPoints(); } catch (err) { showError(err); } } }); async function loadPoints() { points = await api('GET', '/meeting-points'); renderPoints(); const editing = members.find((m) => m.id === $('#member-id').value); fillMemberPoint(editing ? $('#member-point').value : undefined); render(); } async function load() { members = await api('GET', '/members'); render(); } load().then(loadPoints).catch(showError);