Files
reflector-dashboard/auth/profile.js
T

144 lines
5.1 KiB
JavaScript

// Reflector Dashboard — web front-end for SvxReflector
// Copyright (C) 2026 SA7AUX (Björn)
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version. See the LICENSE file for details.
'use strict';
const $ = id => document.getElementById(id);
let ME = null;
const editableFields = [
{key:'firstname', label:'First Name'},
{key:'lastname', label:'Last Name'},
{key:'shortname', label:'Short Name'},
{key:'email', label:'Email'},
{key:'city', label:'City'},
{key:'state', label:'State'},
{key:'country', label:'Country'},
];
function setMsg(el, txt, err){
if (!el) return;
if (txt === null) { el.style.display='none'; el.textContent=''; return; }
el.style.display='block';
el.textContent = txt;
el.style.color = err ? '#ff8080' : '#00ff80';
}
async function loadMe(){
try {
const r = await fetch('/auth/me.php', {credentials:'same-origin'});
const j = await r.json();
if (j && j.logged_in) ME = j;
else { window.location.href = '/'; return; }
} catch(_) { window.location.href = '/'; return; }
renderProfileEditFields();
}
function renderProfileEditFields(){
if (!ME) return;
const container = $('profileEditFields');
container.innerHTML = '';
// Header info
const info = document.createElement('div');
info.className = 'mb-3 d-flex gap-3 align-items-center flex-wrap';
const FLAG_NAMES = [[1,'unreg'],[2,'reg'],[4,'normal'],[8,'lvl1'],[16,'lvl2'],[32,'lvl3']];
const lvlText = FLAG_NAMES.filter(x => (ME.flags||0) & x[0]).map(x => x[1]).join(', ') || '-';
const lvlColor = ME.admin_level >= 2 ? '#ffc800' : 'rgba(0,255,255,.75)';
const star = ME.admin_level >= 2 ? ' \u2605' : '';
info.innerHTML =
'<span class="small text-secondary">UUID: <span class="mono">' + ME.uuid + '</span></span>'
+ '<span class="small" style="color:' + lvlColor + ';">' + lvlText + star + '</span>'
+ '<span class="small text-secondary">Callsign: <span class="mono">' + (ME.callsign||'') + '</span></span>';
container.appendChild(info);
for (const f of editableFields) {
const lbl = document.createElement('label');
lbl.className = 'form-label small text-secondary';
lbl.textContent = f.label;
lbl.setAttribute('for', 'pedit_' + f.key);
const inp = document.createElement('input');
inp.className = 'form-control form-control-sm mb-2';
inp.id = 'pedit_' + f.key;
inp.value = ME[f.key] || '';
container.appendChild(lbl);
container.appendChild(inp);
}
}
async function saveProfile(){
const body = {};
for (const f of editableFields) {
const el = $('pedit_' + f.key);
if (el) body[f.key] = el.value;
}
const r = await fetch('/auth/profile_update.php', {
method:'POST', credentials:'same-origin',
headers:{'Content-Type':'application/json'},
body: JSON.stringify(body)
});
const j = await r.json().catch(()=>null);
if (j && j.ok) {
setMsg($('profileEditMsg'), 'Saved!', false);
await loadMe();
} else {
setMsg($('profileEditMsg'), (j && j.error) || 'Failed', true);
}
}
function switchProfileTab(tab){
document.querySelectorAll('.profile-tab').forEach(b => {
const active = b.dataset.ptab === tab;
b.classList.toggle('active', active);
b.setAttribute('aria-selected', active ? 'true' : 'false');
});
document.querySelectorAll('.profile-tab-pane').forEach(p => {
p.style.display = p.id === 'ptab-' + tab ? '' : 'none';
});
}
document.addEventListener('DOMContentLoaded', () => {
loadMe();
document.querySelectorAll('.profile-tab[data-ptab]').forEach(btn => {
btn.addEventListener('click', () => switchProfileTab(btn.dataset.ptab));
});
$('btnSaveProfile').addEventListener('click', saveProfile);
// Reset web password modal
$('btnUserResetPwd').addEventListener('click', () => {
$('userPwdOld').value = '';
$('userPwdNew').value = '';
$('userPwdNew2').value = '';
setMsg($('userPwdMsg'), null);
new bootstrap.Modal($('userPwdModal')).show();
});
$('btnUserPwdSave').addEventListener('click', async () => {
const old_password = $('userPwdOld').value;
const new_password = $('userPwdNew').value;
const new_password2 = $('userPwdNew2').value;
if (!old_password || !new_password) { setMsg($('userPwdMsg'),'Fill all fields',true); return; }
if (new_password !== new_password2) { setMsg($('userPwdMsg'),'Passwords do not match',true); return; }
const r = await fetch('/auth/password_change.php', {
method:'POST', credentials:'same-origin',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({old_password, new_password})
});
const j = await r.json().catch(()=>null);
if (j && j.ok) {
setMsg($('userPwdMsg'),'Password changed!', false);
setTimeout(() => bootstrap.Modal.getInstance($('userPwdModal'))?.hide(), 800);
} else {
setMsg($('userPwdMsg'), ((j && j.error) || 'Failed').replace(/_/g,' '), true);
}
});
});