Skip to content

Commit 3ed7a32

Browse files
committed
refactor: restructure routes - overview at /, signup at /signup, add auth guard
1 parent 3f53979 commit 3ed7a32

1 file changed

Lines changed: 74 additions & 15 deletions

File tree

public/js/app.js

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ async function api(path, options = {}) {
139139
state.user = null;
140140
localStorage.removeItem('zh_token');
141141
localStorage.removeItem('zh_user');
142-
renderLoginPage();
142+
navigateTo('login');
143143
throw new Error('Session expired. Please sign in again.');
144144
}
145145
if (!res.ok) throw new Error(data.error || 'Request failed');
@@ -245,7 +245,7 @@ function renderLoginPage() {
245245
246246
</form>
247247
<div class="auth-footer">
248-
Don't have an account? <a href="#" id="go-register">Create one</a>
248+
Don't have an account? <a href="/signup" id="go-register">Create one</a>
249249
</div>
250250
</div>
251251
</div>
@@ -254,7 +254,7 @@ function renderLoginPage() {
254254
$('#login-form').addEventListener('submit', handleLogin);
255255
$('#go-register').addEventListener('click', (e) => {
256256
e.preventDefault();
257-
renderRegisterPage();
257+
navigateTo('signup');
258258
});
259259
}
260260

@@ -298,7 +298,7 @@ function renderRegisterPage() {
298298
299299
</form>
300300
<div class="auth-footer">
301-
Already have an account? <a href="#" id="go-login">Sign in</a>
301+
Already have an account? <a href="/login" id="go-login">Sign in</a>
302302
</div>
303303
</div>
304304
</div>
@@ -307,7 +307,7 @@ function renderRegisterPage() {
307307
$('#register-form').addEventListener('submit', handleRegister);
308308
$('#go-login').addEventListener('click', (e) => {
309309
e.preventDefault();
310-
renderLoginPage();
310+
navigateTo('login');
311311
});
312312
}
313313

@@ -332,6 +332,7 @@ async function handleLogin(e) {
332332
state.user = data.user;
333333
localStorage.setItem('zh_token', data.token);
334334
localStorage.setItem('zh_user', JSON.stringify(data.user));
335+
history.replaceState({ page: 'overview' }, '', '/');
335336
renderDashboard();
336337
} catch (err) {
337338
showError(e.target, err.message);
@@ -371,6 +372,7 @@ async function handleRegister(e) {
371372
state.user = data.user;
372373
localStorage.setItem('zh_token', data.token);
373374
localStorage.setItem('zh_user', JSON.stringify(data.user));
375+
history.replaceState({ page: 'overview' }, '', '/');
374376
renderDashboard();
375377
} catch (err) {
376378
showError(e.target, err.message);
@@ -471,7 +473,7 @@ async function renderDashboard() {
471473
<nav class="sidebar-nav">
472474
<div class="nav-indicator" id="nav-indicator"></div>
473475
<div class="nav-section-label">Main</div>
474-
<a class="nav-item active" data-page="overview" href="/overview">
476+
<a class="nav-item active" data-page="overview" href="/">
475477
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
476478
Overview
477479
</a>
@@ -551,7 +553,7 @@ async function renderDashboard() {
551553
state.user = null;
552554
localStorage.removeItem('zh_token');
553555
localStorage.removeItem('zh_user');
554-
renderLoginPage();
556+
navigateTo('login');
555557
});
556558

557559
$('#sidebar-user-info').addEventListener('click', (e) => {
@@ -629,17 +631,48 @@ function initSidebarTooltip() {
629631
}
630632

631633
function navigateTo(page) {
632-
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
633-
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
634-
635634
const parts = page.split('/');
636-
const basePage = parts[0];
635+
let basePage = parts[0] || 'overview';
637636
const param = parts[1];
638637

638+
// Auth pages - redirect to / if already logged in
639+
if ((basePage === 'login' || basePage === 'signup') && state.token) {
640+
basePage = 'overview';
641+
}
642+
643+
// Handle auth pages (no dashboard needed)
644+
if (basePage === 'login') {
645+
renderLoginPage();
646+
history.pushState({ page: 'login' }, '', '/login');
647+
return;
648+
}
649+
if (basePage === 'signup') {
650+
renderRegisterPage();
651+
history.pushState({ page: 'signup' }, '', '/signup');
652+
return;
653+
}
654+
655+
// Auth guard: require valid token for all other pages
656+
if (!state.token) {
657+
renderLoginPage();
658+
history.pushState({ page: 'login' }, '', '/login');
659+
return;
660+
}
661+
662+
// Ensure dashboard layout exists
663+
if (!document.querySelector('.dashboard-layout')) {
664+
renderDashboard();
665+
return;
666+
}
667+
668+
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
669+
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
670+
639671
state.currentPage = basePage;
640672
state.serverId = param ? parseInt(param) : null;
641673
state.serverDetailTab = 'info';
642-
history.pushState({ page: basePage, serverId: state.serverId }, '', `/${page}`);
674+
const url = basePage === 'overview' && !param ? '/' : `/${page}`;
675+
history.pushState({ page: basePage, serverId: state.serverId }, '', url);
643676

644677
if (basePage === 'server' && state.serverId) {
645678
const targetPage = $('#page-server-detail');
@@ -687,9 +720,18 @@ function updateNavIndicator() {
687720
window.addEventListener('popstate', () => {
688721
const path = window.location.pathname;
689722
const parts = path.replace(/^\//, '').split('/');
690-
const basePage = parts[0] || 'overview';
723+
let basePage = parts[0] || 'overview';
691724
const param = parts[1];
692725

726+
// Auth pages - redirect to / if already logged in
727+
if ((basePage === 'login' || basePage === 'signup') && state.token) {
728+
basePage = 'overview';
729+
}
730+
731+
if (basePage === 'login') { renderLoginPage(); return; }
732+
if (basePage === 'signup') { renderRegisterPage(); return; }
733+
if (!state.token) { renderLoginPage(); return; }
734+
693735
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
694736
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
695737

@@ -1413,7 +1455,7 @@ function renderAccount() {
14131455
state.user = null;
14141456
localStorage.removeItem('zh_token');
14151457
localStorage.removeItem('zh_user');
1416-
renderLoginPage();
1458+
navigateTo('login');
14171459
});
14181460
}
14191461

@@ -1698,7 +1740,7 @@ async function handleConfirmDeleteAccount() {
16981740
state.user = null;
16991741
localStorage.removeItem('zh_token');
17001742
localStorage.removeItem('zh_user');
1701-
setTimeout(() => renderLoginPage(), 1500);
1743+
setTimeout(() => navigateTo('login'), 1500);
17021744
} catch (err) {
17031745
showToast(err.message, 'error');
17041746
btn.disabled = false;
@@ -2228,19 +2270,36 @@ async function handleExportData() {
22282270

22292271
// ===== INIT =====
22302272
function init() {
2273+
const path = window.location.pathname;
2274+
const basePage = path.replace(/^\//, '').split('/')[0] || '';
22312275
const token = localStorage.getItem('zh_token');
2276+
22322277
if (token) {
22332278
state.token = token;
22342279
try {
22352280
const user = JSON.parse(localStorage.getItem('zh_user'));
22362281
if (user) state.user = user;
22372282
} catch {}
2283+
}
2284+
2285+
if (basePage === 'login' || basePage === 'signup') {
2286+
if (state.token) {
2287+
history.replaceState({ page: 'overview' }, '', '/');
2288+
renderDashboard();
2289+
} else if (basePage === 'login') {
2290+
renderLoginPage();
2291+
} else {
2292+
renderRegisterPage();
2293+
}
2294+
} else if (state.token) {
22382295
api('/servers/overview').then(() => renderDashboard()).catch(() => {
22392296
renderDashboard();
22402297
});
22412298
} else {
22422299
renderLoginPage();
2300+
history.replaceState({ page: 'login' }, '', '/login');
22432301
}
2302+
22442303
renderCookieBanner();
22452304
}
22462305

0 commit comments

Comments
 (0)