banyaro/backend/static/js/pages/breeder.js

235 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ============================================================
BAN YARO — Öffentliches Züchter-Profil
Seiten-Modul: Zeigt das verifizierte Profil eines Züchters.
============================================================ */
window.Page_breeder = (() => {
let _container = null;
let _appState = null;
const _esc = s => UI.esc ? UI.esc(s) : String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
// ----------------------------------------------------------
// INIT
// ----------------------------------------------------------
async function init(container, appState, params = {}) {
_container = container;
_appState = appState;
// Zwingername aus params oder URL-Pfad (/breeder/vom-sonnenfeld)
const zwingername = params?.zwingername
|| decodeURIComponent((window.location.pathname.split('/breeder/')[1] || '').replace(/\/$/, ''));
if (!zwingername) {
container.innerHTML = '<div style="padding:var(--space-6)">Kein Zwingername angegeben.</div>';
return;
}
container.innerHTML = `
<div id="breeder-profile-body" style="padding:var(--space-4) var(--space-4) calc(var(--space-16) + 24px)">
${UI.skeleton(3)}
</div>
<button id="breeder-back-fab" aria-label="Zurück zur Wurfbörse"
style="position:fixed;bottom:calc(var(--safe-bottom,0px) + 20px);right:20px;
width:54px;height:54px;border-radius:50%;background:var(--c-primary);
border:none;color:#fff;cursor:pointer;z-index:200;
display:flex;align-items:center;justify-content:center;
box-shadow:0 4px 18px rgba(196,132,58,.45);
transition:transform .12s,box-shadow .12s;
-webkit-tap-highlight-color:transparent">
<svg style="width:22px;height:22px" viewBox="0 0 256 256">
<use href="/icons/phosphor.svg#arrow-left"></use>
</svg>
</button>`;
document.getElementById('breeder-back-fab')
?.addEventListener('click', () => App.navigate('wurfboerse'));
try {
const p = await API.breeder.profile(zwingername);
_render(p);
} catch (e) {
document.getElementById('breeder-profile-body').innerHTML =
`<p style="padding:var(--space-6);color:var(--c-text-secondary)">${_esc(e.message || 'Züchter nicht gefunden.')}</p>`;
}
}
// ----------------------------------------------------------
// RENDER
// ----------------------------------------------------------
function _render(p) {
const verifiedDate = p.verified_at
? new Date(p.verified_at).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })
: null;
const websiteHtml = p.website
? `<a href="${_esc(p.website)}" target="_blank" rel="noopener noreferrer"
style="color:var(--c-primary);text-decoration:none;word-break:break-all">
${UI.icon('arrow-square-out')} ${_esc(p.website)}
</a>`
: '';
const beschreibungHtml = p.beschreibung
? `<div class="card" style="margin-bottom:var(--space-3)">
<p style="margin:0;white-space:pre-line;color:var(--c-text-secondary)">${_esc(p.beschreibung)}</p>
</div>`
: '';
const body = document.getElementById('breeder-profile-body') || _container;
body.innerHTML = `
<div style="padding:var(--space-4) 0">
<!-- Header-Card -->
<div class="card" style="margin-bottom:var(--space-3)">
<div style="display:flex;align-items:flex-start;gap:var(--space-3);flex-wrap:wrap">
<div style="flex:1;min-width:0">
<h2 style="margin:0 0 var(--space-1);font-size:var(--text-xl);word-break:break-word">
${UI.icon('certificate')} ${_esc(p.zwingername)}
</h2>
<span class="badge badge-primary" style="background:var(--c-success,#22C55E);color:#fff;font-size:var(--text-xs)">
${UI.icon('seal-check')} Verifizierter Züchter
</span>
</div>
</div>
</div>
<!-- Details-Card -->
<div class="card" style="margin-bottom:var(--space-3)">
<dl style="margin:0;display:flex;flex-direction:column;gap:var(--space-3)">
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Rasse</dt>
<dd style="margin:0;font-weight:600">${_esc(p.rasse_text || '')}</dd>
</div>
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Verein</dt>
<dd style="margin:0">${_esc(p.verein || '')}</dd>
</div>
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">VDH-Mitglied</dt>
<dd style="margin:0">
${p.vdh_mitglied
? `<span class="badge badge-primary">${UI.icon('check')} Ja</span>`
: `<span style="color:var(--c-text-secondary)">Nein</span>`}
</dd>
</div>
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Stadt</dt>
<dd style="margin:0">${_esc(p.stadt || '')}</dd>
</div>
${p.website ? `
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Website</dt>
<dd style="margin:0">${websiteHtml}</dd>
</div>` : ''}
${verifiedDate ? `
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Verifiziert</dt>
<dd style="margin:0;color:var(--c-text-secondary);font-size:var(--text-sm)">${verifiedDate}</dd>
</div>` : ''}
<div style="display:flex;gap:var(--space-2);align-items:baseline">
<dt style="color:var(--c-text-secondary);min-width:100px;font-size:var(--text-sm);flex-shrink:0">Züchter</dt>
<dd style="margin:0">${_esc(p.zuechter_name || '')}</dd>
</div>
</dl>
</div>
<!-- Beschreibung -->
${beschreibungHtml}
<!-- Fotos (werden asynchron nachgeladen) -->
<div id="breeder-photos-section"></div>
<!-- Kontakt-Button -->
${(() => {
if (!p.zuechter_user_id) return '';
const isLoggedIn = !!_appState?.user;
const isOwnProfile = _appState?.user?.id === p.zuechter_user_id;
if (isOwnProfile) return '';
if (isLoggedIn) {
return `<button class="btn btn-primary breeder-chat-btn" style="width:100%">
${UI.icon('chat-circle')} Nachricht senden
</button>`;
}
return `<button class="btn btn-primary breeder-login-btn" style="width:100%">
${UI.icon('sign-in')} Anmelden um zu schreiben
</button>`;
})()}
</div>
`;
_container.querySelector('.breeder-chat-btn')?.addEventListener('click', () => {
_contactBreeder(p.zuechter_user_id);
});
_container.querySelector('.breeder-login-btn')?.addEventListener('click', () => {
App.navigate('settings');
});
// Öffentliche Fotos nachladen
_loadBreederPhotos(p.id);
}
async function _loadBreederPhotos(breederId) {
const section = document.getElementById('breeder-photos-section');
if (!section) return;
try {
const photos = await API.breederPhotos.list('breeder', breederId);
if (!photos || !photos.length) return;
section.innerHTML = `
<div class="card" style="margin-bottom:var(--space-3)">
<h3 style="margin:0 0 var(--space-3);font-size:var(--text-md);font-weight:var(--weight-semibold)">
${UI.icon('images')} Fotos
</h3>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:var(--space-2)">
${photos.map(ph => {
const thumb = ph.thumbnail_url || ph.url || '';
return `
<a href="${_esc(ph.url || '')}" target="_blank" rel="noopener noreferrer"
style="display:block;border-radius:var(--radius-md);overflow:hidden;
border:1px solid var(--c-border);aspect-ratio:1">
<img src="${_esc(thumb)}"
alt="${_esc(ph.caption || '')}"
loading="lazy"
style="width:100%;height:100%;object-fit:cover;display:block"
onerror="this.parentElement.style.display='none'">
</a>`;
}).join('')}
</div>
</div>`;
} catch (_) {
// Fotos sind nicht kritisch — bei Fehler still ignorieren
}
}
async function _contactBreeder(breederId) {
if (!_appState?.user) {
App.navigate('settings');
return;
}
try {
await API.chat.start(breederId);
App.navigate('chat');
} catch (e) {
UI.toast.error(e.message || 'Chat konnte nicht geöffnet werden.');
}
}
function refresh() {}
function onDogChange() {}
function destroy() {
document.getElementById('breeder-back-fab')?.remove();
}
return { init, refresh, onDogChange, destroy };
})();