scMedia/public/assets/js/account.js
2026-01-17 00:55:52 +01:00

159 lines
4.7 KiB
JavaScript

// 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);
}
}
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();
})();