First Commit
This commit is contained in:
459
html/sternwarte/intern/anmeld/js/anmeld.js_o
Normal file
459
html/sternwarte/intern/anmeld/js/anmeld.js_o
Normal file
@@ -0,0 +1,459 @@
|
||||
// Vanilla JS Migration of anmeld.js (jQuery removed)
|
||||
|
||||
async function ladeAbsagegruende() {
|
||||
const res = await fetch('data/absagegruende.txt');
|
||||
const text = await res.text();
|
||||
return text
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.length > 0);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
// URL-Parameter lesen
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const query = {
|
||||
typ: urlParams.get('typ') || 'regular',
|
||||
storno: urlParams.get('storno') === 'true',
|
||||
double: urlParams.get('double') === 'true',
|
||||
name: urlParams.get('name') || 'Null'
|
||||
};
|
||||
|
||||
const absagegrundListe = await ladeAbsagegruende();
|
||||
const fuehrung = query.typ === 'sonnen' ? 'Sonnenführung' : 'Sternführung';
|
||||
let absagegrund = "";
|
||||
|
||||
const ajaxURL = "php/anmeldDB.php";
|
||||
const ANZAHL_DATES = query.typ === 'sonnen' ? 25 : 50;
|
||||
const TEXTE = {
|
||||
|
||||
absagetext: "Absage an alle angemeldeten Besucher senden.",
|
||||
bittegrund: "Die Führung wird abgesagt wegen:",
|
||||
schonabgesagt: "Absage schon gesendet. Nochmal senden?",
|
||||
subject: `Absage der heutigen ${fuehrung}`,
|
||||
bodytext: `Sehr geehrte Dame, sehr geehrter Herr,
|
||||
|
||||
Sie haben sich über unsere Webseite www.sternwarte-welzheim.de zur heutigen ${fuehrung} angemeldet.
|
||||
Aufgrund {absagegrund} können wir heute keine Sternführung anbieten.
|
||||
Bitte melden Sie sich für einen anderen Termin neu an.
|
||||
|
||||
Mit freundlichen Grüßen
|
||||
Beobachtergruppe Sternwarte Welzheim`,
|
||||
};
|
||||
|
||||
const liste = {
|
||||
emails: [],
|
||||
ids: []
|
||||
};
|
||||
|
||||
let abgesagt = false;
|
||||
let actualdate;
|
||||
let isSmallScreen = false
|
||||
let DateTime = luxon.DateTime
|
||||
|
||||
|
||||
function $(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
|
||||
function $all(selector) {
|
||||
return document.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
async function fetchFromDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async function putToDbase(body) {
|
||||
body.typ = query.typ;
|
||||
const response = await fetch(ajaxURL, {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/js'},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
function clearElement(el) {
|
||||
el.innerHTML = '';
|
||||
}
|
||||
|
||||
function appendHtml(el, html) {
|
||||
el.insertAdjacentHTML('beforeend', html);
|
||||
}
|
||||
|
||||
function setVisibility(id, visible) {
|
||||
$(id).style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
async function storeAbsage(ids) {
|
||||
const update = { cmd: 'UPDATE', field: 'abgesagt', ids: ids, values: [1] };
|
||||
await putToDbase(update);
|
||||
abgesagt = true;
|
||||
}
|
||||
|
||||
async function getDetailText(id) {
|
||||
const nbr = parseInt(id);
|
||||
const holit = await fetchFromDbase({cmd:'GET_TEILN_ID', id:nbr});
|
||||
const entry = holit[0];
|
||||
return `
|
||||
<div class="det">${entry.name} ${entry.vorname}<br /></div>
|
||||
<div class="det">${entry.email}<br /></div>
|
||||
<div class="det">${entry.plz} ${entry.stadt}<br /></div>
|
||||
<div class="det">${entry.strasse}<br /></div>
|
||||
<div class="det">${entry.telefon}<br /></div>
|
||||
<div class="det">${entry.remarks}<br /></div>`;
|
||||
}
|
||||
|
||||
|
||||
// Teilnehmer aus 'anmeldungen' austragen und den count in 'fdatum1' anpassen
|
||||
const austragen = async (teilnehmer) => {
|
||||
let update = {cmd: 'DELETEONE', id: parseInt(teilnehmer.id)}
|
||||
const erg1 = await putToDbase(update)
|
||||
// update = {cmd: 'UPDATECOUNT',date: parseInt(teilnehmer.fdatum), anzahl: parseInt(teilnehmer.anzahl)}
|
||||
const erg2 = await putToDbase(update)
|
||||
console.log("Storno Ergebisse: ",erg1,erg2)
|
||||
showAktAnmeldungen(actualdate)
|
||||
}
|
||||
|
||||
|
||||
async function showAktAnmeldungen(date) {
|
||||
actualdate = date;
|
||||
liste.emails = [];
|
||||
liste.ids = [];
|
||||
abgesagt = true;
|
||||
let column = query.storno ? "col-2" : "col-3";
|
||||
const anmeldungen = await fetchFromDbase({cmd:'GET_ANMELD', id:date});
|
||||
let besucher = 0;
|
||||
|
||||
clearElement($('tbody'));
|
||||
|
||||
for (let e of anmeldungen) {
|
||||
besucher += parseInt(e.anzahl);
|
||||
liste.emails.push(e.email);
|
||||
liste.ids.push(e.id);
|
||||
if (e.abgesagt !== '1') {
|
||||
abgesagt = false;
|
||||
}
|
||||
|
||||
// const selected = e.teilgenommen === "1" ? "checked" : "";
|
||||
const row = document.createElement('tr');
|
||||
row.classList.add('d-flex');
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="tdname col-6">${e.name} ${e.vorname}</td>
|
||||
<td class=${column}>${e.anzahl}</td>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<td class="col-2 tdstorno"><input type="checkbox" value="${e.id}" </td>`
|
||||
}
|
||||
|
||||
row.querySelector('.tdname').addEventListener('click', async () => {
|
||||
const detail = await getDetailText(e.id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
|
||||
if(query.storno) {
|
||||
row.querySelector('.tdstorno').addEventListener('click', function() {
|
||||
const tr = this.closest("tr") // Finds the closest row <tr>
|
||||
const index = tr.rowIndex-1
|
||||
austragen(anmeldungen[index])
|
||||
});
|
||||
}
|
||||
|
||||
$('#tabAnmeld tbody').appendChild(row);
|
||||
}
|
||||
if (abgesagt) {
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
}
|
||||
|
||||
if (besucher !== 0) {
|
||||
const sumRow = document.createElement('tr');
|
||||
sumRow.id = 'summe';
|
||||
sumRow.classList.add('d-flex');
|
||||
sumRow.innerHTML = `
|
||||
<td class="col-6">Summe der Anmeldungen</td>`
|
||||
if (query.storno) {
|
||||
sumRow.innerHTML += `<td style="text-align: center;" class="col-4">${besucher}</td>`;
|
||||
} else {
|
||||
sumRow.innerHTML += `<td class="col-3">${besucher}</td>`;
|
||||
}
|
||||
$('#tabAnmeld tbody').appendChild(sumRow);
|
||||
}
|
||||
}
|
||||
|
||||
async function findName(name) {
|
||||
const update = { cmd: 'GET_TEILN_NAME', name: name };
|
||||
let erg = await putToDbase(update);
|
||||
clearElement($('#tnames'));
|
||||
|
||||
appendHtml($('#tnames'), `
|
||||
<thead><tr>
|
||||
<th class="col-6">Name</th>
|
||||
<th class="col-2">Anzahl</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Finden</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
appendHtml($('#tnames'), `
|
||||
<tr>
|
||||
<td class="tdname col-6">${x.name} ${x.vorname}</td>
|
||||
<td class="col-2">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="tdfind col-2"><button type="button" class="findit" value="${x.id}">🔍</button></td>
|
||||
</tr>`);
|
||||
}
|
||||
appendHtml($('#tnames'), `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
|
||||
$all('.findit').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.value;
|
||||
const detail = await getDetailText(id);
|
||||
$('#detailtext').innerHTML = detail;
|
||||
$('#detaildialog').showModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$('#absagen').addEventListener('click', () => {
|
||||
$('#absagetext').innerHTML = abgesagt ? TEXTE.schonabgesagt : TEXTE.absagetext;
|
||||
$('#bittegrund').innerHTML = TEXTE.bittegrund
|
||||
$('#absagedialog').showModal();
|
||||
|
||||
const container = $('#absagegrund');
|
||||
clearElement(container);
|
||||
absagegrundListe.forEach((g, i) => {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'absageline';
|
||||
const radio = document.createElement('input');
|
||||
radio.type = 'radio';
|
||||
radio.name = 'grund';
|
||||
radio.value = i;
|
||||
radio.id = `grund${i}`;
|
||||
radio.checked = i === 0; // Default to the first option
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.setAttribute('for', `grund${i}`);
|
||||
const span = document.createElement('span');
|
||||
span.textContent = g;
|
||||
span.style.marginLeft = "20px"
|
||||
|
||||
line.appendChild(radio);
|
||||
line.appendChild(span);
|
||||
line.appendChild(document.createElement('br'));
|
||||
container.appendChild(line);
|
||||
});
|
||||
});
|
||||
|
||||
$('#absagedialog-send').addEventListener('click', async () => {
|
||||
const grundIndex = Array.from($all('input[name=grund]')).find(el => el.checked)?.value || 0;
|
||||
absagegrund = absagegrundListe[grundIndex];
|
||||
|
||||
await storeAbsage(liste.ids);
|
||||
await fetch('https://laufschrift.rexfue.de/switch/switch_on')
|
||||
|
||||
const bodyText = TEXTE.bodytext.replace("{absagegrund}", absagegrund);
|
||||
await fetchFromDbase({
|
||||
cmd: 'SENDMYMAIL',
|
||||
to: ['rexfue@gmail.com'],
|
||||
betreff: TEXTE.subject,
|
||||
body: bodyText,
|
||||
bcc: liste.emails
|
||||
});
|
||||
console.log("Gesendet an: ", liste.emails)
|
||||
$('#absagen').innerHTML = 'Absage<br />wurde gesendet';
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
$('#absagedialog-cancel').addEventListener('click', () => {
|
||||
$('#absagedialog').close();
|
||||
});
|
||||
|
||||
async function getDoubles(date) {
|
||||
const update = { cmd: 'GET_ANMELDNEW', date: date, special: "alllater" };
|
||||
let { data } = await putToDbase(update);
|
||||
|
||||
data.sort((a, b) => a.name.localeCompare(b.name));
|
||||
data.push({name: '', vorname: '', email: ''});
|
||||
|
||||
let i;
|
||||
for(i = 0; i < data.length - 1; i++) {
|
||||
data[i].single = false;
|
||||
if(data[i].name !== data[i+1].name) {
|
||||
data[i].single = true;
|
||||
} else {
|
||||
while((i < data.length - 1) && (data[i].name === data[i+1].name)) {
|
||||
if (data[i].strasse.slice(0,6).toUpperCase() !== data[i+1].strasse.slice(0,6).toUpperCase()
|
||||
|| data[i].plz !== data[i+1].plz) {
|
||||
data[i].single = true;
|
||||
break;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data[i].single = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function showDoubles(date) {
|
||||
const erg = await getDoubles(date);
|
||||
const container = $('#tnames');
|
||||
clearElement(container);
|
||||
|
||||
appendHtml(container, `
|
||||
<thead><tr>
|
||||
<th class="col-2">Name</th>
|
||||
<th class="col-2">Vorname</th>
|
||||
<th class="col-3">Email</th>
|
||||
<th class="col-1">Anz</th>
|
||||
<th class="col-2">Datum</th>
|
||||
<th class="col-2">Anmeldung</th>
|
||||
</tr></thead><tbody>`);
|
||||
|
||||
for (let x of erg) {
|
||||
if (x.single) continue;
|
||||
appendHtml(container, `
|
||||
<tr>
|
||||
<td class="tdname col-2">${x.name}</td>
|
||||
<td class="tdname col-2">${x.vorname}</td>
|
||||
<td class="tdname col-3">${x.email}</td>
|
||||
<td class="col-1">${x.anzahl}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.fdatum).toFormat('yyyy-LL-dd')}</td>
|
||||
<td class="col-2">${DateTime.fromISO(x.angemeldet).toFormat('yyyy-LL-dd')}</td>
|
||||
</tr>`);
|
||||
}
|
||||
|
||||
appendHtml(container, `</tbody>`);
|
||||
$('#names').style.display = 'block';
|
||||
}
|
||||
|
||||
function switchText() {
|
||||
const thead = document.createElement('thead');
|
||||
const row = document.createElement('tr');
|
||||
let column = query.storno ? "col-2" : "col-3"
|
||||
row.className = 'd-flex';
|
||||
|
||||
row.innerHTML = `
|
||||
<th class="col-6">Name</th>
|
||||
<th class=${column}>${isSmallScreen ? 'Anz' : 'Personen'}</th>`
|
||||
if (query.storno) {
|
||||
row.innerHTML += `<th class="col-2">Storno</th>`;
|
||||
}
|
||||
$('#versn').innerHTML = "Version: " + VERSION + ' vom ' + VDATE
|
||||
|
||||
|
||||
thead.appendChild(row);
|
||||
const table = $('#tabAnmeld');
|
||||
clearElement(table); // Leert sowohl thead als auch tbody
|
||||
table.appendChild(thead);
|
||||
table.appendChild(document.createElement('tbody'));
|
||||
}
|
||||
|
||||
// Aus dem rohen Führungsdatum von der Datenbank ein besser
|
||||
// leserliches Format erzeugen
|
||||
// Params:
|
||||
// w -> Wochentag
|
||||
// d -> Datum in DBase-Format
|
||||
// t -> Uhrzeit
|
||||
// Return
|
||||
// neu formatierter Datums-String
|
||||
const bauDate = (w,d,t) => {
|
||||
let dd = d.replace(/^(\d{4})(\d{2})(\d{2})$/, '$3.$2.$1',);
|
||||
let dt = w.substr(0,2) + ', ' + dd + ' ' + t.substr(0,2) + ':00';
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
async function buildFuehrungsDates(dates, last) {
|
||||
let n = 0;
|
||||
let i = 0;
|
||||
let summ = 0;
|
||||
let select = `<select name='ftermin' id='ftermin'>`;
|
||||
let selectedNext = false;
|
||||
const today = DateTime.now().startOf('day');
|
||||
|
||||
for (let d of dates) {
|
||||
let isselected = "";
|
||||
const fday = DateTime.fromISO(d.datum);
|
||||
if (!selectedNext && (isSameorAfter = fday >= today)) {
|
||||
selectedNext = true;
|
||||
isselected = "selected";
|
||||
n = i;
|
||||
}
|
||||
const count = await fetchFromDbase({cmd: 'GET_COUNTS', fdate: d.datum});
|
||||
const isFuehrung = (count && count > 0) ? '' : 'disabled';
|
||||
let datstr
|
||||
let grpstr
|
||||
if (query.typ == 'regular') {
|
||||
datstr = bauDate(d.wtag, d.datum, d.uhrzeit)
|
||||
grpstr = `(${d.grp})`
|
||||
} else {
|
||||
datstr = bauDate('So', d.datum, '11')
|
||||
grpstr = " "
|
||||
}
|
||||
if (isSmallScreen) {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${count || 0}B</option>`;
|
||||
} else {
|
||||
select += `
|
||||
<option value="${d.datum}" ${isselected} ${isFuehrung}> ${datstr} ${grpstr} ${count || 0} Besucher</option>`;
|
||||
}
|
||||
i++;
|
||||
summ += count ? parseInt(count) : 0;
|
||||
if (d.datum >= last) break;
|
||||
}
|
||||
select += `</select>
|
||||
<div id="gesamtsumme">Gesamtzahl der Anmeldungen (ab heute): ${summ}</div>`;
|
||||
|
||||
$('#auswahl').innerHTML = select;
|
||||
|
||||
$('#ftermin').addEventListener('change', async () => {
|
||||
const date = $('#ftermin').value;
|
||||
const index = $('#ftermin').selectedIndex;
|
||||
setVisibility('#absagen', index === 0);
|
||||
await showAktAnmeldungen(date);
|
||||
});
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
async function main(n) {
|
||||
let index = 0
|
||||
const today = DateTime.now().minus({ days: 14 }).toFormat("yyyyLLdd");
|
||||
const dates = await fetchFromDbase({cmd:'GET_DATES', anzahl:n, date: today});
|
||||
const last = await fetchFromDbase({cmd:'GET_LASTANMELDUNG', date: today});
|
||||
|
||||
let mq = window.matchMedia('(max-width: 800px)');
|
||||
isSmallScreen = mq.matches
|
||||
switchText();
|
||||
mq.addEventListener('change', async (e) => {
|
||||
isSmallScreen = e.matches
|
||||
switchText();
|
||||
await buildFuehrungsDates(dates, last);
|
||||
showAktAnmeldungen(actualdate);
|
||||
});
|
||||
|
||||
index = await buildFuehrungsDates(dates, last);
|
||||
|
||||
await showAktAnmeldungen(dates[index].datum);
|
||||
if (query.name !== 'Null') {
|
||||
await findName(query.name);
|
||||
}
|
||||
if (query.double) {
|
||||
await showDoubles(DateTime.now().toFormat("yyyyLLdd"));
|
||||
}
|
||||
}
|
||||
|
||||
main(ANZAHL_DATES).catch(console.error);
|
||||
});
|
||||
Reference in New Issue
Block a user