Feature: Abo-Kündigung + Ablaufdatum + Dog-Auswahl nach Downgrade (SW by-v945)

This commit is contained in:
rene 2026-05-14 13:56:55 +02:00
parent 44b3fba191
commit 3b666c545f
10 changed files with 341 additions and 11 deletions

View file

@ -104,18 +104,43 @@ window.Page_settings = (() => {
<span style="font-size:var(--text-xs);font-weight:400;opacity:.9">${price}</span>
</button>`;
const expires = u.subscription_expires_at;
const cancelled = u.subscription_cancelled_at;
const expiresDate = expires ? new Date(expires).toLocaleDateString('de-DE', {day:'numeric',month:'long',year:'numeric'}) : null;
const isPaid = (isPro || isBreeder) && !tier.endsWith('_test') && !isAdmin;
const _expiryInfo = () => {
if (!isPaid || !expiresDate) return '';
const color = cancelled ? '#e65100' : 'var(--c-text-secondary)';
const text = cancelled
? `Gekündigt — läuft bis ${expiresDate}`
: `Aktiv bis ${expiresDate}`;
return `<div style="font-size:var(--text-xs);color:${color};margin-top:var(--space-1)">${text}</div>`;
};
const _cancelBtn = () => {
if (!isPaid || cancelled) return '';
return `<button id="settings-cancel-sub-btn"
style="margin-top:var(--space-3);padding:var(--space-2) var(--space-3);
border-radius:var(--radius-md);border:1px solid var(--c-border);
background:transparent;color:var(--c-text-secondary);
font-size:var(--text-xs);cursor:pointer">
Abo kündigen
</button>`;
};
let statusHtml = '';
let actionsHtml = '';
if (isAdmin) {
statusHtml = _badge('Admin', '#6366f1');
} else if (isBreeder) {
statusHtml = _badge('Züchter aktiv', '#C4843A');
statusHtml = _badge(cancelled ? 'Züchter (gekündigt)' : 'Züchter aktiv', '#C4843A');
} else if (isPro) {
statusHtml = _badge('Pro aktiv', '#16a34a');
statusHtml = _badge(cancelled ? 'Pro (gekündigt)' : 'Pro aktiv', '#16a34a');
actionsHtml = `
<div style="margin-top:var(--space-3);display:flex;gap:var(--space-2);flex-wrap:wrap">
${_upgradeBtn('settings-upgrade-breeder-btn','Züchter werden','49 €/Jahr','#C4843A')}
${!cancelled ? _upgradeBtn('settings-upgrade-breeder-btn','Züchter werden','49 €/Jahr','#C4843A') : ''}
</div>`;
} else {
statusHtml = _badge('Kostenlos', '#888');
@ -134,7 +159,9 @@ window.Page_settings = (() => {
<span style="font-size:var(--text-sm);color:var(--c-text-secondary)">Aktueller Tarif:</span>
${statusHtml}
</div>
${_expiryInfo()}
${actionsHtml}
${_cancelBtn()}
</div>
</div>`;
}
@ -340,6 +367,71 @@ window.Page_settings = (() => {
});
}
function _showCancelModal() {
const u = _appState.user;
const tier = u?.subscription_tier || 'standard';
const label = { pro: 'Ban Yaro Pro', breeder: 'Züchter' }[tier] || tier;
const expires = u?.subscription_expires_at;
const expiresDate = expires
? new Date(expires).toLocaleDateString('de-DE', {day:'numeric',month:'long',year:'numeric'})
: null;
UI.modal.open({
title: `${label} kündigen`,
body: `
<div style="padding:var(--space-2) 0">
${expiresDate ? `
<div style="padding:var(--space-3);border-radius:var(--radius-md);
background:rgba(234,88,12,.08);border:1px solid rgba(234,88,12,.2);
margin-bottom:var(--space-4);font-size:var(--text-sm)">
Dein Abo läuft noch bis <strong>${expiresDate}</strong> du hast bis dahin vollen Zugriff.
</div>` : ''}
<div style="font-size:var(--text-sm);color:var(--c-text-secondary);line-height:1.6;
display:flex;flex-direction:column;gap:var(--space-2)">
<div> Alle deine Daten (Tagebuch, Gesundheit, Notizen) bleiben vollständig erhalten</div>
<div> Deine Hunde-Profile bleiben gespeichert</div>
<div> Du kannst jederzeit wieder upgraden</div>
${_appState.dogs?.length > 1
? `<div style="color:var(--c-warning,#f59e0b)">⚠ Du hast mehrere Hunde — nach dem Ablauf wählst du einen als Haupthund</div>`
: ''}
</div>
</div>`,
footer: `
<button data-modal-close
style="padding:var(--space-2) var(--space-4);border-radius:var(--radius-md);
border:1.5px solid var(--c-border);background:transparent;
color:var(--c-text);font-size:var(--text-sm);cursor:pointer">
Abbrechen
</button>
<button id="cancel-sub-confirm-btn"
style="padding:var(--space-2) var(--space-4);border-radius:var(--radius-md);
border:none;cursor:pointer;background:var(--c-danger);color:#fff;
font-size:var(--text-sm);font-weight:600">
Jetzt kündigen
</button>`
});
document.getElementById('cancel-sub-confirm-btn')?.addEventListener('click', async () => {
const btn = document.getElementById('cancel-sub-confirm-btn');
if (!btn) return;
btn.disabled = true;
btn.textContent = '…';
try {
await API.auth.cancelSubscription();
// User-State aktualisieren
const fresh = await API.auth.me();
Object.assign(_appState.user, fresh);
UI.modal.close();
UI.toast.success('Kündigung bestätigt. Eine Bestätigungsmail wurde gesendet.');
_render();
} catch (e) {
btn.disabled = false;
btn.textContent = 'Jetzt kündigen';
UI.toast.error(e.message || 'Fehler beim Kündigen.');
}
});
}
// ----------------------------------------------------------
// RENDER
// ----------------------------------------------------------
@ -1102,6 +1194,9 @@ window.Page_settings = (() => {
document.getElementById('settings-upgrade-breeder-btn')?.addEventListener('click', () => {
_showUpgradeModal('breeder');
});
document.getElementById('settings-cancel-sub-btn')?.addEventListener('click', () => {
_showCancelModal();
});
document.getElementById('settings-worlds-btn')?.addEventListener('click', () => {
if (window.Worlds?._openConfigModal) window.Worlds._openConfigModal();