diff --git a/index.html b/index.html index 2d9a1bd..92296a0 100644 --- a/index.html +++ b/index.html @@ -1336,6 +1336,26 @@ + +
+ +
+
BNI Vorstellungsrunde
+
Bitte gib deinen Lizenzcode ein, um dein Chapter freizuschalten.
+ +
+ +
+
+ @@ -1647,7 +1667,9 @@ // CONSTANTS & CHAPTER CONFIG // ============================================================ const APP_VERSION = '1.1.0'; -const GITEA_RAW = 'http://72.60.134.73:3000/cheubaum/BNI-Sonne/raw/branch/main'; +const GITEA_RAW = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Sonne/raw'; +const GITEA_API = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Sonne'; +function giteaUrl(path) { return `${GITEA_RAW}/${path}?ref=main`; } const CHAPTER_CONFIG_KEY = 'bni-active-chapter'; function loadChapterConfig() { @@ -4009,7 +4031,7 @@ async function activateChapter() { status.textContent = 'Überprüfe Lizenzcode…'; status.style.color = 'rgba(255,255,255,0.6)'; try { - const res = await fetch(`${GITEA_RAW}/chapters/${code}/config.json`, { cache: 'no-store' }); + const res = await fetch(giteaUrl(`chapters/${code}/config.json`), { cache: 'no-store' }); if (!res.ok) { status.textContent = 'Ungültiger oder abgelaufener Lizenzcode.'; status.style.color = '#f87171'; @@ -4050,7 +4072,7 @@ function applyChapterUI(config) { if (ctrlName) ctrlName.textContent = `${name} – Steuerung`; if (config.logoUrl && activeChapter) { const src = config.logoUrl.startsWith('http') ? config.logoUrl - : `${GITEA_RAW}/chapters/${activeChapter.code}/${config.logoUrl}`; + : giteaUrl(`chapters/${activeChapter.code}/${config.logoUrl}`); ['display-logo','display-logo-empty','ctrl-logo'].forEach(id => { const img = document.getElementById(id); if (img) img.src = src; @@ -4066,7 +4088,7 @@ function applyChapterUI(config) { async function checkLicenseAndUpdates() { if (!activeChapter) return; try { - const res = await fetch(`${GITEA_RAW}/chapters/${activeChapter.code}/config.json`, { cache: 'no-store' }); + const res = await fetch(giteaUrl(`chapters/${activeChapter.code}/config.json`), { cache: 'no-store' }); if (!res.ok) { clearChapterData(); state = defaultState(); @@ -4089,7 +4111,7 @@ async function checkLicenseAndUpdates() { async function checkForUpdates() { try { - const res = await fetch(`${GITEA_RAW}/version.json`, { cache: 'no-store' }); + const res = await fetch(giteaUrl('version.json'), { cache: 'no-store' }); if (!res.ok) return; const data = await res.json(); if (data.version && data.version > APP_VERSION) showUpdateBanner(data.version, data.notes); @@ -4110,7 +4132,7 @@ function showUpdateBanner(version, notes) { async function downloadUpdate(version) { try { - const licRes = await fetch(`${GITEA_RAW}/chapters/${activeChapter.code}/config.json`, { cache: 'no-store' }); + const licRes = await fetch(giteaUrl(`chapters/${activeChapter.code}/config.json`), { cache: 'no-store' }); if (!licRes.ok) { clearChapterData(); state = defaultState(); @@ -4120,7 +4142,7 @@ async function downloadUpdate(version) { } } catch(e) { alert('Keine Serververbindung möglich.'); return; } try { - const res = await fetch(`${GITEA_RAW}/index.html`, { cache: 'no-store' }); + const res = await fetch(giteaUrl('index.html'), { cache: 'no-store' }); const html = await res.text(); const blob = new Blob([html], { type: 'text/html' }); const a = document.createElement('a'); @@ -4134,15 +4156,23 @@ async function downloadUpdate(version) { async function fetchChapterMembersFromGitea() { if (!activeChapter) return; try { - const res = await fetch(`${GITEA_RAW}/chapters/${activeChapter.code}/members.json`, { cache: 'no-store' }); + const res = await fetch(giteaUrl(`chapters/${activeChapter.code}/members.json`), { cache: 'no-store' }); if (!res.ok) return; const data = await res.json(); if (!data.members || !data.members.length) return; + const extras = loadExtras(); const mergedMap = new Map(state.members.map(m => [m.id, m])); data.members.forEach(m => { const ex = mergedMap.get(m.id); mergedMap.set(m.id, ex ? Object.assign({}, ex, m) : m); + // Embed photoData into extras so existing photo display picks it up + if (m.photoData) { + const key = extrasKey(m.name); + if (!extras[key]) extras[key] = {}; + extras[key].offlinePhotoB64 = m.photoData; + } }); + saveExtras(extras); state.members = Array.from(mergedMap.values()); const knownIds = new Set(state.meetingOrder); state.members.forEach(m => { if (!knownIds.has(m.id)) state.meetingOrder.push(m.id); }); @@ -4154,6 +4184,65 @@ async function fetchChapterMembersFromGitea() { } catch(e) { /* ignore */ } } +function buildMembersJson() { + const extras = loadExtras(); + const members = state.members.map(m => { + const ex = extras[extrasKey(m.name)] || {}; + const entry = { id: m.id, name: m.name, company: m.company, specialty: m.specialty, photoUrl: m.photoUrl || '', profileUrl: m.profileUrl || '' }; + if (ex.offlinePhotoB64) entry.photoData = ex.offlinePhotoB64; + return entry; + }); + return { lastUpdated: new Date().toISOString().slice(0, 10), members }; +} + +function saveAdminToken() { + const val = (document.getElementById('admin-token-input').value || '').trim(); + if (val) localStorage.setItem('bni-gitea-admin-token', val); + else localStorage.removeItem('bni-gitea-admin-token'); + renderAdminPanel(); +} + +async function uploadMembersToGitea() { + const token = localStorage.getItem('bni-gitea-admin-token'); + if (!token) { alert('Bitte zuerst den Admin-Token speichern.'); return; } + const statusEl = document.getElementById('upload-status'); + statusEl.textContent = 'Lädt hoch…'; + statusEl.style.color = 'var(--muted)'; + + const data = buildMembersJson(); + const jsonStr = JSON.stringify(data, null, 2); + const content = btoa(unescape(encodeURIComponent(jsonStr))); + const path = `chapters/${activeChapter.code}/members.json`; + + try { + // Get current SHA + let sha = null; + const shaRes = await fetch(`${GITEA_API}/contents/${path}`, { headers: { 'Authorization': `token ${token}` } }); + if (shaRes.ok) sha = (await shaRes.json()).sha; + + const body = { message: `Mitglieder aktualisiert ${new Date().toLocaleDateString('de')}`, content }; + if (sha) body.sha = sha; + + const res = await fetch(`${GITEA_API}/contents/${path}`, { + method: sha ? 'PUT' : 'POST', + headers: { 'Authorization': `token ${token}`, 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + if (res.ok) { + activeChapter.lastMemberUpload = new Date().toISOString(); + saveChapterConfig(activeChapter); + statusEl.textContent = `✓ ${data.members.length} Mitglieder hochgeladen`; + statusEl.style.color = 'var(--success)'; + } else { + statusEl.textContent = 'Fehler beim Upload. Token prüfen.'; + statusEl.style.color = '#dc2626'; + } + } catch(e) { + statusEl.textContent = 'Verbindungsfehler.'; + statusEl.style.color = '#dc2626'; + } +} + function renderAdminPanel() { const panel = document.getElementById('admin-panel'); if (!panel) return; @@ -4161,7 +4250,8 @@ function renderAdminPanel() { const code = activeChapter && activeChapter.code; const lastChecked = activeChapter && activeChapter.lastChecked ? new Date(activeChapter.lastChecked).toLocaleString('de') : '—'; const lastSync = activeChapter && activeChapter.lastMemberSync ? new Date(activeChapter.lastMemberSync).toLocaleString('de') : '—'; - const maskedCode = code ? code.slice(0, -3).replace(/./g, '·') + code.slice(-3) : '—'; + const lastUpload = activeChapter && activeChapter.lastMemberUpload ? new Date(activeChapter.lastMemberUpload).toLocaleString('de') : '—'; + const hasToken = !!localStorage.getItem('bni-gitea-admin-token'); panel.innerHTML = `
Chapter-Administration
@@ -4169,13 +4259,26 @@ function renderAdminPanel() {
Aktives Chapter
${cfg.chapterName || '—'}
-
Version: ${APP_VERSION}
-
Letzte Lizenzprüfung: ${lastChecked}
+
Version: ${APP_VERSION} · Lizenzprüfung: ${lastChecked}
- -
Letzte Synchronisation: ${lastSync}
- -
+ +
Mitglieder laden
+ +
Letzter Download: ${lastSync}
+ +
Mitglieder hochladen (Admin)
+
+ + +
+ +
+
Letzter Upload: ${lastUpload}
+ + ` : `
Kein Chapter aktiviert.
`}
@@ -4204,25 +4307,6 @@ if (getView() === 'control') { } - -
- -
-
BNI Vorstellungsrunde
-
Bitte gib deinen Lizenzcode ein, um dein Chapter freizuschalten.
- -
- -
-