Settings entrümpelt: Züchter-Block komplett in den Züchter-Bereich umgezogen
Rene: 'Dieser Bereich könnte auch in den Züchter-Bereich, dann ist alles sauber.' - Settings zeigt für verifizierte Züchter/Admins KEINE Züchter-Karte mehr — der Welten-Chip ist der Einstieg (wie beim Partner). Antrag/Prüfung/Abgelehnt bleiben in Settings (Nicht-Züchter sehen den Chip nicht). - Züchter-Bereich neu: KI-Züchter-Assistenz-Karte (5 Toggles, optimistisches Update + Revert), Status-Badge unterscheidet Admin/Züchter, Admin ohne Profil bekommt 'Profil anlegen' direkt im Hub. - Toter Code raus: _openBreederEditModal (75 Z., Settings-Doppel-Editor — breeder-editor-Seite ist der vollwertige), _kiToggleRow + 3 verwaiste Bindings aus settings.js.
This commit is contained in:
parent
8c76263ea0
commit
dfffd07a96
7 changed files with 111 additions and 293 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1268
|
1269
|
||||||
|
|
@ -86,14 +86,14 @@
|
||||||
<title>Ban Yaro</title>
|
<title>Ban Yaro</title>
|
||||||
|
|
||||||
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
<!-- Theme + theme-color Statusleiste vor CSS setzen -->
|
||||||
<script src="/js/boot-early.js?v=1268"></script>
|
<script src="/js/boot-early.js?v=1269"></script>
|
||||||
|
|
||||||
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||||
<link rel="stylesheet" href="/css/design-system.css?v=1268">
|
<link rel="stylesheet" href="/css/design-system.css?v=1269">
|
||||||
<link rel="stylesheet" href="/css/layout.css?v=1268">
|
<link rel="stylesheet" href="/css/layout.css?v=1269">
|
||||||
<link rel="stylesheet" href="/css/components.css?v=1268">
|
<link rel="stylesheet" href="/css/components.css?v=1269">
|
||||||
<link rel="stylesheet" href="/css/utilities.css?v=1268">
|
<link rel="stylesheet" href="/css/utilities.css?v=1269">
|
||||||
<link rel="stylesheet" href="/css/lists.css?v=1268">
|
<link rel="stylesheet" href="/css/lists.css?v=1269">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -620,11 +620,11 @@
|
||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
|
|
||||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||||
<script src="/js/api.js?v=1268"></script>
|
<script src="/js/api.js?v=1269"></script>
|
||||||
<script src="/js/ui.js?v=1268"></script>
|
<script src="/js/ui.js?v=1269"></script>
|
||||||
<script src="/js/app.js?v=1268"></script>
|
<script src="/js/app.js?v=1269"></script>
|
||||||
<script src="/js/worlds.js?v=1268"></script>
|
<script src="/js/worlds.js?v=1269"></script>
|
||||||
<script src="/js/offline-indicator.js?v=1268"></script>
|
<script src="/js/offline-indicator.js?v=1269"></script>
|
||||||
|
|
||||||
<!-- Feature-Seiten werden lazy geladen -->
|
<!-- Feature-Seiten werden lazy geladen -->
|
||||||
|
|
||||||
|
|
@ -634,7 +634,7 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
<!-- Boot: Offline-Banner + SW-Registration (extrahiert für CSP) -->
|
||||||
<script src="/js/boot.js?v=1268"></script>
|
<script src="/js/boot.js?v=1269"></script>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '1268'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '1269'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
|
||||||
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
|
||||||
window.APP_VERSION = APP_VERSION;
|
window.APP_VERSION = APP_VERSION;
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
window.Page_breeder_dashboard = (() => {
|
window.Page_breeder_dashboard = (() => {
|
||||||
|
|
||||||
let _container = null;
|
let _container = null;
|
||||||
|
let _appState = null;
|
||||||
|
|
||||||
async function init(container) {
|
async function init(container, appState) {
|
||||||
_container = container;
|
_container = container;
|
||||||
|
_appState = appState;
|
||||||
_render();
|
_render();
|
||||||
await _load();
|
await _load();
|
||||||
}
|
}
|
||||||
|
|
@ -73,15 +75,35 @@ window.Page_breeder_dashboard = (() => {
|
||||||
<div style="font-weight:700">${UI.escape(profile?.zwingername || 'Noch kein Profil angelegt')}</div>
|
<div style="font-weight:700">${UI.escape(profile?.zwingername || 'Noch kein Profil angelegt')}</div>
|
||||||
${profile?.rasse_text ? `<div class="text-xs-muted">${UI.escape(profile.rasse_text)}</div>` : ''}
|
${profile?.rasse_text ? `<div class="text-xs-muted">${UI.escape(profile.rasse_text)}</div>` : ''}
|
||||||
<span class="badge" style="background:#dcfce7;color:#16a34a;margin-top:var(--space-1)">
|
<span class="badge" style="background:#dcfce7;color:#16a34a;margin-top:var(--space-1)">
|
||||||
${UI.icon('check-circle')} Verifizierter Züchter
|
${UI.icon('check-circle')} ${status?.rolle === 'admin' ? 'Admin — alle Züchter-Features' : 'Verifizierter Züchter'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-secondary" data-bd-nav="breeder-editor">
|
${profile
|
||||||
${UI.icon('pencil-simple')} Profil
|
? `<button class="btn btn-sm btn-secondary" data-bd-nav="breeder-editor">
|
||||||
</button>
|
${UI.icon('pencil-simple')} Profil
|
||||||
|
</button>`
|
||||||
|
: status?.rolle === 'admin'
|
||||||
|
? `<button class="btn btn-sm btn-primary" id="bd-admin-create">
|
||||||
|
${UI.icon('plus')} Profil anlegen
|
||||||
|
</button>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${profile ? `
|
||||||
|
<!-- KI-Züchter-Assistenz (aus den Einstellungen hierher umgezogen) -->
|
||||||
|
<div class="card" style="padding:var(--space-4);margin-bottom:var(--space-3)">
|
||||||
|
<div style="font-size:var(--text-xs);font-weight:700;text-transform:uppercase;
|
||||||
|
letter-spacing:.06em;color:var(--c-text-muted);margin-bottom:var(--space-2)">KI-Züchter-Assistenz</div>
|
||||||
|
${_kiToggleRow('ki_zucht_wurfankuendigung', 'Wurfankündigungen schreiben')}
|
||||||
|
${_kiToggleRow('ki_zucht_genetik', 'Genetik-Erklärung für Käufer')}
|
||||||
|
${_kiToggleRow('ki_zucht_paarung', 'Paarungsanalyse')}
|
||||||
|
${_kiToggleRow('ki_zucht_beschreibung', 'Hunde-Beschreibungen')}
|
||||||
|
${_kiToggleRow('ki_zucht_jahresbericht', 'Jahresauswertung')}
|
||||||
|
<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:var(--space-2)">
|
||||||
|
${UI.icon('info')} Der Tierschutz-Check läuft immer automatisch und ist nicht abschaltbar.
|
||||||
|
</div>
|
||||||
|
</div>` : ''}
|
||||||
|
|
||||||
<!-- Wurfverwaltung -->
|
<!-- Wurfverwaltung -->
|
||||||
<div class="card" style="padding:var(--space-4);margin-bottom:var(--space-3)">
|
<div class="card" style="padding:var(--space-4);margin-bottom:var(--space-3)">
|
||||||
<div style="display:flex;align-items:center;gap:var(--space-3)">
|
<div style="display:flex;align-items:center;gap:var(--space-3)">
|
||||||
|
|
@ -129,10 +151,74 @@ window.Page_breeder_dashboard = (() => {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KI-Toggle-Zeile (aus settings.js umgezogen — Zustand kommt aus _appState.user)
|
||||||
|
function _kiToggleRow(key, label) {
|
||||||
|
const user = _appState?.user || {};
|
||||||
|
const active = user[key] !== 0;
|
||||||
|
return `
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;
|
||||||
|
padding:var(--space-2) 0;font-size:var(--text-sm)">
|
||||||
|
<span>${UI.escape(label)}</span>
|
||||||
|
<button class="by-toggle bd-ki-toggle" data-key="${UI.escape(key)}"
|
||||||
|
data-active="${active ? '1' : '0'}"
|
||||||
|
style="position:relative;display:inline-block;width:44px;height:24px;
|
||||||
|
border:none;border-radius:12px;cursor:pointer;flex-shrink:0;
|
||||||
|
background:${active ? 'var(--c-primary)' : 'var(--c-border)'};
|
||||||
|
transition:background .2s">
|
||||||
|
<span class="by-toggle-thumb"
|
||||||
|
style="position:absolute;top:2px;left:${active ? '22px' : '2px'};
|
||||||
|
width:20px;height:20px;border-radius:50%;
|
||||||
|
background:#fff;transition:left .2s;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.3)"></span>
|
||||||
|
</button>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
function _bindEvents(el) {
|
function _bindEvents(el) {
|
||||||
el.querySelectorAll('[data-bd-nav]').forEach(btn => {
|
el.querySelectorAll('[data-bd-nav]').forEach(btn => {
|
||||||
btn.addEventListener('click', () => App.navigate(btn.dataset.bdNav));
|
btn.addEventListener('click', () => App.navigate(btn.dataset.bdNav));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Admin ohne Profil: Züchterprofil anlegen
|
||||||
|
el.querySelector('#bd-admin-create')?.addEventListener('click', async e => {
|
||||||
|
const btn = e.currentTarget;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Wird angelegt…';
|
||||||
|
try {
|
||||||
|
await API.breeder.adminCreateProfile();
|
||||||
|
UI.toast.success('Admin-Züchterprofil angelegt.');
|
||||||
|
await _load();
|
||||||
|
} catch (err) {
|
||||||
|
UI.toast.error(err.message || 'Fehler beim Anlegen.');
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerHTML = `${UI.icon('plus')} Profil anlegen`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// KI-Toggles — optimistisches Update mit Revert bei Fehler
|
||||||
|
el.querySelectorAll('.bd-ki-toggle').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async () => {
|
||||||
|
const key = btn.dataset.key;
|
||||||
|
const active = btn.dataset.active === '1';
|
||||||
|
const newVal = active ? 0 : 1;
|
||||||
|
const thumb = btn.querySelector('.by-toggle-thumb');
|
||||||
|
|
||||||
|
btn.dataset.active = newVal ? '1' : '0';
|
||||||
|
btn.style.background = newVal ? 'var(--c-primary)' : 'var(--c-border)';
|
||||||
|
if (thumb) thumb.style.left = newVal ? '22px' : '2px';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await API.patch('/profile', { [key]: newVal });
|
||||||
|
if (_appState?.user) _appState.user[key] = newVal;
|
||||||
|
UI.toast.success(newVal ? 'KI-Feature aktiviert.' : 'KI-Feature deaktiviert.');
|
||||||
|
} catch (err) {
|
||||||
|
btn.dataset.active = active ? '1' : '0';
|
||||||
|
btn.style.background = active ? 'var(--c-primary)' : 'var(--c-border)';
|
||||||
|
if (thumb) thumb.style.left = active ? '22px' : '2px';
|
||||||
|
UI.toast.error(err?.message || 'Einstellung konnte nicht gespeichert werden.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return { init, refresh, onDogChange };
|
return { init, refresh, onDogChange };
|
||||||
|
|
|
||||||
|
|
@ -1664,29 +1664,6 @@ window.Page_settings = (() => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// KI-Toggle-Zeile (Hilfsfunktion für Züchter-Card)
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
function _kiToggleRow(key, label, user) {
|
|
||||||
const active = user[key] !== 0;
|
|
||||||
return `
|
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;
|
|
||||||
padding:var(--space-2) 0;font-size:var(--text-sm)">
|
|
||||||
<span>${UI.escape(label)}</span>
|
|
||||||
<button class="by-toggle ki-toggle-btn" data-key="${UI.escape(key)}"
|
|
||||||
data-active="${active ? '1' : '0'}"
|
|
||||||
style="position:relative;display:inline-block;width:44px;height:24px;
|
|
||||||
border:none;border-radius:12px;cursor:pointer;flex-shrink:0;
|
|
||||||
background:${active ? 'var(--c-primary)' : 'var(--c-border)'};
|
|
||||||
transition:background .2s">
|
|
||||||
<span class="by-toggle-thumb"
|
|
||||||
style="position:absolute;top:2px;left:${active ? '22px' : '2px'};
|
|
||||||
width:20px;height:20px;border-radius:50%;
|
|
||||||
background:#fff;transition:left .2s;
|
|
||||||
box-shadow:0 1px 3px rgba(0,0,0,.3)"></span>
|
|
||||||
</button>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// ZÜCHTER-CARD — asynchron laden und in Slot rendern
|
// ZÜCHTER-CARD — asynchron laden und in Slot rendern
|
||||||
|
|
@ -1714,41 +1691,10 @@ window.Page_settings = (() => {
|
||||||
let actionBlock = '';
|
let actionBlock = '';
|
||||||
|
|
||||||
if (rolle === 'breeder' || rolle === 'admin') {
|
if (rolle === 'breeder' || rolle === 'admin') {
|
||||||
statusBadge = `<span class="badge badge-primary" style="background:var(--c-success);color:#fff">
|
// Verifizierte Züchter/Admins: alles Inhaltliche (Profil, KI-Assistenz,
|
||||||
${UI.icon('check-circle')} ${rolle === 'admin' ? 'Admin — alle Züchter-Features verfügbar' : 'Verifizierter Züchter'}
|
// Würfe, Zuchtkartei) lebt im Züchter-Bereich — hier nur der Verweis.
|
||||||
</span>`;
|
slot.innerHTML = '';
|
||||||
actionBlock = `
|
return;
|
||||||
<div style="margin-top:var(--space-3);font-size:var(--text-sm);display:flex;flex-direction:column;gap:var(--space-1)">
|
|
||||||
${profile?.zwingername ? `<div class="text-secondary">Zwinger: <strong>${UI.escape(profile.zwingername)}</strong></div>` : ''}
|
|
||||||
${profile?.rasse_text ? `<div class="text-secondary">Rasse: <strong>${UI.escape(profile.rasse_text)}</strong></div>` : ''}
|
|
||||||
</div>
|
|
||||||
${rolle === 'breeder' && profile ? `
|
|
||||||
<button class="btn btn-secondary btn-sm mt-3" id="breeder-edit-profile-btn">
|
|
||||||
${UI.icon('pencil-simple')} Profil bearbeiten
|
|
||||||
</button>` : ''}
|
|
||||||
${rolle === 'admin' && !profile ? `
|
|
||||||
<button class="btn btn-primary btn-sm mt-3" id="breeder-admin-create-btn">
|
|
||||||
${UI.icon('plus')} Admin-Züchterprofil anlegen
|
|
||||||
</button>` : ''}
|
|
||||||
${rolle === 'admin' && profile ? `
|
|
||||||
<button class="btn btn-secondary btn-sm mt-3" id="breeder-edit-profile-btn">
|
|
||||||
${UI.icon('pencil-simple')} Profil bearbeiten
|
|
||||||
</button>` : ''}
|
|
||||||
${profile ? `
|
|
||||||
<div style="margin-top:var(--space-4);padding-top:var(--space-3);border-top:1px solid var(--c-border)">
|
|
||||||
<div style="font-size:var(--text-xs);font-weight:600;color:var(--c-text-secondary);
|
|
||||||
text-transform:uppercase;letter-spacing:0.05em;margin-bottom:var(--space-3)">
|
|
||||||
KI-Züchter-Assistenz
|
|
||||||
</div>
|
|
||||||
${_kiToggleRow('ki_zucht_wurfankuendigung', 'Wurfankündigungen schreiben', _appState.user || {})}
|
|
||||||
${_kiToggleRow('ki_zucht_genetik', 'Genetik-Erklärung für Käufer', _appState.user || {})}
|
|
||||||
${_kiToggleRow('ki_zucht_paarung', 'Paarungsanalyse', _appState.user || {})}
|
|
||||||
${_kiToggleRow('ki_zucht_beschreibung', 'Hunde-Beschreibungen', _appState.user || {})}
|
|
||||||
${_kiToggleRow('ki_zucht_jahresbericht', 'Jahresauswertung', _appState.user || {})}
|
|
||||||
<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:var(--space-2)">
|
|
||||||
${UI.icon('info')} Der Tierschutz-Check läuft immer automatisch und ist nicht abschaltbar.
|
|
||||||
</div>
|
|
||||||
</div>` : ''}`;
|
|
||||||
} else if (breeder_status === 'pending') {
|
} else if (breeder_status === 'pending') {
|
||||||
statusBadge = `<span class="badge" style="background:#f59e0b;color:#fff">
|
statusBadge = `<span class="badge" style="background:#f59e0b;color:#fff">
|
||||||
${UI.icon('hourglass')} Antrag wird geprüft
|
${UI.icon('hourglass')} Antrag wird geprüft
|
||||||
|
|
@ -1784,221 +1730,7 @@ window.Page_settings = (() => {
|
||||||
// Button-Handler binden
|
// Button-Handler binden
|
||||||
slot.querySelector('#breeder-reapply-btn')?.addEventListener('click', () => _showUpgradeModal('breeder'));
|
slot.querySelector('#breeder-reapply-btn')?.addEventListener('click', () => _showUpgradeModal('breeder'));
|
||||||
|
|
||||||
slot.querySelector('#breeder-edit-profile-btn')?.addEventListener('click', () =>
|
|
||||||
_openBreederEditModal(profile)
|
|
||||||
);
|
|
||||||
|
|
||||||
slot.querySelector('#breeder-admin-create-btn')?.addEventListener('click', async (e) => {
|
|
||||||
const btn = e.currentTarget;
|
|
||||||
btn.disabled = true;
|
|
||||||
btn.textContent = 'Wird angelegt…';
|
|
||||||
try {
|
|
||||||
await API.breeder.adminCreateProfile();
|
|
||||||
UI.toast.success('Admin-Züchterprofil angelegt. Bitte Seite neu laden.');
|
|
||||||
_loadBreederCard();
|
|
||||||
} catch (err) {
|
|
||||||
UI.toast.error(err.message || 'Fehler beim Anlegen.');
|
|
||||||
btn.disabled = false;
|
|
||||||
btn.innerHTML = `${UI.icon('plus')} Admin-Züchterprofil anlegen`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// KI-Toggle-Handler
|
|
||||||
slot.querySelectorAll('.ki-toggle-btn').forEach(btn => {
|
|
||||||
btn.addEventListener('click', async () => {
|
|
||||||
const key = btn.dataset.key;
|
|
||||||
const active = btn.dataset.active === '1';
|
|
||||||
const newVal = active ? 0 : 1;
|
|
||||||
|
|
||||||
// Optimistisches UI-Update
|
|
||||||
btn.dataset.active = newVal ? '1' : '0';
|
|
||||||
btn.style.background = newVal ? 'var(--c-primary)' : 'var(--c-border)';
|
|
||||||
const thumb = btn.querySelector('.by-toggle-thumb');
|
|
||||||
if (thumb) thumb.style.left = newVal ? '22px' : '2px';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const updated = await API.patch('/profile', { [key]: newVal });
|
|
||||||
if (_appState?.user) _appState.user[key] = newVal;
|
|
||||||
UI.toast.success(newVal ? 'KI-Feature aktiviert.' : 'KI-Feature deaktiviert.');
|
|
||||||
} catch (err) {
|
|
||||||
// Revert
|
|
||||||
btn.dataset.active = active ? '1' : '0';
|
|
||||||
btn.style.background = active ? 'var(--c-primary)' : 'var(--c-border)';
|
|
||||||
if (thumb) thumb.style.left = active ? '22px' : '2px';
|
|
||||||
UI.toast.error(err?.message || 'Einstellung konnte nicht gespeichert werden.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// ZÜCHTER-PROFIL BEARBEITEN MODAL
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
function _openBreederEditModal(profile) {
|
|
||||||
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)`;
|
|
||||||
|
|
||||||
UI.modal.open({
|
|
||||||
title: `${UI.icon('pencil-simple')} Züchter-Profil bearbeiten`,
|
|
||||||
body: `
|
|
||||||
<form id="breeder-edit-form" style="display:flex;flex-direction:column;gap:var(--space-4)">
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">Zwingername</label>
|
|
||||||
<input name="zwingername" type="text" maxlength="100" style="${inputStyle}"
|
|
||||||
value="${UI.escape(profile?.zwingername || '')}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">Rasse</label>
|
|
||||||
<input name="rasse_text" type="text" maxlength="100" style="${inputStyle}"
|
|
||||||
value="${UI.escape(profile?.rasse_text || '')}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">Zuchtverein</label>
|
|
||||||
<input name="verein" type="text" maxlength="100" style="${inputStyle}"
|
|
||||||
value="${UI.escape(profile?.verein || '')}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">Stadt</label>
|
|
||||||
<input name="stadt" type="text" maxlength="80" style="${inputStyle}"
|
|
||||||
value="${UI.escape(profile?.stadt || '')}">
|
|
||||||
</div>
|
|
||||||
<div style="display:flex;align-items:center;gap:var(--space-3)">
|
|
||||||
<input name="vdh_mitglied" type="checkbox" id="edit-breeder-vdh"
|
|
||||||
style="width:18px;height:18px;cursor:pointer;flex-shrink:0"
|
|
||||||
${profile?.vdh_mitglied ? 'checked' : ''}>
|
|
||||||
<label for="edit-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:var(--space-1)">Website (optional)</label>
|
|
||||||
<input name="website" type="url" maxlength="200" style="${inputStyle}"
|
|
||||||
value="${UI.escape(profile?.website || '')}" placeholder="https://mein-zwinger.de">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">Beschreibung (optional)</label>
|
|
||||||
<textarea name="beschreibung" maxlength="500" rows="3"
|
|
||||||
style="${inputStyle};resize:vertical">${UI.escape(profile?.beschreibung || '')}</textarea>
|
|
||||||
</div>
|
|
||||||
</form>`,
|
|
||||||
footer: `
|
|
||||||
<div style="display:flex;gap:var(--space-2);width:100%">
|
|
||||||
<button type="submit" form="breeder-edit-form" class="btn btn-primary flex-1" id="breeder-edit-submit">Speichern</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-modal-close>Abbrechen</button>
|
|
||||||
</div>`,
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('breeder-edit-form')?.addEventListener('submit', async e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const btn = document.getElementById('breeder-edit-submit');
|
|
||||||
await UI.asyncButton(btn, async () => {
|
|
||||||
const form = e.target;
|
|
||||||
const data = {
|
|
||||||
zwingername: form.zwingername.value.trim() || undefined,
|
|
||||||
rasse_text: form.rasse_text.value.trim() || undefined,
|
|
||||||
verein: form.verein.value.trim() || undefined,
|
|
||||||
stadt: form.stadt.value.trim() || undefined,
|
|
||||||
vdh_mitglied: form.vdh_mitglied.checked ? 1 : 0,
|
|
||||||
website: form.website.value.trim() || undefined,
|
|
||||||
beschreibung: form.beschreibung.value.trim() || undefined,
|
|
||||||
};
|
|
||||||
await API.breeder.updateProfile(data);
|
|
||||||
UI.modal.close?.();
|
|
||||||
UI.toast.success('Profil aktualisiert.');
|
|
||||||
_loadBreederCard();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// ZÜCHTER-ANTRAG MODAL
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
function _openBreederApplyModal() {
|
|
||||||
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)`;
|
|
||||||
|
|
||||||
UI.modal.open({
|
|
||||||
title: `${UI.icon('certificate')} Züchter-Antrag stellen`,
|
|
||||||
body: `
|
|
||||||
<form id="breeder-apply-form" style="display:flex;flex-direction:column;gap:var(--space-4)">
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">
|
|
||||||
Zwingername <span class="text-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:var(--space-1)">
|
|
||||||
Rasse <span class="text-danger">*</span>
|
|
||||||
</label>
|
|
||||||
<input name="rasse_text" type="text" maxlength="100" required
|
|
||||||
placeholder="z. B. Labrador Retriever"
|
|
||||||
style="${inputStyle}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">
|
|
||||||
Zuchtverein <span class="text-danger">*</span>
|
|
||||||
</label>
|
|
||||||
<input name="verein" type="text" maxlength="100" required
|
|
||||||
placeholder="z. B. DLRG, VDH, BCD"
|
|
||||||
style="${inputStyle}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">
|
|
||||||
Stadt <span class="text-danger">*</span>
|
|
||||||
</label>
|
|
||||||
<input name="stadt" type="text" maxlength="80" required
|
|
||||||
placeholder="z. B. München"
|
|
||||||
style="${inputStyle}">
|
|
||||||
</div>
|
|
||||||
<div style="display:flex;align-items:center;gap:var(--space-3)">
|
|
||||||
<input name="vdh_mitglied" type="checkbox" id="breeder-vdh"
|
|
||||||
style="width:18px;height:18px;cursor:pointer;flex-shrink:0">
|
|
||||||
<label for="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:var(--space-1)">
|
|
||||||
Website (optional)
|
|
||||||
</label>
|
|
||||||
<input name="website" type="url" maxlength="200"
|
|
||||||
placeholder="https://mein-zwinger.de"
|
|
||||||
style="${inputStyle}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">
|
|
||||||
Beschreibung (optional)
|
|
||||||
</label>
|
|
||||||
<textarea name="beschreibung" maxlength="500" rows="3"
|
|
||||||
placeholder="Kurze Beschreibung deines Zwingers"
|
|
||||||
style="${inputStyle};resize:vertical"></textarea>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label style="display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)">
|
|
||||||
Dokument hochladen <span class="text-danger">*</span>
|
|
||||||
</label>
|
|
||||||
<input name="dokument" type="file" id="breeder-doc-input" required
|
|
||||||
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:var(--space-1)">
|
|
||||||
Zuchtbuch-Eintrag, Vereinsmitgliedschaft o.ä. (PDF, JPG, PNG, WebP)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
`,
|
|
||||||
footer: `
|
|
||||||
<div class="w3-btn-stack">
|
|
||||||
<button type="submit" form="breeder-apply-form" class="btn btn-primary w-full" id="breeder-apply-submit"
|
|
||||||
>Antrag einreichen</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-modal-close>Abbrechen</button>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('breeder-apply-form')?.addEventListener('submit', async e => {
|
document.getElementById('breeder-apply-form')?.addEventListener('submit', async e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="color-scheme" content="light dark">
|
<meta name="color-scheme" content="light dark">
|
||||||
<script src="/js/landing-init.js?v=1268"></script>
|
<script src="/js/landing-init.js?v=1269"></script>
|
||||||
<title>Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz</title>
|
<title>Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz</title>
|
||||||
<meta name="description" content="Ban Yaro: Die kostenlose All-in-One Hunde-App für DACH. Tagebuch, Giftköder-Alarm, Training mit KI, Forum, Wurfbörse, Stammbaum, Inzucht-Check — DSGVO-konform, offline-fähig, direkt im Browser.">
|
<meta name="description" content="Ban Yaro: Die kostenlose All-in-One Hunde-App für DACH. Tagebuch, Giftköder-Alarm, Training mit KI, Forum, Wurfbörse, Stammbaum, Inzucht-Check — DSGVO-konform, offline-fähig, direkt im Browser.">
|
||||||
<meta name="keywords" content="Hunde App, Hunde Community, Wurfbörse, Züchter, Welpen kaufen, Stammbaum Hund, Inzuchtkoeffizient, Hundezucht, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundetraining App, Hunde Forum, Hunde KI, Hundefilm Datenbank, Welpen Marktplatz">
|
<meta name="keywords" content="Hunde App, Hunde Community, Wurfbörse, Züchter, Welpen kaufen, Stammbaum Hund, Inzuchtkoeffizient, Hundezucht, Impfpass Hund, Giftköder Alarm, Gassi Community, Hundetraining App, Hunde Forum, Hunde KI, Hundefilm Datenbank, Welpen Marktplatz">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
|
||||||
const VER = '1268';
|
const VER = '1269';
|
||||||
const CACHE_VERSION = `by-v${VER}`;
|
const CACHE_VERSION = `by-v${VER}`;
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue