Kundenbereich: Verträge und Abmelden nur noch im Profilbild-Menü
- "Abo verwalten & Rechnungen" (Stripe-Kundenportal) steht nur noch im Konto-Menü (Gruppe "Verträge", nur mit Abo). In der Wartungskarte bleibt nur bei fehlgeschlagener Abbuchung "Zahlungsart aktualisieren". - "Verträge hier kündigen" und "Vertrag widerrufen": raus aus Seitenfuß, Wartungskarte und Abo-Seite; im Kundenbereich nur noch im Konto-Menü. Ausnahme: während der Widerrufsfrist zeigt die Wartungskarte weiter "Vertrag widerrufen · bis TT.MM." (§ 356a BGB: hervorgehoben platziert). Öffentlich bleiben beide auf der Login-Seite und im Footer von webklar.com. - "Abmelden" nicht mehr in der Kopfzeile, nur noch im Konto-Menü. - Hinweis unter den Rechnungen verweist aufs Profilbild und öffnet das Menü. - Browser ohne <dialog>: Menü klappt als Box auf (statt Abmelden in der Kopfzeile). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d72d30dd2a
commit
93381a81c5
3 files changed
+79
-48
No files matched your search
+46
-25
@@ -706,26 +706,30 @@ function renderAboSideActive(card, data) {
|
||||
<strong>${fmtHours(l.balanceMinutes)}</strong><span>Arbeitszeit verfügbar</span><em aria-hidden="true">›</em>
|
||||
</button>
|
||||
<p class="kb-sub">${dateLine}</p>
|
||||
${sub.paymentProblem ? '<p class="kb-side-alert">Die letzte Abbuchung ist fehlgeschlagen. Bitte aktualisieren Sie Ihre Zahlungsart, damit Ihre Website online bleibt.</p>' : ''}
|
||||
<button type="button" class="kb-side-btn" id="abo-manage">${sub.paymentProblem ? 'Zahlungsart aktualisieren ↗' : 'Abo verwalten & Rechnungen ↗'}</button>
|
||||
${sub.paymentProblem ? `
|
||||
<p class="kb-side-alert">Die letzte Abbuchung ist fehlgeschlagen. Bitte aktualisieren Sie Ihre Zahlungsart, damit Ihre Website online bleibt.</p>
|
||||
<button type="button" class="kb-side-btn" id="abo-manage">Zahlungsart aktualisieren ↗</button>` : ''}
|
||||
<button type="button" class="kb-side-btn" data-view="takeover">Übernahmegutschrift beantragen <span class="kb-badge hidden" id="takeover-badge" title="Rückfrage offen"></span></button>
|
||||
${sub.withdrawalOpen ? `<a class="kb-side-btn" href="/widerrufen.html">Vertrag widerrufen <small>· bis ${fmtDayMonth(sub.withdrawalUntil)}</small></a>` : ''}
|
||||
<div class="kb-divider"></div>
|
||||
<p class="kb-fine" style="margin-top:0">${aboTermText(sub)}</p>
|
||||
${sub.cancelAtPeriodEnd ? '' : '<p class="kb-fine"><a href="/kuendigen.html">Vertrag hier kündigen</a></p>'}
|
||||
<p class="error hidden" id="abo-error"></p>`
|
||||
|
||||
card.querySelector('#abo-manage')?.addEventListener('click', async (ev) => {
|
||||
const btn = ev.currentTarget
|
||||
btn.disabled = true
|
||||
try {
|
||||
const { url } = await api('/api/abo/portal', { method: 'POST' })
|
||||
window.location.href = url
|
||||
} catch (err) {
|
||||
showError(card.querySelector('#abo-error'), err.message)
|
||||
btn.disabled = false
|
||||
}
|
||||
})
|
||||
card.querySelector('#abo-manage')?.addEventListener('click', (ev) => openBillingPortal(ev.currentTarget, card.querySelector('#abo-error')))
|
||||
}
|
||||
|
||||
/* Stripe-Kundenportal (Zahlungsart, Rechnungen, Abo): "Abo verwalten & Rechnungen" im Konto-Menü,
|
||||
in der Wartungskarte nur bei fehlgeschlagener Abbuchung ("Zahlungsart aktualisieren") */
|
||||
async function openBillingPortal(btn, errorEl) {
|
||||
btn.disabled = true
|
||||
hideError(errorEl)
|
||||
try {
|
||||
const { url } = await api('/api/abo/portal', { method: 'POST' })
|
||||
window.location.href = url
|
||||
} catch (err) {
|
||||
showError(errorEl, err.message)
|
||||
btn.disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
/* Ansicht "Wartungs-Abo": Bestellung (Bestellübersicht direkt über dem Bestellbutton, § 312j BGB) */
|
||||
@@ -842,7 +846,7 @@ function renderAboAccountView(view, data) {
|
||||
<div class="kb-panel">
|
||||
<p class="abo-note" style="margin-top:0">Jeden bezahlten Monat kommt 1 Stunde dazu. Angerechnet wird in 15-Minuten-Schritten, die ältesten Stunden zuerst. Aufträge schicken Sie uns einfach über den <a href="#chat" data-view="chat">Chat</a>.</p>
|
||||
${sub.offerText ? `<p class="abo-note">Ihr Angebot: ${escapeHtml(sub.offerText)}.</p>` : ''}
|
||||
<p class="abo-note">${aboTermText(sub)}${sub.cancelAtPeriodEnd ? '' : ' <a href="/kuendigen.html">Vertrag hier kündigen</a>'}</p>
|
||||
<p class="abo-note">${aboTermText(sub)}</p>
|
||||
<p class="abo-note" style="margin-bottom:0"><a href="/abo-bedingungen.html" target="_blank" rel="noopener">Leistungen & Bedingungen</a></p>
|
||||
</div>
|
||||
<div class="kb-panel">
|
||||
@@ -880,6 +884,7 @@ async function loadAboCard({ afterCheckout = false } = {}) {
|
||||
}
|
||||
card.classList.remove('hidden')
|
||||
document.getElementById('invoices-abo-note')?.classList.toggle('hidden', !data.subscription)
|
||||
document.getElementById('kb-sheet-abo')?.classList.toggle('hidden', !data.subscription)
|
||||
loadTakeoverCard({ abo: data })
|
||||
document.dispatchEvent(new CustomEvent('kb:abo', { detail: data }))
|
||||
} catch (err) {
|
||||
@@ -1185,14 +1190,16 @@ async function initDashboardPage() {
|
||||
const loading = document.getElementById('loading')
|
||||
const empty = document.getElementById('empty')
|
||||
const loadError = document.getElementById('load-error')
|
||||
const logoutBtn = document.getElementById('logout-btn')
|
||||
|
||||
initAppShell()
|
||||
|
||||
logoutBtn?.addEventListener('click', async () => {
|
||||
// Konto-Menü (Profilbild): Abmelden und "Abo verwalten & Rechnungen" gibt es nur dort
|
||||
document.getElementById('kb-sheet-logout')?.addEventListener('click', async () => {
|
||||
await api('/api/auth/logout', { method: 'POST' })
|
||||
window.location.href = '/login.html'
|
||||
})
|
||||
document.getElementById('kb-sheet-abo')?.addEventListener('click', (ev) =>
|
||||
openBillingPortal(ev.currentTarget, document.getElementById('kb-sheet-error')))
|
||||
|
||||
// Seitenleiste, Chips in den Projektkarten und Links im Inhalt schalten die Ansicht um
|
||||
document.addEventListener('click', (ev) => {
|
||||
@@ -1438,15 +1445,30 @@ function renderInstallOffers() {
|
||||
})
|
||||
}
|
||||
|
||||
/* Konto: Bottom-Sheet (Handy) bzw. Popover (Desktop) mit Ansprechpartner, Rechtlichem und Abmelden */
|
||||
/* Konto: Bottom-Sheet (Handy) bzw. Popover (Desktop) mit Ansprechpartner, Verträgen, Rechtlichem und Abmelden.
|
||||
Geöffnet über das Profilbild oder Verweise mit data-open-account (z. B. Hinweis unter den Rechnungen). */
|
||||
function initAccountSheet() {
|
||||
const sheet = document.getElementById('kb-sheet')
|
||||
const avatar = document.getElementById('customer-avatar')
|
||||
if (!sheet || !avatar) return
|
||||
const fill = () => {
|
||||
document.getElementById('kb-sheet-name').textContent = document.getElementById('customer-name')?.textContent || 'Mein Konto'
|
||||
document.getElementById('kb-sheet-meta').textContent = document.getElementById('customer-meta')?.textContent || ''
|
||||
document.getElementById('kb-sheet-avatar').textContent = avatar.textContent
|
||||
renderInstallOffers()
|
||||
}
|
||||
if (typeof sheet.showModal !== 'function') {
|
||||
// Sehr alte Browser ohne <dialog>: Abmelden bleibt in der Kopfzeile
|
||||
// Sehr alte Browser ohne <dialog>: das Menü klappt als einfache Box unter der Kopfzeile auf (kb-no-sheet)
|
||||
document.body.classList.add('kb-no-sheet')
|
||||
avatar.disabled = true
|
||||
const show = (on) => {
|
||||
if (on) fill()
|
||||
sheet.toggleAttribute('open', on)
|
||||
}
|
||||
avatar.addEventListener('click', () => show(!sheet.hasAttribute('open')))
|
||||
document.addEventListener('click', (ev) => {
|
||||
if (ev.target.closest('[data-open-account]')) show(true)
|
||||
else if (ev.target.closest('#kb-sheet [data-sheet-close], #kb-sheet [data-view]')) show(false)
|
||||
})
|
||||
return
|
||||
}
|
||||
const panel = sheet.querySelector('.kb-sheet-panel')
|
||||
@@ -1457,10 +1479,7 @@ function initAccountSheet() {
|
||||
const open = () => {
|
||||
if (sheet.open) return
|
||||
closeToken += 1
|
||||
document.getElementById('kb-sheet-name').textContent = document.getElementById('customer-name')?.textContent || 'Mein Konto'
|
||||
document.getElementById('kb-sheet-meta').textContent = document.getElementById('customer-meta')?.textContent || ''
|
||||
document.getElementById('kb-sheet-avatar').textContent = avatar.textContent
|
||||
renderInstallOffers()
|
||||
fill()
|
||||
sheet.classList.remove('is-closing')
|
||||
panel.style.transform = ''
|
||||
sheet.showModal()
|
||||
@@ -1485,6 +1504,9 @@ function initAccountSheet() {
|
||||
}
|
||||
|
||||
avatar.addEventListener('click', open)
|
||||
document.addEventListener('click', (ev) => {
|
||||
if (ev.target.closest('[data-open-account]')) open()
|
||||
})
|
||||
// Escape bzw. Android-Zurück: mit Animation schließen
|
||||
sheet.addEventListener('cancel', (ev) => {
|
||||
ev.preventDefault()
|
||||
@@ -1499,7 +1521,6 @@ function initAccountSheet() {
|
||||
sheet.addEventListener('click', (ev) => {
|
||||
if (ev.target === sheet || ev.target.closest('[data-sheet-close], [data-view]')) close()
|
||||
})
|
||||
document.getElementById('kb-sheet-logout')?.addEventListener('click', () => document.getElementById('logout-btn')?.click())
|
||||
|
||||
// Nach unten wischen schließt das Sheet (Griff und Kopf des Sheets)
|
||||
let drag = null
|
||||
|
||||
+14
-8
@@ -44,12 +44,14 @@
|
||||
<strong id="customer-name"></strong>
|
||||
<span id="customer-meta"></span>
|
||||
</div>
|
||||
<button type="button" class="kb-avatar" id="customer-avatar" aria-label="Mein Konto" aria-haspopup="dialog" aria-controls="kb-sheet"></button>
|
||||
<button type="button" class="kb-logout" id="logout-btn">Abmelden</button>
|
||||
<button type="button" class="kb-avatar" id="customer-avatar" aria-label="Mein Konto" title="Mein Konto" aria-haspopup="dialog" aria-controls="kb-sheet"></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Konto: auf dem Handy als Bottom-Sheet, am Desktop als Popover unter dem Avatar (initAppShell) -->
|
||||
<!-- Konto: auf dem Handy als Bottom-Sheet, am Desktop als Popover unter dem Avatar (initAccountSheet).
|
||||
Alles zu den Verträgen und "Abmelden" steht im Kundenbereich nur hier. Einzige Ausnahme: während
|
||||
der Widerrufsfrist zeigt die Wartungskarte "Vertrag widerrufen" (§ 356a BGB: hervorgehoben platziert).
|
||||
Öffentlich, ohne Anmeldung: Login-Seite und Footer von webklar.com. -->
|
||||
<dialog class="kb-sheet" id="kb-sheet" aria-label="Mein Konto">
|
||||
<div class="kb-sheet-panel">
|
||||
<div class="kb-sheet-grip" aria-hidden="true"></div>
|
||||
@@ -66,10 +68,16 @@
|
||||
<!-- App-Ansicht: hierher wandert die Karte "Dein Ansprechpartner" aus der Seitenleiste -->
|
||||
<div id="kb-contact-slot"></div>
|
||||
<div class="kb-install hidden" data-install></div>
|
||||
<nav class="kb-sheet-links" aria-label="Verträge und Rechtliches">
|
||||
<p class="kb-label kb-sheet-label">Verträge</p>
|
||||
<nav class="kb-sheet-links" aria-label="Verträge">
|
||||
<!-- Nur mit Wartungs-Abo: Stripe-Kundenportal; Name wie in den Bedingungen § 7 ("Abo verwalten") -->
|
||||
<button type="button" class="kb-sheet-ext hidden" id="kb-sheet-abo">Abo verwalten & Rechnungen</button>
|
||||
<a href="/abo-bedingungen.html" target="_blank" rel="noopener">Vertragsbedingungen</a>
|
||||
<a class="legal-strong" href="/kuendigen.html">Verträge hier kündigen</a>
|
||||
<a class="legal-strong" href="/widerrufen.html">Vertrag widerrufen</a>
|
||||
<a href="/abo-bedingungen.html" target="_blank" rel="noopener">Vertragsbedingungen</a>
|
||||
</nav>
|
||||
<p class="error hidden" id="kb-sheet-error"></p>
|
||||
<nav class="kb-sheet-links" aria-label="Rechtliches">
|
||||
<a href="/datenschutz.html" target="_blank" rel="noopener">Datenschutz</a>
|
||||
<a href="https://webklar.com/impressum" target="_blank" rel="noopener">Impressum</a>
|
||||
</nav>
|
||||
@@ -145,7 +153,7 @@
|
||||
<p>Deine Rechnungen ansehen, bezahlen und herunterladen.</p>
|
||||
</header>
|
||||
<div class="kb-panel" id="invoices-body"><p class="kb-empty">Lade…</p></div>
|
||||
<p class="kb-note hidden" id="invoices-abo-note">Rechnungen zum Wartungs-Abo findest du unter „Abo verwalten & Rechnungen“ <span class="kb-desk-only">in der Seitenleiste</span><span class="kb-app-only">im Bereich <a href="#wartung" data-view="wartung">Wartung</a></span>.</p>
|
||||
<p class="kb-note hidden" id="invoices-abo-note">Rechnungen zum Wartungs-Abo findest du über dein <button type="button" class="kb-link" data-open-account>Profilbild</button> oben rechts unter „Abo verwalten & Rechnungen“.</p>
|
||||
</section>
|
||||
|
||||
<!-- Chat -->
|
||||
@@ -185,8 +193,6 @@
|
||||
</section>
|
||||
|
||||
<footer class="kb-legal">
|
||||
<a class="legal-strong" href="/kuendigen.html">Verträge hier kündigen</a>
|
||||
<a class="legal-strong" href="/widerrufen.html">Vertrag widerrufen</a>
|
||||
<a href="/abo-bedingungen.html" target="_blank" rel="noopener">Vertragsbedingungen</a>
|
||||
<a href="/datenschutz.html" target="_blank" rel="noopener">Datenschutz</a>
|
||||
<a href="https://webklar.com/impressum" target="_blank" rel="noopener">Impressum</a>
|
||||
|
||||
+19
-15
@@ -54,11 +54,6 @@
|
||||
flex: none; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
|
||||
font-size: 13px; font-weight: 700; background: #26124a; border: 1px solid var(--kb-purple-line);
|
||||
}
|
||||
.kb-logout {
|
||||
flex: none; background: transparent; color: #fff; border: 1px solid var(--kb-border-strong); border-radius: 999px;
|
||||
padding: 9px 18px; font: inherit; font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; cursor: pointer;
|
||||
}
|
||||
.kb-logout:hover { background: #fff; color: #111; }
|
||||
|
||||
/* ---------------------------------------------------------------- Raster --- */
|
||||
.kb-shell {
|
||||
@@ -165,6 +160,8 @@
|
||||
.kb-panel h3 { margin: 0 0 10px; font-size: 16px; }
|
||||
.kb-empty { color: var(--kb-muted); }
|
||||
.kb-note { font-size: 13px; color: var(--kb-muted); }
|
||||
/* Button, der wie ein Link aussieht (z. B. "Profilbild" oeffnet das Konto-Menue) */
|
||||
.kb-link { padding: 0; border: none; background: none; color: #d4b4ff; font: inherit; text-decoration: underline; cursor: pointer; }
|
||||
|
||||
.viewas-banner {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
|
||||
@@ -333,7 +330,6 @@
|
||||
/* ---------------------------------------------------------- Pflichtlinks --- */
|
||||
.kb-legal { margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--kb-border); display: flex; flex-wrap: wrap; gap: 8px 18px; font-size: 13px; }
|
||||
.kb-legal a { color: var(--kb-muted); }
|
||||
.kb-legal a.legal-strong { color: #fff; font-weight: 700; text-decoration: underline; }
|
||||
|
||||
/* ------------------------------------------ Konto (Avatar-Menue, alle Groessen) --- */
|
||||
/* Desktop: Popover unter dem Avatar. App-Ansicht: Bottom-Sheet (siehe unten). */
|
||||
@@ -345,7 +341,6 @@ button.kb-avatar {
|
||||
.kb-bar-title { display: contents; }
|
||||
button.kb-avatar:hover { box-shadow: 0 0 0 3px rgba(157, 61, 254, 0.35); }
|
||||
button.kb-avatar:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
||||
button.kb-avatar:disabled { cursor: default; box-shadow: none; }
|
||||
|
||||
.kb-sheet {
|
||||
inset: 0; margin: 72px clamp(16px, 3vw, 36px) auto auto; padding: 0; border: none; background: transparent;
|
||||
@@ -373,24 +368,34 @@ button.kb-avatar:disabled { cursor: default; box-shadow: none; }
|
||||
}
|
||||
.kb-sheet-x svg, .kb-install-x svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
|
||||
#kb-contact-slot .kb-contact { margin-bottom: 12px; }
|
||||
.kb-sheet-label { margin: 4px 0 8px 4px; }
|
||||
.kb-sheet-links {
|
||||
display: flex; flex-direction: column; margin: 12px 0; border-radius: 14px; overflow: hidden;
|
||||
border: 1px solid var(--kb-border); background: rgba(255, 255, 255, 0.02);
|
||||
}
|
||||
.kb-sheet-links a {
|
||||
.kb-sheet-label + .kb-sheet-links { margin-top: 0; }
|
||||
.kb-sheet-links > a, .kb-sheet-links > button {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 14px;
|
||||
color: var(--kb-muted); font-size: 14.5px; text-decoration: none;
|
||||
}
|
||||
.kb-sheet-links a + a { border-top: 1px solid var(--kb-border); }
|
||||
.kb-sheet-links a::after { content: '›'; font-size: 20px; line-height: 1; color: var(--kb-faint); }
|
||||
.kb-sheet-links a[target='_blank']::after { content: '↗'; font-size: 15px; }
|
||||
.kb-sheet-links > button { width: 100%; margin: 0; border: none; background: none; font-family: inherit; line-height: inherit; text-align: left; cursor: pointer; }
|
||||
.kb-sheet-links > button:disabled { cursor: progress; opacity: 0.6; }
|
||||
/* Trennlinien nur zwischen sichtbaren Eintraegen ("Abo verwalten" gibt es nur mit Abo) */
|
||||
.kb-sheet-links > :not(.hidden) ~ :not(.hidden) { border-top: 1px solid var(--kb-border); }
|
||||
.kb-sheet-links > *::after { content: '›'; font-size: 20px; line-height: 1; color: var(--kb-faint); }
|
||||
.kb-sheet-links > [target='_blank']::after, .kb-sheet-links > .kb-sheet-ext::after { content: '↗'; font-size: 15px; }
|
||||
.kb-sheet-links > .kb-sheet-ext { color: #fff; font-weight: 600; }
|
||||
.kb-sheet-links a.legal-strong { color: #fff; font-weight: 700; }
|
||||
.kb-sheet-links a:active { background: rgba(255, 255, 255, 0.05); }
|
||||
.kb-sheet-links > :active { background: rgba(255, 255, 255, 0.05); }
|
||||
#kb-sheet-error { margin: -4px 0 12px; }
|
||||
.kb-sheet-logout {
|
||||
width: 100%; padding: 13px; border-radius: 14px; border: 1px solid rgba(248, 113, 113, 0.45);
|
||||
background: rgba(248, 113, 113, 0.08); color: #fca5a5; font: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
|
||||
}
|
||||
.kb-sheet-logout:hover { background: rgba(248, 113, 113, 0.14); }
|
||||
/* Sehr alte Browser ohne <dialog> (initAccountSheet): das Menue klappt unter der Kopfzeile auf */
|
||||
.kb-no-sheet .kb-sheet { display: none; position: relative; z-index: 6; inset: auto; margin: 12px auto 0; }
|
||||
.kb-no-sheet .kb-sheet[open] { display: block; }
|
||||
|
||||
/* "WEBklar als App": Hinweis im Tab Projekte (ausblendbar) und im Konto-Sheet */
|
||||
.kb-install {
|
||||
@@ -478,8 +483,7 @@ button.kb-avatar:disabled { cursor: default; box-shadow: none; }
|
||||
.kb-titled .kb-app-title { opacity: 1; transform: translateY(-50%); }
|
||||
.kb-titled .kb-logo, .kb-subpage .kb-logo { opacity: 0; visibility: hidden; transform: translateY(-8px); }
|
||||
.kb-account { flex: none; gap: 0; }
|
||||
.kb-account-text, .kb-logout { display: none; }
|
||||
.kb-no-sheet .kb-logout { display: inline-block; margin-left: 10px; }
|
||||
.kb-account-text { display: none; }
|
||||
.kb-header .kb-avatar { width: 36px; height: 36px; font-size: 13.5px; }
|
||||
|
||||
/* Inhalt: eine Spalte, Platz fuer die Tab-Leiste; auf Tablets mittig begrenzt */
|
||||
@@ -645,7 +649,7 @@ button.kb-avatar:disabled { cursor: default; box-shadow: none; }
|
||||
.kb-sheet-panel.is-dragging { transition: none; }
|
||||
.kb-sheet-grip { display: block; width: 40px; height: 5px; margin: 2px auto 12px; border-radius: 3px; background: rgba(255, 255, 255, 0.24); }
|
||||
.kb-sheet-grip, .kb-sheet-me { touch-action: none; }
|
||||
.kb-sheet-links a, .kb-sheet-logout { padding-top: 14px; padding-bottom: 14px; }
|
||||
.kb-sheet-links > a, .kb-sheet-links > button, .kb-sheet-logout { padding-top: 14px; padding-bottom: 14px; }
|
||||
}
|
||||
|
||||
/* App-Ansicht mit Touch: der Hinweis unter dem Chat (Enter-Taste, Anhaenge) kostet zu viel Hoehe,
|
||||
|
||||
Reference in new issue
Block a user