// public/assets/account.js /* English comments: account profile + preferences */ (function () { const state = { profile: null, ui: null, }; let avatarUrl = null; function qs(id) { return window.UI?.qs ? window.UI.qs(id) : document.getElementById(id); } function setStatus(text) { const hint = qs('accountPasswordHint'); if (hint) hint.textContent = text || ''; } function setAvatarBlob(blob) { const avatar = qs('accountAvatar'); if (!avatar || !blob) return; if (avatarUrl) { URL.revokeObjectURL(avatarUrl); } avatarUrl = URL.createObjectURL(blob); avatar.src = avatarUrl; } async function fetchAvatar() { const token = window.Auth?.getAccessToken?.(); if (!token) return; const res = await fetch('/api/account/avatar', { headers: { Authorization: `Bearer ${token}` }, }); if (!res.ok) return; const blob = await res.blob(); setAvatarBlob(blob); } function applyProfile(profile) { state.profile = profile || {}; if (qs('accountNickname')) qs('accountNickname').value = state.profile.nickname || ''; if (qs('accountEmail')) qs('accountEmail').value = state.profile.email || ''; if (state.profile.avatar_present) { fetchAvatar().catch(() => {}); } } function applyUi(ui) { state.ui = ui || {}; if (qs('accountLanguage')) qs('accountLanguage').value = state.ui.language || 'en'; if (qs('accountTheme')) qs('accountTheme').value = state.ui.theme || 'dark'; if (qs('accountTableMode')) qs('accountTableMode').value = state.ui.table_mode || 'pagination'; if (qs('accountTableSize')) qs('accountTableSize').value = String(state.ui.table_page_size || 50); } async function loadAccount() { const res = await window.Api.request('/api/account', { method: 'GET' }); const data = res?.data || res || {}; applyProfile(data.profile || {}); applyUi(data.ui || {}); if (window.UserPrefs?.load) { await window.UserPrefs.load(); } } async function saveProfile() { const nickname = (qs('accountNickname')?.value || '').trim(); const email = (qs('accountEmail')?.value || '').trim(); const ui = { language: qs('accountLanguage')?.value || 'en', theme: qs('accountTheme')?.value || 'dark', table_mode: qs('accountTableMode')?.value || 'pagination', table_page_size: Number(qs('accountTableSize')?.value || 50), }; await window.Api.request('/api/account', { method: 'POST', body: { nickname, ui }, }); if (window.UserPrefs?.setUi) { Object.keys(ui).forEach((key) => window.UserPrefs.setUi(key, ui[key])); } if (email && email !== state.profile?.email) { await window.Api.request('/api/account/email', { method: 'POST', body: { email }, }); } if (ui.theme && window.UI?.setTheme) { window.UI.setTheme(ui.theme); } if (ui.language && ui.language !== (window.APP_LANG || 'en')) { localStorage.setItem('scmedia_lang', ui.language); } } async function uploadAvatar() { const file = qs('avatarFile')?.files?.[0]; if (!file) return; if (file.size > 5 * 1024 * 1024) { alert('File too large (max 5MB)'); return; } const form = new FormData(); form.append('avatar', file); await window.Api.request('/api/account/avatar', { method: 'POST', body: form, headers: {}, }); await fetchAvatar(); } async function changePassword() { const current = qs('accountPasswordCurrent')?.value || ''; const next = qs('accountPasswordNew')?.value || ''; const confirm = qs('accountPasswordConfirm')?.value || ''; if (!current || !next) { setStatus('Missing password'); return; } if (next !== confirm) { setStatus('Passwords do not match'); return; } setStatus('Saving…'); await window.Api.request('/api/account/password', { method: 'POST', body: { current, next }, }); setStatus('Saved'); qs('accountPasswordCurrent').value = ''; qs('accountPasswordNew').value = ''; qs('accountPasswordConfirm').value = ''; if (window.Auth?.logout) { window.Auth.logout(); return; } if (window.Auth?.clearTokens) { window.Auth.clearTokens(); } window.location.href = '/login'; } function init() { if (window.Auth?.requireAuth) { window.Auth.requireAuth(); } window.UI?.initHeader?.(); window.UI?.initThemeToggle?.(); window.UI?.bindThemePreference?.(); loadAccount().catch(() => {}); qs('btnAccountSave')?.addEventListener('click', () => saveProfile().catch((e) => alert(e.message))); qs('btnAvatarUpload')?.addEventListener('click', () => uploadAvatar().catch((e) => alert(e.message))); qs('btnPasswordChange')?.addEventListener('click', () => changePassword().catch((e) => setStatus(e.message))); } init(); })();