Vier Ansichten in einer Seite: Anmeldung, Passwort festlegen ueber den
Einladungslink, Uebersicht, Projektdetail. 71 Textbausteine in fuenf
Sprachen.
Korrektur an einer frueheren Entscheidung: Ich hatte das Portal als "nur
Deutsch" eingestuft wie die Verwaltung. Denkfehler -- die Verwaltung
nutzen Dogfather und VanVan, das PORTAL nutzen Kunden, und die koennen
Franzosen oder Portugiesen sein. Jetzt fuenfsprachig, und die Sprache des
Kunden wird bei der Anmeldung automatisch uebernommen.
Gestaltungsentscheidungen:
* Eine Phasenleiste zeigt auf einen Blick, wo das Projekt steht. Das ist
die haeufigste Frage ueberhaupt und der Grund, warum Kunden anrufen.
Bei pausierten oder abgebrochenen Projekten wird KEINE Leiste gezeigt --
ein Fortschrittsbalken waere dort irrefuehrend.
* Eine Marke sagt, wer gerade am Zug ist ("Wir warten auf dich" /
"Dogfather ist dran"). Das beendet die haeufigste Unklarheit im
Projektverlauf.
* Offene Zahlungen stehen ganz oben und in Gold -- das Einzige, was den
Kunden wirklich zum Handeln auffordert.
* Rueckfrage nur beim ANNEHMEN eines Zusatzangebots, nicht beim Ablehnen.
Annehmen erzeugt eine Zahlungspflicht, Ablehnen ist folgenlos.
* Abgelaufene Sitzung fuehrt zur Anmeldung mit klarer Ansage statt zu
einer leeren Seite, die wie "du hast keine Projekte" aussaehe.
* Der Einladungslink wird nach Gebrauch aus der Adresszeile entfernt --
er ist verbraucht und hat in der Chronik nichts verloren.
* Die Zahlungsknoepfe sagen ehrlich, dass PayPal noch eingerichtet wird,
statt so zu tun als wuerde etwas passieren.
Pruefskript zweimal geschaerft, beide Male waren es Fehlalarme:
* Die Heuristik fuer Nachschlagetabellen hielt gewoehnliche Woerter wie
"abnahme" und "uebergeben" fuer Woerterbuch-Schluessel. Jetzt muss ein
Unterstrich im Namen sein, so wie bei allen echten Schluesseln.
* Eine Ueberschrift gilt jetzt auch als uebersetzt, wenn die Uebersetzung
INNEN sitzt (fester Teil + dynamischer Teil).
i18n vollstaendig, 45/45 Handy-Abnahme.
Co-Authored-By: Claude Opus 5 <[email protected]>
457 lines
20 KiB
JavaScript
457 lines
20 KiB
JavaScript
/* =====================================================================
|
|
wd-portal.js — Kundenportal, Oberfläche (Masterplan S.12)
|
|
|
|
Vier Ansichten in einer Seite: Anmeldung, Passwort festlegen,
|
|
Übersicht, Projektdetail.
|
|
|
|
Wichtig zum Verständnis: Diese Datei stellt nur DAR. Sie entscheidet
|
|
nichts darüber, wer was sehen darf — das macht ausschließlich der
|
|
Server (routes/webdesign-portal.js), weil dieser Code hier im Browser
|
|
des Kunden läuft und dort beliebig veränderbar ist. Was hier ankommt,
|
|
ist bereits gefiltert.
|
|
===================================================================== */
|
|
(function () {
|
|
"use strict";
|
|
|
|
var TOKEN = "wd-portal-token";
|
|
var token = null;
|
|
var s = window.WD.sicher;
|
|
var meldung = document.getElementById("po-meldung");
|
|
|
|
/* Sitzungsspeicher, nicht dauerhaft: derselbe Grundsatz wie überall in
|
|
diesem Bereich — beim Schließen ist der Zugang weg. */
|
|
function tokenLesen() { try { return sessionStorage.getItem(TOKEN); } catch (e) { return null; } }
|
|
function tokenSchreiben(t) {
|
|
try { if (t) sessionStorage.setItem(TOKEN, t); else sessionStorage.removeItem(TOKEN); } catch (e) { /* egal */ }
|
|
}
|
|
|
|
function api(pfad, optionen) {
|
|
var opt = optionen || {};
|
|
opt.headers = Object.assign({ Authorization: "Bearer " + token }, opt.headers || {});
|
|
return window.WD.api(pfad, opt);
|
|
}
|
|
|
|
function zeige(welche) {
|
|
["po-anmeldung", "po-setzen", "po-uebersicht", "po-detail"].forEach(function (id) {
|
|
document.getElementById(id).hidden = id !== welche;
|
|
});
|
|
}
|
|
|
|
/* Sitzung abgelaufen: zurück zur Anmeldung mit klarer Ansage. Eine leere
|
|
Seite würde aussehen wie "du hast keine Projekte" — eine stille
|
|
Falschaussage. */
|
|
function behandleFehler(fehler) {
|
|
if (fehler && fehler.status === 401) {
|
|
token = null; tokenSchreiben(null);
|
|
zeige("po-anmeldung");
|
|
window.WD.meldung(meldung, window.WD.t("po_abgelaufen"), "fehler");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* ---------------- Anmeldung ---------------- */
|
|
document.getElementById("po-login-form").addEventListener("submit", async function (e) {
|
|
e.preventDefault();
|
|
var feld = document.getElementById("po-feld-passwort");
|
|
var knopf = e.target.querySelector("button");
|
|
feld.classList.remove("wd-feld--fehler");
|
|
window.WD.meldungAus(meldung);
|
|
|
|
var email = document.getElementById("po-email").value.trim();
|
|
var passwort = document.getElementById("po-passwort").value;
|
|
if (!email || !passwort) {
|
|
feld.classList.add("wd-feld--fehler");
|
|
feld.querySelector(".wd-feld-fehler").textContent = window.WD.t("po_login_leer");
|
|
return;
|
|
}
|
|
|
|
window.WD.knopfSperren(knopf, true, window.WD.t("po_anmelden_laeuft"));
|
|
try {
|
|
var antwort = await window.WD.api("/webdesign/portal/anmelden", {
|
|
method: "POST", body: { email: email, passwort: passwort },
|
|
});
|
|
token = antwort.token;
|
|
tokenSchreiben(token);
|
|
/* Sprache des Kunden übernehmen, wenn er eine hinterlegt hat —
|
|
so kommt er in seiner Sprache an, ohne umschalten zu müssen. */
|
|
if (antwort.kunde && antwort.kunde.sprache) window.WD.setSprache(antwort.kunde.sprache);
|
|
ladeUebersicht();
|
|
} catch (fehler) {
|
|
feld.classList.add("wd-feld--fehler");
|
|
feld.querySelector(".wd-feld-fehler").textContent = fehler.message || window.WD.t("po_fehler_login");
|
|
document.getElementById("po-passwort").select();
|
|
} finally {
|
|
window.WD.knopfSperren(knopf, false);
|
|
}
|
|
});
|
|
|
|
document.getElementById("po-abmelden").addEventListener("click", async function () {
|
|
try { await api("/webdesign/portal/abmelden", { method: "POST", body: {} }); } catch (e) { /* egal */ }
|
|
token = null; tokenSchreiben(null);
|
|
location.href = "/webdesign/portal.html";
|
|
});
|
|
|
|
/* ---------------- Passwort setzen (Einladungslink) ---------------- */
|
|
var einladungsToken = new URLSearchParams(location.search).get("einladung");
|
|
|
|
document.getElementById("po-setz-form").addEventListener("submit", async function (e) {
|
|
e.preventDefault();
|
|
var feld = document.getElementById("po-feld-neu");
|
|
var knopf = e.target.querySelector("button");
|
|
feld.classList.remove("wd-feld--fehler");
|
|
|
|
var passwort = document.getElementById("po-neu").value;
|
|
window.WD.knopfSperren(knopf, true, window.WD.t("po_anmelden_laeuft"));
|
|
try {
|
|
await window.WD.api("/webdesign/portal/passwort", {
|
|
method: "POST", body: { token: einladungsToken, passwort: passwort },
|
|
});
|
|
zeige("po-anmeldung");
|
|
window.WD.meldung(meldung, window.WD.t("po_setz_fertig"), "ok");
|
|
/* Adresszeile säubern: der Einladungslink ist verbraucht und hat in
|
|
der Chronik nichts mehr verloren. */
|
|
history.replaceState(null, "", "/webdesign/portal.html");
|
|
} catch (fehler) {
|
|
feld.classList.add("wd-feld--fehler");
|
|
feld.querySelector(".wd-feld-fehler").textContent = fehler.message;
|
|
} finally {
|
|
window.WD.knopfSperren(knopf, false);
|
|
}
|
|
});
|
|
|
|
/* ---------------- Übersicht ---------------- */
|
|
var PHASEN = ["briefing", "angebot", "design", "entwicklung", "tests", "abnahme", "uebergeben"];
|
|
|
|
function statusText(st) { return window.WD.t("po_st_" + st); }
|
|
|
|
function phasenLeiste(status) {
|
|
var jetzt = PHASEN.indexOf(status);
|
|
/* Pausiert oder abgebrochen: keine Leiste. Ein Fortschrittsbalken bei
|
|
einem gestoppten Projekt wäre irreführend. */
|
|
if (jetzt < 0) return "";
|
|
return '<div class="po-phasen" aria-hidden="true">' +
|
|
PHASEN.map(function (p, i) {
|
|
return '<span class="po-phase' + (i < jetzt ? " po-erledigt" : i === jetzt ? " po-jetzt" : "") + '"></span>';
|
|
}).join("") + "</div>" +
|
|
'<div class="po-phasen-text">' + s(statusText(status)) + " · " +
|
|
(jetzt + 1) + "/" + PHASEN.length + "</div>";
|
|
}
|
|
|
|
function wartetMarke(wartet) {
|
|
if (wartet !== "kunde" && wartet !== "dogfather") return "";
|
|
return '<span class="po-wartet po-wartet--' + wartet + '">' +
|
|
s(window.WD.t(wartet === "kunde" ? "po_wartet_kunde" : "po_wartet_dogfather")) + "</span>";
|
|
}
|
|
|
|
async function ladeUebersicht() {
|
|
zeige("po-uebersicht");
|
|
var ziel = document.getElementById("po-inhalt");
|
|
ziel.innerHTML = '<div class="po-laedt">' + s(window.WD.t("laedt")) + "</div>";
|
|
|
|
try {
|
|
var d = await api("/webdesign/portal/uebersicht");
|
|
document.getElementById("po-name").textContent = d.kunde.name || "";
|
|
window.WD.meldungAus(meldung);
|
|
|
|
var html = "";
|
|
|
|
/* Offene Zahlungen ganz oben — das ist das Einzige, was den Kunden
|
|
zum Handeln auffordert. Gold, weil es wirklich wichtig ist. */
|
|
if (d.offeneZahlungen.length) {
|
|
html += '<div class="wd-hinweis" style="margin-bottom:1.2rem">' +
|
|
'<p class="wd-hinweis-titel">' + s(window.WD.t("po_offene_zahlungen")) + "</p>" +
|
|
d.offeneZahlungen.map(function (z) {
|
|
return "<p><strong>" + s(z.betrag_text) + "</strong> · " + s(z.zweck_text) + "</p>";
|
|
}).join("") + "</div>";
|
|
}
|
|
|
|
html += "<h2>" + s(window.WD.t("po_projekte")) + "</h2>";
|
|
if (!d.projekte.length) {
|
|
html += '<p class="wd-leise">' + s(window.WD.t("po_keine_projekte")) + "</p>";
|
|
} else {
|
|
html += d.projekte.map(function (p) {
|
|
return '<button type="button" class="wd-karte po-projekt" data-projekt="' + s(p.id) + '">' +
|
|
'<span class="po-projekt-kopf">' +
|
|
'<span class="po-projekt-nr">' + s(p.nummer) + "</span>" +
|
|
"<h3>" + s(p.titel) + "</h3>" +
|
|
wartetMarke(p.wartet_auf) +
|
|
"</span>" +
|
|
phasenLeiste(p.status) +
|
|
(p.naechster_schritt
|
|
? '<p class="wd-klein" style="margin:.7rem 0 .3rem"><strong>' +
|
|
s(window.WD.t("po_naechster_schritt")) + ":</strong> " + s(p.naechster_schritt) + "</p>"
|
|
: "") +
|
|
(p.richttermin
|
|
? '<p class="wd-klein wd-leise" style="margin:0">' + s(window.WD.t("po_richttermin")) +
|
|
": " + window.WD.datum(p.richttermin) + "</p>"
|
|
: "") +
|
|
(p.offene_aenderungen || p.ungelesene_nachrichten
|
|
? '<p class="wd-klein" style="margin:.5rem 0 0;color:var(--wd-blau)">' +
|
|
(p.ungelesene_nachrichten ? p.ungelesene_nachrichten + " " + s(window.WD.t("po_nachrichten")) : "") +
|
|
(p.ungelesene_nachrichten && p.offene_aenderungen ? " · " : "") +
|
|
(p.offene_aenderungen ? p.offene_aenderungen + " " + s(window.WD.t("po_ideen")) : "") +
|
|
"</p>"
|
|
: "") +
|
|
"</button>";
|
|
}).join("");
|
|
}
|
|
|
|
if (d.abos.length) {
|
|
html += '<h2 style="margin-top:1.8rem">' + s(window.WD.t("po_betreuung")) + "</h2>" +
|
|
'<div class="wd-karte"><ul class="po-liste">' +
|
|
d.abos.map(function (a) {
|
|
return '<li class="po-eintrag"><span class="po-eintrag-haupt">' +
|
|
'<span class="po-eintrag-name">' + s(a.paket) + "</span>" +
|
|
'<span class="po-eintrag-neben">' + s(a.preis_text) +
|
|
(a.naechste_zahlung ? " · " + s(window.WD.t("po_naechste_zahlung")) + ": " + window.WD.datum(a.naechste_zahlung) : "") +
|
|
"</span></span></li>";
|
|
}).join("") + "</ul></div>";
|
|
}
|
|
|
|
ziel.innerHTML = html;
|
|
ziel.querySelectorAll("[data-projekt]").forEach(function (b) {
|
|
b.addEventListener("click", function () { ladeProjekt(b.dataset.projekt); });
|
|
});
|
|
} catch (fehler) {
|
|
if (behandleFehler(fehler)) return;
|
|
ziel.innerHTML = "";
|
|
window.WD.meldung(meldung, fehler.message, "fehler");
|
|
}
|
|
}
|
|
|
|
/* ---------------- Projektdetail ---------------- */
|
|
var aktuellesProjekt = null;
|
|
|
|
document.getElementById("po-zurueck").addEventListener("click", function () {
|
|
aktuellesProjekt = null;
|
|
ladeUebersicht();
|
|
});
|
|
|
|
async function ladeProjekt(id) {
|
|
aktuellesProjekt = id;
|
|
zeige("po-detail");
|
|
var ziel = document.getElementById("po-detail-inhalt");
|
|
ziel.innerHTML = '<div class="po-laedt">' + s(window.WD.t("laedt")) + "</div>";
|
|
|
|
try {
|
|
var d = await api("/webdesign/portal/projekt/" + encodeURIComponent(id));
|
|
var p = d.projekt;
|
|
var html = "";
|
|
|
|
html += '<div class="wd-karte" style="margin-bottom:1.2rem">' +
|
|
'<span class="po-projekt-nr">' + s(p.nummer) + "</span>" +
|
|
"<h2 style=\"margin:.2rem 0 .6rem\">" + s(p.titel) + "</h2>" +
|
|
wartetMarke(p.wartet_auf) +
|
|
phasenLeiste(p.status) +
|
|
(p.naechster_schritt
|
|
? '<p style="margin:.8rem 0 0"><strong>' + s(window.WD.t("po_naechster_schritt")) +
|
|
":</strong> " + s(p.naechster_schritt) + "</p>"
|
|
: "") +
|
|
"</div>";
|
|
|
|
/* --- Zahlungen --- */
|
|
html += '<div class="wd-karte" style="margin-bottom:1.2rem"><h3>' + s(window.WD.t("po_zahlungen")) + "</h3>";
|
|
if (!d.zahlungen.length) {
|
|
html += '<p class="wd-leise wd-klein">' + s(window.WD.t("po_keine_zahlungen")) + "</p>";
|
|
} else {
|
|
html += '<ul class="po-liste">' + d.zahlungen.map(function (z) {
|
|
var offen = z.status === "offen" || z.status === "freigegeben";
|
|
return '<li class="po-eintrag"><span class="po-eintrag-haupt">' +
|
|
'<span class="po-eintrag-name">' + s(z.betrag_text) + "</span>" +
|
|
'<span class="po-eintrag-neben">' + s(z.zweck_text) + "</span></span>" +
|
|
'<span class="wd-tag' + (z.status === "bezahlt" ? " wd-tag--ok" : offen ? " wd-tag--gold" : "") + '">' +
|
|
s(window.WD.t("po_za_" + (z.status === "fehlge" ? "fehlge" : z.status))) + "</span>" +
|
|
(offen ? '<button type="button" class="wd-btn wd-btn--haupt wd-btn--klein" data-zahlung="' +
|
|
s(z.id) + '">' + s(window.WD.t("po_jetzt_bezahlen")) + "</button>" : "") +
|
|
"</li>";
|
|
}).join("") + "</ul>";
|
|
}
|
|
html += "</div>";
|
|
|
|
/* --- Dateien --- */
|
|
html += '<div class="wd-karte" style="margin-bottom:1.2rem"><h3>' + s(window.WD.t("po_dateien")) + "</h3>";
|
|
if (!d.dateien.length) {
|
|
html += '<p class="wd-leise wd-klein">' + s(window.WD.t("po_keine_dateien")) + "</p>";
|
|
} else {
|
|
html += '<ul class="po-liste">' + d.dateien.map(function (f) {
|
|
return '<li class="po-eintrag"><span class="po-eintrag-haupt">' +
|
|
'<span class="po-eintrag-name">' + s(f.anzeigename) + "</span>" +
|
|
'<span class="po-eintrag-neben">' + window.WD.datum(f.erstellt_am) +
|
|
(f.version > 1 ? " · " + s(window.WD.t("po_version")) + " " + f.version : "") +
|
|
"</span></span></li>";
|
|
}).join("") + "</ul>";
|
|
}
|
|
html += "</div>";
|
|
|
|
/* --- Ideen & Änderungswünsche --- */
|
|
html += '<div class="wd-karte" style="margin-bottom:1.2rem"><h3>' + s(window.WD.t("po_ideen")) + "</h3>" +
|
|
'<p class="wd-klein wd-leise">' + s(window.WD.t("po_ideen_text")) + "</p>";
|
|
|
|
if (d.aenderungen.length) {
|
|
html += d.aenderungen.map(function (a) {
|
|
var entscheidbar = a.status === "angeboten";
|
|
return '<div class="po-idee' + (entscheidbar ? " po-idee--offen" : "") + '">' +
|
|
'<div class="po-idee-kopf"><h4>' + s(a.titel) + "</h4>" +
|
|
'<span class="wd-tag' + (entscheidbar ? " wd-tag--gold" : a.status === "angenommen" ? " wd-tag--ok" : "") + '">' +
|
|
s(window.WD.t("po_ae_" + a.status)) + "</span></div>" +
|
|
'<p class="wd-klein" style="margin:0 0 .4rem">' + s(a.beschreibung) + "</p>" +
|
|
(a.aufwand_text ? '<p class="wd-klein wd-leise" style="margin:0">' + s(a.aufwand_text) + "</p>" : "") +
|
|
(a.zusatzpreis_text
|
|
? '<p class="wd-klein" style="margin:.3rem 0 0"><strong>' + s(window.WD.t("po_zusatzpreis")) +
|
|
": " + s(a.zusatzpreis_text) + "</strong>" +
|
|
(a.zusatzdauer_text ? " · " + s(window.WD.t("po_zusatzdauer")) + ": " + s(a.zusatzdauer_text) : "") +
|
|
"</p>"
|
|
: "") +
|
|
(entscheidbar
|
|
? '<div class="wd-btn-reihe" style="margin-top:.8rem">' +
|
|
'<button type="button" class="wd-btn wd-btn--haupt wd-btn--klein" data-ja="' + s(a.id) + '">' +
|
|
s(window.WD.t("po_annehmen")) + "</button>" +
|
|
'<button type="button" class="wd-btn wd-btn--still wd-btn--klein" data-nein="' + s(a.id) + '">' +
|
|
s(window.WD.t("po_ablehnen")) + "</button></div>"
|
|
: "") +
|
|
"</div>";
|
|
}).join("");
|
|
} else {
|
|
html += '<p class="wd-leise wd-klein">' + s(window.WD.t("po_keine_ideen")) + "</p>";
|
|
}
|
|
|
|
html += '<div class="wd-feld" style="margin:1rem 0 .6rem">' +
|
|
"<label for=\"po-idee-titel\">" + s(window.WD.t("po_idee_titel")) + "</label>" +
|
|
'<input type="text" id="po-idee-titel" maxlength="160" />' +
|
|
"</div>" +
|
|
'<div class="wd-feld" style="margin-bottom:.6rem" id="po-feld-idee">' +
|
|
"<label for=\"po-idee-text\">" + s(window.WD.t("po_idee_text")) + "</label>" +
|
|
'<textarea id="po-idee-text" rows="3"></textarea>' +
|
|
'<p class="wd-feld-fehler"></p></div>' +
|
|
'<button type="button" class="wd-btn wd-btn--zweit wd-btn--klein" id="po-idee-senden">' +
|
|
s(window.WD.t("po_idee_senden")) + "</button></div>";
|
|
|
|
/* --- Nachrichten --- */
|
|
html += '<div class="wd-karte"><h3>' + s(window.WD.t("po_nachrichten")) + "</h3>";
|
|
if (!d.nachrichten.length) {
|
|
html += '<p class="wd-leise wd-klein">' + s(window.WD.t("po_keine_nachrichten")) + "</p>";
|
|
} else {
|
|
html += d.nachrichten.map(function (n) {
|
|
var vonMir = n.autor === "kunde";
|
|
return '<div class="po-nachricht po-nachricht--' + (vonMir ? "ich" : "du") + '">' +
|
|
'<div class="po-nachricht-kopf">' + (vonMir ? "" : "Dogfather · ") +
|
|
window.WD.datum(n.erstellt_am) + "</div><p>" + s(n.text) + "</p></div>";
|
|
}).join("");
|
|
}
|
|
html += '<div class="wd-feld" style="margin:1rem 0 .6rem">' +
|
|
'<textarea id="po-nachricht-text" rows="2" placeholder="' +
|
|
s(window.WD.t("po_nachricht_platzhalter")) + '"></textarea></div>' +
|
|
'<button type="button" class="wd-btn wd-btn--zweit wd-btn--klein" id="po-nachricht-senden">' +
|
|
s(window.WD.t("po_senden")) + "</button></div>";
|
|
|
|
ziel.innerHTML = html;
|
|
|
|
/* --- Verknüpfungen --- */
|
|
ziel.querySelectorAll("[data-ja], [data-nein]").forEach(function (b) {
|
|
b.addEventListener("click", async function () {
|
|
var annehmen = !!b.dataset.ja;
|
|
var aeId = b.dataset.ja || b.dataset.nein;
|
|
/* Nur beim Annehmen nachfragen — das erzeugt eine Zahlungspflicht.
|
|
Ablehnen ist folgenlos und braucht keine Hürde. */
|
|
if (annehmen && !confirm(window.WD.t("po_annehmen_frage"))) return;
|
|
window.WD.knopfSperren(b, true, "…");
|
|
try {
|
|
await api("/webdesign/portal/aenderung/" + encodeURIComponent(aeId) + "/entscheiden",
|
|
{ method: "POST", body: { annehmen: annehmen } });
|
|
ladeProjekt(id);
|
|
} catch (f) {
|
|
if (behandleFehler(f)) return;
|
|
window.WD.knopfSperren(b, false);
|
|
window.WD.meldung(meldung, f.message, "fehler");
|
|
}
|
|
});
|
|
});
|
|
|
|
ziel.querySelector("#po-idee-senden").addEventListener("click", async function (e) {
|
|
var titel = ziel.querySelector("#po-idee-titel").value.trim();
|
|
var beschreibung = ziel.querySelector("#po-idee-text").value.trim();
|
|
var feld = ziel.querySelector("#po-feld-idee");
|
|
feld.classList.remove("wd-feld--fehler");
|
|
if (!titel || !beschreibung) {
|
|
feld.classList.add("wd-feld--fehler");
|
|
feld.querySelector(".wd-feld-fehler").textContent = window.WD.t("po_idee_leer");
|
|
return;
|
|
}
|
|
window.WD.knopfSperren(e.target, true, "…");
|
|
try {
|
|
await api("/webdesign/portal/aenderung",
|
|
{ method: "POST", body: { projektId: id, titel: titel, beschreibung: beschreibung } });
|
|
ladeProjekt(id);
|
|
} catch (f) {
|
|
if (behandleFehler(f)) return;
|
|
window.WD.knopfSperren(e.target, false);
|
|
window.WD.meldung(meldung, f.message, "fehler");
|
|
}
|
|
});
|
|
|
|
ziel.querySelector("#po-nachricht-senden").addEventListener("click", async function (e) {
|
|
var feld = ziel.querySelector("#po-nachricht-text");
|
|
var inhalt = feld.value.trim();
|
|
if (!inhalt) { feld.focus(); return; }
|
|
window.WD.knopfSperren(e.target, true, "…");
|
|
try {
|
|
await api("/webdesign/portal/nachricht",
|
|
{ method: "POST", body: { projektId: id, text: inhalt } });
|
|
ladeProjekt(id);
|
|
} catch (f) {
|
|
if (behandleFehler(f)) return;
|
|
window.WD.knopfSperren(e.target, false);
|
|
window.WD.meldung(meldung, f.message, "fehler");
|
|
}
|
|
});
|
|
|
|
/* Zahlungsknöpfe: die eigentliche PayPal-Anbindung folgt. Bis dahin
|
|
ein ehrlicher Hinweis statt eines Knopfes, der nichts tut. */
|
|
ziel.querySelectorAll("[data-zahlung]").forEach(function (b) {
|
|
b.addEventListener("click", function () {
|
|
window.WD.meldung(meldung,
|
|
"Die Zahlung über PayPal wird gerade eingerichtet. Bitte melde dich kurz bei Dogfather.", "fehler");
|
|
});
|
|
});
|
|
|
|
} catch (fehler) {
|
|
if (behandleFehler(fehler)) return;
|
|
ziel.innerHTML = "";
|
|
window.WD.meldung(meldung, fehler.message, "fehler");
|
|
}
|
|
}
|
|
|
|
/* ---------------- Start ---------------- */
|
|
async function start() {
|
|
/* Einladungslink hat Vorrang: wer gerade sein Passwort setzen soll,
|
|
will nicht zuerst eine Anmeldemaske sehen. */
|
|
if (einladungsToken) {
|
|
try {
|
|
var info = await window.WD.api("/webdesign/portal/einladung?token=" + encodeURIComponent(einladungsToken));
|
|
document.getElementById("po-setz-fuer").textContent = info.email || "";
|
|
zeige("po-setzen");
|
|
return;
|
|
} catch (fehler) {
|
|
zeige("po-anmeldung");
|
|
window.WD.meldung(meldung, fehler.message, "fehler");
|
|
return;
|
|
}
|
|
}
|
|
|
|
token = tokenLesen();
|
|
if (!token) { zeige("po-anmeldung"); return; }
|
|
ladeUebersicht();
|
|
}
|
|
|
|
/* Nach einem Sprachwechsel die per JS gebauten Teile neu zeichnen. */
|
|
document.addEventListener("wd-sprache-geaendert", function () {
|
|
if (!token) return;
|
|
if (aktuellesProjekt) ladeProjekt(aktuellesProjekt);
|
|
else if (!document.getElementById("po-uebersicht").hidden) ladeUebersicht();
|
|
});
|
|
|
|
if (window.WD) start();
|
|
else document.addEventListener("wd-bereit", start);
|
|
})();
|