const STECKBRIEF_FIELDS = [ ['spitzname', 'Spitzname'], ['geburtstag', 'Geburtstag'], ['adresse', 'Adresse / Wohnort'], ['lieblingsfarbe', 'Lieblingsfarbe'], ['lieblingsessen', 'Lieblingsessen'], ['lieblingstier', 'Lieblingstier'], ['hobbys', 'Hobbys'], ['lieblingsmusik', 'Lieblingsmusik'], ['lieblingsfilm', 'Lieblingsfilm/-serie'], ['traumberuf', 'Traumberuf'], ['bestefreunde', 'Beste Freunde'], ['motto', 'Motto / Lebensweisheit'], ['sonstiges', 'Sonstiges'], ]; const pathParts = window.location.pathname.split('/').filter(Boolean); // ['friend', ':id'] or ['share', ':id'] const mode = pathParts[0]; // 'friend' | 'share' const friendId = pathParts[1]; let currentFriend = null; let currentFolder = null; let selectedType = 'image'; function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str || ''; return div.innerHTML; } async function init() { const sessionRes = await fetch('/api/session'); const session = await sessionRes.json(); const isAdmin = session.role === 'admin'; const isMatchingFriend = session.role === 'friend' && session.friendId === friendId; document.getElementById('adminBackWrap').style.display = isAdmin ? 'block' : 'none'; if (isAdmin || isMatchingFriend) { loadFriend(); } else if (mode === 'share') { showLoginGate(); } else { // /friend/:id ohne Admin-Session -> zur Startseite window.location.href = '/'; } } function showLoginGate() { document.getElementById('loginGate').style.display = 'block'; document.getElementById('editorRoot').style.display = 'none'; } document.getElementById('gateForm').addEventListener('submit', async (e) => { e.preventDefault(); const password = document.getElementById('gatePassword').value; const errBox = document.getElementById('gateErr'); errBox.innerHTML = ''; const res = await fetch(`/api/share/${friendId}/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password }), }); const data = await res.json(); if (!res.ok) { errBox.innerHTML = `

${data.error}

`; return; } loadFriend(); }); async function loadFriend() { const res = await fetch(`/api/friends/${friendId}`); if (res.status === 401) { showLoginGate(); return; } if (res.status === 404) { document.body.innerHTML = '

Diesen Freund gibt es nicht (mehr).

'; return; } const data = await res.json(); currentFriend = data.friend; currentFolder = currentFriend.folderName; document.getElementById('loginGate').style.display = 'none'; document.getElementById('editorRoot').style.display = 'block'; document.getElementById('pageTitle').textContent = `📖 ${currentFriend.name}`; renderProfileImage(); renderSteckbrief(); renderBlocks(); } function uploadUrl(filename) { return `/uploads/${encodeURIComponent(currentFolder)}/${encodeURIComponent(filename)}`; } function renderProfileImage() { const img = document.getElementById('profileImg'); const placeholder = document.getElementById('profilePlaceholder'); if (currentFriend.profileImage) { img.src = uploadUrl(currentFriend.profileImage) + `?t=${Date.now()}`; img.style.display = 'block'; placeholder.style.display = 'none'; } else { img.style.display = 'none'; placeholder.style.display = 'flex'; } } document.getElementById('profileInput').addEventListener('change', async (e) => { const file = e.target.files[0]; if (!file) return; const fd = new FormData(); fd.append('image', file); const res = await fetch(`/api/friends/${friendId}/profileimage`, { method: 'POST', body: fd }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; renderProfileImage(); } else { alert(data.error || 'Upload fehlgeschlagen.'); } }); function renderSteckbrief() { const form = document.getElementById('steckbriefForm'); form.innerHTML = ''; STECKBRIEF_FIELDS.forEach(([key, label]) => { const wrap = document.createElement('div'); const val = (currentFriend.steckbrief && currentFriend.steckbrief[key]) || ''; wrap.innerHTML = ``; form.appendChild(wrap); }); } document.getElementById('steckbriefForm').addEventListener('submit', async (e) => { e.preventDefault(); const inputs = document.querySelectorAll('#steckbriefForm input'); const payload = {}; inputs.forEach((inp) => { payload[inp.dataset.key] = inp.value; }); const res = await fetch(`/api/friends/${friendId}/steckbrief`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; const savedEl = document.getElementById('sbSaved'); savedEl.textContent = 'Gespeichert ✓'; savedEl.classList.add('show'); setTimeout(() => savedEl.classList.remove('show'), 1800); } else { alert(data.error || 'Speichern fehlgeschlagen.'); } }); // --- Block-Typ-Auswahl --- document.querySelectorAll('.tab-btn').forEach((btn) => { btn.addEventListener('click', () => { selectedType = btn.dataset.type; document.querySelectorAll('.tab-btn').forEach((b) => b.classList.toggle('active', b === btn)); document.getElementById('blockType').value = selectedType; const fileWrap = document.getElementById('blockFileWrap'); const textWrap = document.getElementById('blockTextWrap'); const fileLabel = document.getElementById('blockFileLabel'); const fileInput = document.getElementById('blockFile'); if (selectedType === 'text') { fileWrap.style.display = 'none'; textWrap.style.display = 'block'; } else { fileWrap.style.display = 'block'; textWrap.style.display = 'none'; fileLabel.textContent = selectedType === 'image' ? 'Bild auswählen' : 'MP3 auswählen'; fileInput.accept = selectedType === 'image' ? 'image/*' : 'audio/*'; } }); }); document.getElementById('blockForm').addEventListener('submit', async (e) => { e.preventDefault(); const fd = new FormData(); fd.append('type', selectedType); fd.append('caption', document.getElementById('blockCaption').value); if (selectedType === 'text') { fd.append('content', document.getElementById('blockContent').value); } else { const file = document.getElementById('blockFile').files[0]; if (!file) { alert('Bitte eine Datei auswählen.'); return; } fd.append('file', file); } const res = await fetch(`/api/friends/${friendId}/blocks`, { method: 'POST', body: fd }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; document.getElementById('blockForm').reset(); renderBlocks(); } else { alert(data.error || 'Hinzufügen fehlgeschlagen.'); } }); function renderBlocks() { const list = document.getElementById('blocksList'); list.innerHTML = ''; const blocks = [...(currentFriend.blocks || [])].sort((a, b) => a.order - b.order); blocks.forEach((b, idx) => { const el = document.createElement('div'); el.className = 'block-item'; const tag = { image: '🖼️ Bild', text: '📝 Text', audio: '🎙️ Audio' }[b.type] || b.type; let inner = `
${tag}
`; if (b.type === 'image') { inner += ``; } else if (b.type === 'audio') { inner += ``; } else { inner += ``; } inner += ``; inner += `
`; el.innerHTML = inner; list.appendChild(el); }); list.querySelectorAll('[data-save]').forEach((btn) => btn.addEventListener('click', () => saveBlock(btn.dataset.save))); list.querySelectorAll('[data-del]').forEach((btn) => btn.addEventListener('click', () => deleteBlock(btn.dataset.del))); list.querySelectorAll('[data-up]').forEach((btn) => btn.addEventListener('click', () => moveBlock(btn.dataset.up, -1))); list.querySelectorAll('[data-down]').forEach((btn) => btn.addEventListener('click', () => moveBlock(btn.dataset.down, 1))); } async function saveBlock(id) { const captionInput = document.querySelector(`[data-caption-for="${id}"]`); const contentInput = document.querySelector(`[data-content-for="${id}"]`); const payload = { caption: captionInput ? captionInput.value : '' }; if (contentInput) payload.content = contentInput.value; const res = await fetch(`/api/friends/${friendId}/blocks/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; renderBlocks(); } } async function deleteBlock(id) { if (!confirm('Diesen Block wirklich löschen?')) return; const res = await fetch(`/api/friends/${friendId}/blocks/${id}`, { method: 'DELETE' }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; renderBlocks(); } } async function moveBlock(id, dir) { const blocks = [...(currentFriend.blocks || [])].sort((a, b) => a.order - b.order); const idx = blocks.findIndex((b) => b.id === id); const swapIdx = idx + dir; if (swapIdx < 0 || swapIdx >= blocks.length) return; [blocks[idx], blocks[swapIdx]] = [blocks[swapIdx], blocks[idx]]; const order = blocks.map((b) => b.id); const res = await fetch(`/api/friends/${friendId}/blocks/reorder`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ order }), }); const data = await res.json(); if (res.ok) { currentFriend = data.friend; renderBlocks(); } } init();