Files
hcrb/private/js/gruppe.js
T
2026-10-10 13:54:33 +02:00

217 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = '<option value="">(keine Vorliebe)</option>'
+ sortByName(members.filter((m) => m.id !== selfId))
.map((m) => `<option value="${m.id}" ${m.id === selected ? 'selected' : ''}>${esc(m.name)}</option>`).join('');
}
// Auswahl Standard-Treffpunkt
function fillMemberPoint(selected) {
$('#member-point').innerHTML = '<option value="">(Treffpunkt der Fahrt)</option>'
+ points.map((p) => `<option value="${p.id}" ${p.id === selected ? 'selected' : ''}>${esc(p.name)}</option>`).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) => `
<li>
<span class="name">${esc(m.name)}${m.external ? ' <span class="badge">Extern</span>' : ''}</span>
${m.hasCar && pointOf(m.meetingPoint) ? `<span class="meta">ab ${esc(pointOf(m.meetingPoint))}</span>` : ''}
${nameOf(m.ridesWith) ? `<span class="meta">fährt gern bei ${esc(nameOf(m.ridesWith))} mit</span>` : ''}
<span class="badge">${m.hasCar ? `Auto · ${seatsLabel(m.seats)}${m.alwaysDrives ? ' · fährt immer' : ''}` : 'kein Auto'}</span>
<span class="actions">
<button class="link" data-edit="${m.id}">Bearbeiten</button>
<button class="link danger" data-del="${m.id}">Löschen</button>
</span>
</li>`).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) => `
<li>
<span class="name">${esc(p.name)}</span>
<span class="meta">${esc(p.address)}</span>
<span class="actions">
<button class="link" data-edit="${p.id}">Bearbeiten</button>
<button class="link danger" data-del="${p.id}">Löschen</button>
</span>
</li>`).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);