Skip to content
This repository was archived by the owner on Jul 28, 2026. It is now read-only.

Commit 00df51f

Browse files
committed
feat: update URL with tab name when switching server/user tabs
1 parent 0608428 commit 00df51f

1 file changed

Lines changed: 78 additions & 12 deletions

File tree

public/js/admin.js

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ async function renderAdminServerDetail(serverId) {
519519
</div>
520520
`;
521521

522-
initAdminTabs();
522+
initAdminTabs(serverId);
523523
initAdminActions(serverId);
524524
initIcons();
525525
} catch (err) {
@@ -535,7 +535,7 @@ async function renderAdminServerDetail(serverId) {
535535
}
536536
}
537537

538-
function initAdminTabs() {
538+
function initAdminTabs(serverId) {
539539
const tabs = $a('#admin-server-tabs');
540540
if (!tabs) return;
541541
const indicator = $a('#admin-tab-indicator');
@@ -554,6 +554,8 @@ function initAdminTabs() {
554554
indicator.style.left = tabBtn.offsetLeft + 'px';
555555
indicator.style.width = tabBtn.offsetWidth + 'px';
556556
}
557+
558+
history.pushState({ adminPage: 'server', serverId, tab: tabName }, '', `/admin/server/${serverId}/${tabName}`);
557559
}
558560

559561
btns.forEach(btn => {
@@ -564,6 +566,16 @@ function initAdminTabs() {
564566
});
565567

566568
// Set initial indicator position
569+
const pathParts = window.location.pathname.replace('/admin/', '').split('/');
570+
const tabFromUrl = pathParts[2];
571+
if (tabFromUrl) {
572+
const tabBtn = Array.from(btns).find(b => b.dataset.tab === tabFromUrl);
573+
if (tabBtn) {
574+
switchTab(tabBtn);
575+
return;
576+
}
577+
}
578+
567579
const activeBtn = tabs.querySelector('.tab.active');
568580
if (activeBtn && indicator) {
569581
indicator.style.left = activeBtn.offsetLeft + 'px';
@@ -806,12 +818,18 @@ function showNotifyAllModal() {
806818
</div>
807819
<div class="form-group" style="margin-bottom:16px">
808820
<label for="admin-notify-all-type">Type</label>
809-
<select id="admin-notify-all-type" style="width:100%">
810-
<option value="info">Info</option>
811-
<option value="success">Success</option>
812-
<option value="warning">Warning</option>
813-
<option value="error">Error</option>
814-
</select>
821+
<div class="custom-select" id="admin-notify-all-type">
822+
<div class="custom-select-trigger" tabindex="0">
823+
<span class="custom-select-label">Info</span>
824+
<i data-lucide="chevron-down" class="custom-select-arrow" style="width:16px;height:16px"></i>
825+
</div>
826+
<div class="custom-select-dropdown">
827+
<div class="custom-select-option" data-value="info">Info</div>
828+
<div class="custom-select-option" data-value="success">Success</div>
829+
<div class="custom-select-option" data-value="warning">Warning</div>
830+
<div class="custom-select-option" data-value="error">Error</div>
831+
</div>
832+
</div>
815833
</div>
816834
<div style="display:flex;gap:8px">
817835
<button type="submit" class="btn btn-primary btn-full" id="admin-btn-send-notify-all" style="justify-content:center">Send to All Users</button>
@@ -822,14 +840,36 @@ function showNotifyAllModal() {
822840
</div>
823841
`;
824842
overlay.style.display = 'flex';
843+
initIcons();
844+
845+
const nTypeSelect = $a('#admin-notify-all-type');
846+
if (nTypeSelect) {
847+
const nTrigger = nTypeSelect.querySelector('.custom-select-trigger');
848+
const nLabel = nTypeSelect.querySelector('.custom-select-label');
849+
nTrigger.addEventListener('click', (e) => {
850+
e.stopPropagation();
851+
document.querySelectorAll('.custom-select.open').forEach(s => s.classList.remove('open'));
852+
nTypeSelect.classList.add('open');
853+
});
854+
nTypeSelect.querySelectorAll('.custom-select-option').forEach(opt => {
855+
opt.addEventListener('click', (e) => {
856+
e.stopPropagation();
857+
nLabel.textContent = opt.textContent;
858+
nTypeSelect.dataset.selectedValue = opt.dataset.value;
859+
nTypeSelect.classList.remove('open');
860+
});
861+
});
862+
document.addEventListener('click', () => {
863+
nTypeSelect.classList.remove('open');
864+
});
865+
}
825866

826867
$a('#admin-notify-all-form')?.addEventListener('submit', async (e) => {
827868
e.preventDefault();
828869
const btn = $a('#admin-btn-send-notify-all');
829870
const msgEl = $a('#admin-notify-all-msg');
830871
const titleEl = $a('#admin-notify-all-title');
831872
const messageEl = $a('#admin-notify-all-message');
832-
const typeEl = $a('#admin-notify-all-type');
833873
btn.disabled = true;
834874
btn.innerHTML = '<span class="spinner"></span> Sending...';
835875
if (msgEl) msgEl.style.display = 'none';
@@ -839,7 +879,7 @@ function showNotifyAllModal() {
839879
body: JSON.stringify({
840880
title: titleEl.value.trim(),
841881
message: messageEl.value.trim(),
842-
type: typeEl.value,
882+
type: nTypeSelect.dataset.selectedValue || 'info',
843883
}),
844884
});
845885
if (msgEl) { msgEl.textContent = `Notification sent to ${data.count} user(s) successfully`; msgEl.style.display = 'block'; msgEl.style.color = 'var(--accent-green)'; }
@@ -1129,7 +1169,7 @@ async function renderAdminUserDetail(userId) {
11291169
<div id="admin-user-action-msg" style="margin-top:12px;display:none"></div>
11301170
`;
11311171

1132-
initUserTabs();
1172+
initUserTabs(userId);
11331173
initUserActions(userId);
11341174
initIcons();
11351175
} catch (err) {
@@ -1145,7 +1185,7 @@ async function renderAdminUserDetail(userId) {
11451185
}
11461186
}
11471187

1148-
function initUserTabs() {
1188+
function initUserTabs(userId) {
11491189
const tabs = $a('#admin-user-tabs');
11501190
if (!tabs) return;
11511191
const indicator = $a('#admin-user-tab-indicator');
@@ -1164,6 +1204,8 @@ function initUserTabs() {
11641204
indicator.style.left = tabBtn.offsetLeft + 'px';
11651205
indicator.style.width = tabBtn.offsetWidth + 'px';
11661206
}
1207+
1208+
history.pushState({ adminPage: 'user', userId, tab: tabName }, '', `/admin/user/${userId}/${tabName}`);
11671209
}
11681210

11691211
btns.forEach(btn => {
@@ -1173,6 +1215,16 @@ function initUserTabs() {
11731215
});
11741216
});
11751217

1218+
const pathParts = window.location.pathname.replace('/admin/', '').split('/');
1219+
const tabFromUrl = pathParts[2];
1220+
if (tabFromUrl) {
1221+
const tabBtn = Array.from(btns).find(b => b.dataset.tab === tabFromUrl);
1222+
if (tabBtn) {
1223+
switchTab(tabBtn);
1224+
return;
1225+
}
1226+
}
1227+
11761228
const activeBtn = tabs.querySelector('.tab.active');
11771229
if (activeBtn && indicator) {
11781230
indicator.style.left = activeBtn.offsetLeft + 'px';
@@ -1913,10 +1965,24 @@ window.addEventListener('popstate', () => {
19131965
$a('#admin-page-server-detail')?.classList.add('active');
19141966
$a('#admin-page-servers')?.classList.remove('active');
19151967
renderAdminServerDetail(pid);
1968+
const tab = pathParts[2];
1969+
if (tab) {
1970+
setTimeout(() => {
1971+
const tabBtn = document.querySelector('#admin-server-tabs .tab[data-tab="' + tab + '"]');
1972+
if (tabBtn) tabBtn.click();
1973+
}, 50);
1974+
}
19161975
} else if (basePage === 'user' && param) {
19171976
const uid = parseInt(param, 10);
19181977
$a('#admin-page-user-detail')?.classList.add('active');
19191978
renderAdminUserDetail(uid);
1979+
const tab = pathParts[2];
1980+
if (tab) {
1981+
setTimeout(() => {
1982+
const tabBtn = document.querySelector('#admin-user-tabs .tab[data-tab="' + tab + '"]');
1983+
if (tabBtn) tabBtn.click();
1984+
}, 50);
1985+
}
19201986
} else if (basePage === 'users') {
19211987
adminNavigateTo('users');
19221988
} else if (basePage === 'dashboard' || !basePage || basePage === 'login') {

0 commit comments

Comments
 (0)