Refactor: Züchter-Antrag in Upgrade-Flow integriert (SW by-v925)

- /breeder/apply: Dokument jetzt optional (File(None)), kann per Mail nachgereicht werden
- _showUpgradeModal('breeder'): enthält jetzt Zwinger-Formular (Zwingername*, Rasse*,
  Verein, Stadt, VDH-Checkbox, optionales Dokument)
  → sendet /breeder/apply + /auth/upgrade-request in einem Schritt
- Züchter-Profil-Karte in Settings: 'Züchter werden'-Button entfernt
  → für neue User ohne Antrag wird die Card vollständig ausgeblendet
  → 'Neu beantragen' bei Ablehnung öffnet jetzt _showUpgradeModal('breeder')
- Verifizierte Züchter: Card unverändert (Profil, Edit, KI-Settings)
This commit is contained in:
rene 2026-05-14 11:17:49 +02:00
parent a27b8ea5b4
commit 4332b1195e
5 changed files with 118 additions and 38 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '924'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '925'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';
// Cache-Bust-Parameter nach Update-Reload sofort entfernen

View file

@ -152,6 +152,61 @@ window.Page_settings = (() => {
`<li style="padding:var(--space-1) 0;font-size:var(--text-sm)">✓ ${f}</li>`
).join('');
const inputStyle = `width:100%;box-sizing:border-box;padding:var(--space-2) var(--space-3);
border:1.5px solid var(--c-border);border-radius:var(--radius-md);
font-size:var(--text-sm);font-family:inherit;background:var(--c-surface);color:var(--c-text)`;
const breederForm = isPro ? '' : `
<div style="margin-top:var(--space-4);padding-top:var(--space-4);border-top:1px solid var(--c-border)">
<div style="font-size:var(--text-xs);font-weight:700;color:var(--c-text-muted);
text-transform:uppercase;letter-spacing:.05em;margin-bottom:var(--space-3)">
Dein Zwinger
</div>
<form id="breeder-upgrade-form" style="display:flex;flex-direction:column;gap:var(--space-3)">
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:4px">
Zwingername <span style="color:var(--c-danger)">*</span>
</label>
<input name="zwingername" type="text" maxlength="100" required
placeholder="z. B. vom Sonnenfeld" style="${inputStyle}">
</div>
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:4px">
Rasse <span style="color:var(--c-danger)">*</span>
</label>
<input name="rasse_text" type="text" maxlength="100" required
placeholder="z. B. Labrador Retriever" style="${inputStyle}">
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2)">
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:4px">Zuchtverein</label>
<input name="verein" type="text" maxlength="100"
placeholder="z. B. VDH, BCD" style="${inputStyle}">
</div>
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:4px">Stadt</label>
<input name="stadt" type="text" maxlength="80"
placeholder="z. B. München" style="${inputStyle}">
</div>
</div>
<div style="display:flex;align-items:center;gap:var(--space-2)">
<input name="vdh_mitglied" type="checkbox" id="upg-breeder-vdh"
style="width:16px;height:16px;cursor:pointer;flex-shrink:0">
<label for="upg-breeder-vdh" style="font-size:var(--text-sm);cursor:pointer">VDH-Mitglied</label>
</div>
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:4px">
Dokument hochladen <span style="font-weight:400;color:var(--c-text-muted)">(optional)</span>
</label>
<input name="dokument" type="file" accept=".pdf,.jpg,.jpeg,.png,.webp"
style="font-size:var(--text-sm);width:100%;box-sizing:border-box">
<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:4px">
Zuchtbuch, Vereinsausweis o.ä. kann auch per E-Mail nachgereicht werden
</div>
</div>
</form>
</div>`;
UI.modal.open({
title: `${label} freischalten`,
body: `
@ -162,7 +217,7 @@ window.Page_settings = (() => {
Einmaliger Jahresbeitrag<br>Kündigung jederzeit möglich
</div>
</div>
<ul style="list-style:none;padding:0;margin:0 0 var(--space-4)">
<ul style="list-style:none;padding:0;margin:0 0 var(--space-3)">
${featureList}
</ul>
<div style="padding:var(--space-3);border-radius:var(--radius-md);
@ -171,6 +226,7 @@ window.Page_settings = (() => {
Wir schalten deinen Account manuell frei innerhalb von 24 Stunden.
Wir melden uns mit den Zahlungsdetails per E-Mail.
</div>
${breederForm}
</div>`,
footer: `
<button data-modal-close
@ -190,8 +246,35 @@ window.Page_settings = (() => {
document.getElementById('upgrade-request-send-btn')?.addEventListener('click', async () => {
const btn = document.getElementById('upgrade-request-send-btn');
if (!btn) return;
btn.disabled = true;
btn.textContent = 'Wird gesendet…';
// Züchter: Formular validieren + als FormData senden
if (!isPro) {
const form = document.getElementById('breeder-upgrade-form');
if (form && !form.reportValidity()) return;
if (form) {
const fd = new FormData(form);
fd.set('vdh_mitglied', form.querySelector('[name="vdh_mitglied"]').checked ? '1' : '0');
// Pflichtfelder aus Form übernehmen falls leer → leere Strings senden
if (!fd.get('verein')) fd.set('verein', '');
if (!fd.get('stadt')) fd.set('stadt', '');
btn.disabled = true;
btn.textContent = 'Wird gesendet…';
try {
await API.breeder.apply(fd);
} catch (e) {
if (!e.message?.includes('bereits')) {
btn.disabled = false;
btn.textContent = 'Anfrage senden';
UI.toast.error(e.message || 'Fehler beim Einreichen.');
return;
}
}
}
} else {
btn.disabled = true;
btn.textContent = 'Wird gesendet…';
}
try {
const res = await API.auth.upgradeRequest(tier);
UI.modal.close();
@ -200,6 +283,7 @@ window.Page_settings = (() => {
} else {
UI.toast.success('Anfrage gesendet! Wir melden uns per E-Mail.');
}
if (!isPro) _loadBreederCard();
} catch (e) {
btn.disabled = false;
btn.textContent = 'Anfrage senden';
@ -1300,17 +1384,17 @@ window.Page_settings = (() => {
</span>`;
actionBlock = `
<div style="margin-top:var(--space-3)">
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin:0 0 var(--space-2)">
Du kannst einen neuen Antrag stellen.
</p>
<button class="btn btn-secondary btn-sm" id="breeder-reapply-btn">
${UI.icon('arrow-counter-clockwise')} Neu beantragen
</button>
</div>`;
} else {
actionBlock = `
<div style="margin-top:var(--space-3)">
<button class="btn btn-primary btn-sm" id="breeder-apply-btn">
${UI.icon('certificate')} Züchter werden
</button>
</div>`;
// Kein Antrag, kein Profil — Card ausblenden (Upgrade-Flow läuft über Abo & Tarif)
slot.innerHTML = '';
return;
}
slot.innerHTML = `
@ -1323,11 +1407,7 @@ window.Page_settings = (() => {
</div>`;
// Button-Handler binden
const applyBtn = slot.querySelector('#breeder-apply-btn');
const reapplyBtn = slot.querySelector('#breeder-reapply-btn');
if (applyBtn || reapplyBtn) {
(applyBtn || reapplyBtn).addEventListener('click', () => _openBreederApplyModal());
}
slot.querySelector('#breeder-reapply-btn')?.addEventListener('click', () => _showUpgradeModal('breeder'));
slot.querySelector('#breeder-edit-profile-btn')?.addEventListener('click', () =>
_openBreederEditModal(profile)