472 lines
18 KiB
JavaScript
472 lines
18 KiB
JavaScript
// anmeldung.js rxf 2020-10.12
|
|
// Dynamik für die Anmelde-Seite
|
|
//
|
|
|
|
$(document).ready(() => {
|
|
|
|
const ajaxURL="../DB4js.php";
|
|
const maxPersonen = 10;
|
|
|
|
const dummyTln = {
|
|
name:"Zuname{z}",
|
|
vorname:"",
|
|
email:"rxf{z}@gmx.de",
|
|
telefon:"0711123456789",
|
|
plz:"12345",
|
|
stadt:"Ort{z}",
|
|
strasse:"Straße {z}",
|
|
fid: "",
|
|
anzahl:1,
|
|
teilgenommen: 0,
|
|
remarks:"Bemerkung Nr {z}",
|
|
abgesagt: 0,
|
|
angemeldet: moment().format("YYYY-MM-DD")
|
|
};
|
|
|
|
let aktualTln = {
|
|
name:"",
|
|
vorname:"",
|
|
email:"",
|
|
telefon:"",
|
|
plz:"",
|
|
stadt:"",
|
|
strasse:"",
|
|
fid: "",
|
|
anzahl:1,
|
|
teilgenommen: 0,
|
|
remarks:"",
|
|
abgesagt: 0,
|
|
angemeldet: ""
|
|
};
|
|
|
|
const mandatory = {
|
|
name:true,
|
|
vorname:false,
|
|
email:true,
|
|
telefon:false,
|
|
plz:true,
|
|
stadt:true,
|
|
strasse:true,
|
|
fid: false,
|
|
anzahl:false,
|
|
teilgenommen: false,
|
|
remarks:false,
|
|
abgesagt: false,
|
|
angemeldet: true
|
|
};
|
|
|
|
let allParticipants = [];
|
|
let errtext = "";
|
|
|
|
|
|
// Von der Datenbank Werte abholen
|
|
// Param:
|
|
// body: Object mit cmd und param
|
|
// Return:
|
|
// angeforderte Daten als JSON
|
|
const fetchFromDbase = async (body) => {
|
|
const response = await fetch(ajaxURL,{
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/js'},
|
|
body: JSON.stringify(body)
|
|
});
|
|
return await response.json();
|
|
}
|
|
|
|
|
|
// In die Datenbank Werte eintragen
|
|
// Param:
|
|
// body: Object mit cmd und param
|
|
// Return:
|
|
// angeforderte Daten als JSON
|
|
const putToDbase = async (body) => {
|
|
const response = await fetch(ajaxURL,{
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/js'},
|
|
body: JSON.stringify(body)
|
|
});
|
|
return await response.json();
|
|
}
|
|
|
|
|
|
// Beim Senden der Anmeldeseite die Nummer der Führung mit schicken
|
|
$('form').submit((event) => {
|
|
let nr = $('#ftermin').find(':selected');
|
|
console.log('nr: ', nr[0].value);
|
|
$('#fid').val(nr[0].value);
|
|
});
|
|
|
|
|
|
// zum Testen die Anmelde-Seite automatisch ausfüllen
|
|
$('#autofillbutton').click(() => {
|
|
let rand = Math.floor(Math.random() * 100);
|
|
for (let f in dummyTln) {
|
|
if (f=='fid') {
|
|
continue;
|
|
}
|
|
let x = dummyTln[f].toString();
|
|
aktualTln[f] = x.replace("{z}",rand);
|
|
$('#'+f).val(x.replace("{z}",rand));
|
|
}
|
|
});
|
|
|
|
|
|
// Aus dem rohen Führungsdatum von der Datenbank ein besser
|
|
// leserliches Format erzeugen
|
|
// Params:
|
|
// w -> Wocjentag
|
|
// 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',);
|
|
return w.substr(0,2) + ', ' + dd + ' ' + t;
|
|
}
|
|
|
|
|
|
// Aus der Datenbank die nächsten 'n' Führungsdaten holen und
|
|
// in den <option>-Tags anzeigen.
|
|
// Zusätzlich für jeden Tag zählen, wieviel schon angemeldet sind.
|
|
// Sind es >= 10, dass diese <option> als "disbaled" markieren.
|
|
// Die Anzahl der noch freien Plätze mit anzeigen
|
|
async function buildfuehrungdates(n) {
|
|
const dates = await fetchFromDbase({cmd:'GET_DATES',anzahl:n, fid:0});
|
|
|
|
str = "";
|
|
for (let d of dates) {
|
|
const count = await fetchFromDbase({cmd: 'GET_COUNTS', fid: d.fid});
|
|
str += `<option ${count >= maxPersonen ? "disabled" : ""} ` +
|
|
`value=${d.fid}> ${bauDate(d.weekday, d.date, d.time)} Frei: ${maxPersonen - count}</>`;
|
|
}
|
|
$('#fid').append(str);
|
|
}
|
|
|
|
|
|
// Mit der fid das Führungsdatum aus der DB holen und in leserliche
|
|
// Form umsetzen
|
|
// Params:
|
|
// fid -> ID des Eintrages in der DB
|
|
// Return
|
|
// String mit dem Führungsdatum
|
|
const getfdateformatted = async (fid) => {
|
|
const nxd = await fetchFromDbase({cmd: 'GET_DATES', anzahl: 1, fid: fid});
|
|
let newdate = bauDate(nxd[0].weekday, nxd[0].date, nxd[0].time);
|
|
return newdate.replace(/(\d+) Uhr/, "um $1 Uhr");
|
|
}
|
|
|
|
// Infomail über die Anmeldung bzw. Stornierung an rexfue@gmail.com senden
|
|
// Parameters:
|
|
// storno -> true: Stornierung, fals: Anmeldung
|
|
const sendInfoMail = async(storno) => {
|
|
const fdatum = await getfdateformatted(aktualTln.fid);
|
|
const subj = storno ? "Stornierung einer Stern-Führung" : "Neue Anmeldung zu einer Stern-Führung";
|
|
const ret = await putToDbase({
|
|
cmd: 'SEND_INFO_MAIL',
|
|
to: 'rexfue@gmail.com',
|
|
subject: subj,
|
|
body: '<html>' +
|
|
'<body><table>' +
|
|
'<tr><td>Name, Vorname</td><td style="text-align: right;">' + aktualTln.name + ', ' + aktualTln.vorname + '</td></tr>' +
|
|
'<tr><td>Strasse</td><td style="text-align: right;">' + aktualTln.strasse + '</td></tr>' +
|
|
'<tr><td>Ort</td><td style="text-align: right;">' + aktualTln.plz + ', ' + aktualTln.stadt + '</td></tr>' +
|
|
'<tr><td>Telefon</td><td style="text-align: right;">' + aktualTln.telefon + '</td></tr>' +
|
|
'<tr><td>E-mail</td><td style="text-align: right;">' + aktualTln.email + '</td></tr>' +
|
|
'<tr><td>Termin</td><td style="text-align: right;">' + fdatum + '</td></tr>' +
|
|
'<tr><td>Personen</td><td style="text-align: right;">' + aktualTln.anzahl + '</td></tr>' +
|
|
'<tr><td>Bemerkungen</td><td class="fr">' + aktualTln.remarks + '</td></tr>' +
|
|
'</table></body></html>'
|
|
});
|
|
}
|
|
|
|
|
|
// Bestätigungsmail an den Anmeldeneden senden
|
|
// Params:
|
|
// storno -> true: Stornierung, fals: Anmeldung
|
|
const sendConfirmation = async (storno) => {
|
|
const fdatum = await getfdateformatted(aktualTln.fid);
|
|
let body = "Sehr geehrte Dame, sehr geehrter Herr, \r\n\r\nhiermit bestätigen wir Ihre "
|
|
body += storno ? "Stornierung der " : "";
|
|
body += "Anmeldung zu der Führung auf der Sternwarte Welzheim am\r\n\r\n" +
|
|
`${fdatum} für ${aktualTln.name} ${aktualTln.vorname} mit ${aktualTln.anzahl} ${aktualTln.anzahl==1?"Person.":"Personen."}` +
|
|
"\r\n\r\n";
|
|
if (!storno) {
|
|
body +=
|
|
"Bitte bringen Sie diese Bestätigung als Ausdruck oder digital zur Führung mit. \r\n" +
|
|
"Ohne diese Bestätigung erfolgt ausnahmslos k e i n Einlass.\r\n\r\n" +
|
|
"Falls Sie den Führungstermin absagen wollen, verwenden Sie bitte folgenden Link \r\n";
|
|
body += develop == "true" ?
|
|
"http://localhost:8082/anmeldung.php?storno=" :
|
|
"https://sternwarte-welzheim.de/anmeldung.php?storno=";
|
|
body += md5(aktualTln.email + aktualTln.fid) + "\n\r";
|
|
body += "Die Führung findet NUR bei sternklarem Himmel statt. Falls der Himmel bedeckt ist \r\n" +
|
|
"und die Führung ausfällt, bitten wir Sie um eine neue Anmeldung.\r\n\r\n" +
|
|
"Die Hygienevorschriften sind zu beachten: Die Teilnehmer/-innen müssen Gesichtsmasken \r\n" +
|
|
"tragen und den vorgeschriebenen Abstand halten. " +
|
|
"Nicht teilnehmen dürfen Personen, \r\ndie in den letzten vierzehn Tagen Kontakt " +
|
|
"mit einem Coronavirus-Infizierten \r\nhatten oder Infektionssymptome zeigen.\r\n\r\n";
|
|
}
|
|
body += "Mit freundlichen Grüßen\r\n\r\n" +
|
|
"Beobachterteam der Sternwarte Welzheim\r\n\r\n" +
|
|
"www.sternwarte-welzheim.de"
|
|
const ret = await putToDbase({
|
|
cmd: 'SEND_MAIL',
|
|
to: aktualTln.email,
|
|
subject: storno ?
|
|
"Stornierung Ihrer Anmeldung zu einer Führung auf der Sternwarte Welzheim" :
|
|
"Anmeldung zu einer Führung auf der Sternwarte Welzheim",
|
|
body: body,
|
|
});
|
|
console.log("hier wird die Email gesendet");
|
|
sendInfoMail(storno);
|
|
}
|
|
|
|
|
|
// MD5-Hash ausrechnen
|
|
const md5 = (value) => {
|
|
return CryptoJS.MD5(value).toString();
|
|
}
|
|
|
|
|
|
// Den neuen Teilnehmer in die DB eintragen
|
|
const insertEntry = async () => {
|
|
let ret = await putToDbase({cmd: 'INSERT_TLN', data: aktualTln})
|
|
sendConfirmation(false);
|
|
}
|
|
|
|
|
|
// Den Teilnehmer mit der ID id aus der DB löschen
|
|
const deleteEntry = async (id) => {
|
|
let ret = await putToDbase({cmd: 'DELETE_TLN', id:id});
|
|
return ret;
|
|
}
|
|
|
|
|
|
// Den Teilnehmer mit der ID id mit den neuen Daten versorgen
|
|
const updateEntry = async (id) => {
|
|
let ret = await putToDbase({cmd: 'UPDATE_TLN', data: aktualTln, id: id })
|
|
sendConfirmation(false);
|
|
}
|
|
|
|
|
|
// Dialogbox für 'doppelt eingetragen'
|
|
$("#dialogdoppelt").dialog({
|
|
dialogClass: 'no-close',
|
|
autoOpen: false,
|
|
closeOnEscape: false,
|
|
width: 700,
|
|
modal: true,
|
|
position: 'center',
|
|
title: 'Doppelter Eintrag',
|
|
open: () => {
|
|
showdoppelText();
|
|
},
|
|
buttons: [
|
|
{
|
|
text: 'Auswahl übernehmen',
|
|
click: async function() {
|
|
let gewaehlt = [];
|
|
$.each($("input[name='dopp']:checked"), function() {
|
|
gewaehlt.push($(this).val());
|
|
});
|
|
let tln = $("#dialogdoppelt").data('fids').otln;
|
|
if (gewaehlt.length === 1) {
|
|
if (gewaehlt[0] == "new") {
|
|
deleteEntry($("#dialogdoppelt").data('fids').otln.id);
|
|
insertEntry();
|
|
tln = $("#dialogdoppelt").data('fids').ntln;
|
|
}
|
|
} else {
|
|
insertEntry();
|
|
tln = $("#dialogdoppelt").data('fids').ntln;
|
|
}
|
|
$(this).dialog('close');
|
|
let meld = await afterDialogtext(tln);
|
|
$('#mainContent').html(meld);
|
|
$('#mainContent').css('height','430px');
|
|
}
|
|
}
|
|
]
|
|
}).prev(".ui-dialog-titlebar").css("background","red");
|
|
|
|
|
|
// Der Eintrag wird jetzt doppelt: dieses melden in einer
|
|
// kleinen Dialog-Box
|
|
function showDoppelt(oldone, newone) {
|
|
$('#dialogdoppelt').data('fids', {otln: oldone, ntln: newone}).dialog('open');
|
|
|
|
}
|
|
|
|
|
|
// Text für doppelten Eintrag anzeigen
|
|
async function showdoppelText() {
|
|
const ofdate = await fetchFromDbase({
|
|
cmd: 'GET_ONE_DATE',
|
|
fid: $("#dialogdoppelt").data('fids').otln.fid
|
|
});
|
|
const nfdate = await fetchFromDbase({
|
|
cmd: 'GET_ONE_DATE',
|
|
fid: $("#dialogdoppelt").data('fids').ntln.fid
|
|
});
|
|
$('#dialogdoppelttext').html('Sie haben sich doppelt eingetragen.<br />' +
|
|
'Wenn das so gewollt ist, dann kreuzen Sie bitte unten beide Führungen an,<br />' +
|
|
'andernfalls nur diejenige, an der Sie wirklich teilnehmen wollen.<br /> <br />' +
|
|
'<input type="checkbox" name="dopp" value="new" checked style="margin-right:10px;">' +
|
|
bauDate(nfdate.wtag, nfdate.datum, nfdate.uhrzeit) + '<br />' +
|
|
'<input type="checkbox" value="old" name="dopp" style="margin-right:10px;">' +
|
|
bauDate(ofdate.wtag, ofdate.datum, ofdate.uhrzeit) + '<br />');
|
|
}
|
|
|
|
const errnum = {'no':1, 'error':2, 'double':3};
|
|
|
|
|
|
// Alle Einträge auf Plausibilität prüfen
|
|
// Return:
|
|
// Object mit:
|
|
// error: 'true', 'false'
|
|
// action: 'store', 'exit', 'none'
|
|
async function checkPlausibilität() {
|
|
let error = false;
|
|
// Zuerst prüfen, ob auch alle notwendigen Felder ausgefüllt sind
|
|
for (let feld in aktualTln) {
|
|
aktualTln[feld] = $('#' + feld).val(); // Feld des actualTln auf dem Wert setzen
|
|
if (!mandatory[feld]) {
|
|
continue;
|
|
}
|
|
if (aktualTln[feld] == "") { // Falls das Feld leer ist, den Rahmen
|
|
$('#' + feld).css('border-color', 'red'); // rot machen und das
|
|
error = true; // errorfralg setzen
|
|
}
|
|
}
|
|
if (error) { // wenn Error, dieses melden
|
|
errtext = "Bitte korrigieren Sie die fehlenden Einträge in den rot umrandeten Feldern";
|
|
return errnum.error; // und raus
|
|
}
|
|
// Als Nächstes die PLZ prüfen: Das müssen 5 Ziffern sein
|
|
const plz = $('#plz').val();
|
|
let re = RegExp(/^[0-9]{5}$/);
|
|
if(!re.test(plz)) {
|
|
$('#plz').css('border-color', 'red');
|
|
errtext = "Bitte geben Sie bei der Postleitzahl mindestens fünf Ziffern und keine Buchstaben ein";
|
|
return errnum.error; // und raus
|
|
}
|
|
// Die Email prüfen
|
|
re = RegExp(/^[a-z0-9]+([-_\.]?[a-z0-9])+@[a-z0-9]+([-_\.]?[a-z0-9])+\.[a-z]{2,4}/);
|
|
let mail = $('#email').val().toLowerCase();
|
|
if(!re.test(mail)) {
|
|
$('#email').css('border-color', 'red');
|
|
errtext = "Bitte geben Sie eine gültige E-Mail-Adresse ein";
|
|
return errnum.error; // und raus
|
|
}
|
|
// Nun noch doppelte Einträge checken
|
|
// dazu prüfen, ob die email_Adresse in den Teilnehmern schon enthalten ist
|
|
const aktMail = aktualTln.email;
|
|
let allParticipants = await fetchAlleTln();
|
|
const find = allParticipants.findIndex((f) => f.email === aktMail);
|
|
if (find == -1) {
|
|
insertEntry();
|
|
return errnum.no;
|
|
}
|
|
let oldTln = allParticipants[find];
|
|
// Email enthalten. Ist der Führungstag identisch? Wenn ja, dann einfach die neuen
|
|
// Werte eintragen (also überschreiben)
|
|
if (aktualTln.fid === oldTln.fid) {
|
|
updateEntry(oldTln.id);
|
|
return errnum.no;
|
|
} else {
|
|
// Hier nun 'Doppelt' melden
|
|
showDoppelt(oldTln, aktualTln);
|
|
return errnum.double;
|
|
}
|
|
return errnum.no;
|
|
}
|
|
|
|
|
|
// Text für den Dialog der Anmeldung
|
|
const afterDialogtext = async(tln) => {
|
|
let fdate = await getfdateformatted(tln.fid);
|
|
return '<p>Vielen Dank für Ihre Anmeldung. <br /><br />' +
|
|
'Wir freuen uns über Ihren Besuch auf der Sternwarte Welzheim am<br /> ' +
|
|
'<div id="antwort_fdatum" style="text-align:center;">' +
|
|
`${fdate} mit ${tln.anzahl} ${tln.anzahl == 1 ? "Person" : "Personen"}` +
|
|
'</div> <br />' +
|
|
'Wir haben Ihnen die Anmelde-Bestätigung per Email zugesandt.</p>' +
|
|
'<p><a class="button" href="/index.php">Zurück</a></p>';
|
|
}
|
|
|
|
|
|
// Formular ist ausgefüllt - der Anmelde-Knopf wurde gerdückt.
|
|
// Alle Eingaben in den aktuelTln eintragen und dann
|
|
// eine Plausibilitäts-Prüfung durchführen und wenn Alles
|
|
// OK ist, die Einträge in die Datenbank schreiben
|
|
$('input[name="submit"]').click(async () => {
|
|
$('#errordiv').css('visibility','hidden'); // erst mal die evtl. vorhandenen Fehlermeldung
|
|
for ( let f in aktualTln) { // löschen und alle Rahmen
|
|
$('#'+f).css('border-color','black'); // wieder schwarz machen
|
|
}
|
|
let nr = $('#fid').find(':selected');
|
|
aktualTln.fid = nr[0].value; // selektiertes Führungsdatum merken
|
|
const ret = await checkPlausibilität();
|
|
if (ret === errnum.error) {
|
|
$('#errordiv').html(errtext);
|
|
$('#errordiv').css('visibility', 'visible');
|
|
} else if (ret === errnum.no) {
|
|
let meld = await afterDialogtext(aktualTln);
|
|
$('#mainContent').html(meld);
|
|
$('#mainContent').css('height','430px');
|
|
}
|
|
});
|
|
|
|
|
|
// Storno
|
|
// Der Link für die Stornierung wurde aufgerufen:
|
|
// Zuerst die email-Adresse suchen (mit Hilfe des übergebenen md5-hash),
|
|
// dann die Stornierung anzeigen und dann noch eine Bestätigung senden
|
|
const doStorno = async(md5hash) => {
|
|
let emails = await fetchFromDbase({cmd:'GET_ALL_EMAILS'});
|
|
for (let em of emails) {
|
|
if(md5((em.email+em.fid)) == md5hash) {
|
|
// komplette Info dieses teilnehmers holen
|
|
let teilnehmer = await fetchFromDbase({cmd: 'GET_TEILN', id: em.id, isid: true});
|
|
aktualTln = Object.assign({}, teilnehmer[0]);
|
|
// Löschen des Eintrages
|
|
let ret = putToDbase({cmd:'DELETE_TLN', id: em.id});
|
|
// Meldung anzeigen
|
|
let fdate = await getfdateformatted(em.fid);
|
|
let meld = '<p><h1 style="text-align:center">Stornierung</h1><br />' +
|
|
'Ihre Anmeldung für die Führung auf der Sternwarte Welzheim am<br /><br />' +
|
|
'<div id="antwort_fdatum" style="text-align:center;">' +
|
|
`${fdate} mit ${aktualTln.anzahl} ${aktualTln.anzahl == 1 ? "Person" : "Personen"}` +
|
|
'</div> <br />' +
|
|
'wurde storniert.<br /><br /> Wir haben Ihnen die Stornierungs-Bestätigung per Email zugesandt.</p>' +
|
|
'<p><a class="button" href="/index.php">Zurück</a></p>';
|
|
$('#mainContent').html(meld);
|
|
$('#mainContent').css('height','430px');
|
|
sendConfirmation(true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Alle eingetragenen Teilnehmer ab 'morgen' in das globale Array einlesen
|
|
const fetchAlleTln = async () => {
|
|
const nxtDate = await fetchFromDbase({cmd: 'GET_DATES', anzahl: 1, fid:0});
|
|
return await fetchFromDbase({cmd: 'GET_ALLTEILN', fid: nxtDate[0].fid});
|
|
}
|
|
|
|
|
|
async function main() {
|
|
// Falls Storno angefordert, dann anzeigen
|
|
if(md5Hash != "") {
|
|
await doStorno(md5Hash);
|
|
return;
|
|
}
|
|
// Alle eingetragenen Teilnehmer ab 'morgen' in das globale Array einlesen
|
|
// die nächste 30 Führungsdaten anzeigen
|
|
buildfuehrungdates(30);
|
|
}
|
|
|
|
main().catch(console.err);
|
|
|
|
});
|