bowler-chart/public/js/admin.js

118 lines
3.9 KiB
JavaScript

'use strict';
function adminApp() {
return {
me: null,
users: [],
schemes: [],
error: '',
tab: 'users',
user: { id: null, username: '', email: '', password: '', role: 'user', active: true },
scheme: { id: null, name: '', seed_color: '#1565c0', mode: 'light', is_default: false },
async init() {
try {
const me = await API.get('/api/me');
this.me = me.user;
if (me.user.role !== 'admin') { window.location.href = '/'; return; }
} catch (_) {
window.location.href = '/login.html';
return;
}
await this.loadSchemes();
await this.loadUsers();
const scheme = Theme.resolve(this.schemes, this.me.preferred_scheme_id);
await Theme.apply(scheme);
},
async loadUsers() {
try { this.users = (await API.get('/api/users')).users; }
catch (e) { this.toast(e.message); }
},
async loadSchemes() {
try { this.schemes = (await API.get('/api/schemes')).schemes; }
catch (e) { this.toast(e.message); }
},
schemeName(id) {
const s = this.schemes.find((x) => x.id === id);
return s ? s.name : '—';
},
// ---- Users ----
openNewUser() {
this.user = { id: null, username: '', email: '', password: '', role: 'user', active: true };
this.$refs.userDialog.showModal();
},
openEditUser(u) {
this.user = { id: u.id, username: u.username, email: u.email || '', password: '', role: u.role, active: !!u.active };
this.$refs.userDialog.showModal();
},
async saveUser() {
try {
if (this.user.id) {
const body = { email: this.user.email, role: this.user.role, active: this.user.active };
if (this.user.password) body.password = this.user.password;
await API.patch(`/api/users/${this.user.id}`, body);
} else {
await API.post('/api/users', {
username: this.user.username,
email: this.user.email,
password: this.user.password,
role: this.user.role,
active: this.user.active,
});
}
this.$refs.userDialog.close();
await this.loadUsers();
} catch (e) { this.toast(e.message); }
},
async deleteUser(u) {
if (!confirm(`Delete user "${u.username}"? Their projects and KPIs will also be removed.`)) return;
try { await API.del(`/api/users/${u.id}`); await this.loadUsers(); }
catch (e) { this.toast(e.message); }
},
// ---- Schemes ----
openNewScheme() {
this.scheme = { id: null, name: '', seed_color: '#1565c0', mode: 'light', is_default: false };
this.$refs.schemeDialog.showModal();
},
openEditScheme(s) {
this.scheme = { id: s.id, name: s.name, seed_color: s.seed_color, mode: s.mode, is_default: !!s.is_default };
this.$refs.schemeDialog.showModal();
},
previewScheme() {
Theme.apply({ seed_color: this.scheme.seed_color, mode: this.scheme.mode });
},
async saveScheme() {
try {
const body = {
name: this.scheme.name,
seed_color: this.scheme.seed_color,
mode: this.scheme.mode,
is_default: this.scheme.is_default,
};
if (this.scheme.id) await API.patch(`/api/schemes/${this.scheme.id}`, body);
else await API.post('/api/schemes', body);
this.$refs.schemeDialog.close();
await this.loadSchemes();
// Restore the admin's own theme after previewing.
await Theme.apply(Theme.resolve(this.schemes, this.me.preferred_scheme_id));
} catch (e) { this.toast(e.message); }
},
async deleteScheme(s) {
if (!confirm(`Delete scheme "${s.name}"?`)) return;
try { await API.del(`/api/schemes/${s.id}`); await this.loadSchemes(); }
catch (e) { this.toast(e.message); }
},
toast(msg) {
this.error = msg;
if (typeof window.ui === 'function') window.ui('#snackbar');
},
};
}
window.adminApp = adminApp;