@@ -207,9 +207,8 @@ function renderAdminLayout() {
207207 </div>
208208 </nav>
209209 <main class="admin-content">
210- <div class="admin-notice">
211- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
212- <span>Le panel admin a été ajouté très récemment — peu de fonctionnalités et quelques petits bugs pour le moment. Je suis focus sur l'installateur bash, la doc d'installation et le polish UI côté user, mais une fois tout ça fini, le panel admin aura toute mon attention.</span>
210+ <div class="admin-modal-overlay" id="admin-modal-overlay" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:1000;align-items:center;justify-content:center" onclick="if(event.target===this)closeAdminModal()">
211+ <div class="admin-modal" style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px;max-width:420px;width:90%;box-shadow:0 20px 60px rgba(0,0,0,0.4)" onclick="event.stopPropagation()" id="admin-modal-content"></div>
213212 </div>
214213 <div class="admin-page" id="admin-page-dashboard"></div>
215214 <div class="admin-page active" id="admin-page-servers"></div>
@@ -429,16 +428,11 @@ async function renderAdminServerDetail(serverId) {
429428 <div class="card" style="margin-bottom:16px">
430429 <h2 class="card-title" style="margin-bottom:16px">Suspend</h2>
431430 <p style="color:var(--text-secondary);font-size:0.88rem;margin-bottom:12px">
432- Suspend this server. The user will see the reason on their dashboard and cannot renew until unsuspended .
431+ Suspend or expire this server .
433432 </p>
434- <div class="form-group">
435- <label for="admin-suspend-reason">Reason (optional)</label>
436- <textarea id="admin-suspend-reason" rows="2" placeholder="Enter reason for suspension..." style="resize:vertical;width:100%;padding:10px 14px;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-primary);font-family:inherit;font-size:0.88rem"></textarea>
437- </div>
438433 <div style="display:flex;gap:8px;flex-wrap:wrap">
439434 ${ isSuspended ? ahtml `<button class="btn btn-primary" id="admin-btn-unsuspend" style="width:auto">Unsuspend</button>` : ahtml `<button class="btn btn-danger" id="admin-btn-suspend" style="width:auto">Suspend</button>` }
440435 <button class="btn btn-warning" id="admin-btn-stop" style="width:auto">Stop</button>
441- ${ ! isSuspended ? ahtml `<button class="btn btn-ghost" id="admin-btn-renew-now" style="width:auto">Renew Now</button>` : '' }
442436 </div>
443437 <div id="admin-action-msg" style="margin-top:12px;display:none"></div>
444438 </div>
@@ -520,24 +514,8 @@ function initAdminActions(serverId) {
520514 if ( msgEl ) msgEl . style . display = 'none' ;
521515 }
522516
523- $a ( '#admin-btn-suspend' ) ?. addEventListener ( 'click' , async ( ) => {
524- const btn = $a ( '#admin-btn-suspend' ) ;
525- btn . disabled = true ;
526- btn . innerHTML = '<span class="spinner"></span> Suspending...' ;
527- clearMsg ( ) ;
528- try {
529- const reason = $a ( '#admin-suspend-reason' ) ?. value ?. trim ( ) || '' ;
530- await adminApi ( `/servers/${ serverId } /suspend` , {
531- method : 'POST' ,
532- body : JSON . stringify ( { reason : reason || undefined } ) ,
533- } ) ;
534- showMsg ( 'Server suspended successfully' ) ;
535- setTimeout ( ( ) => renderAdminServerDetail ( serverId ) , 1500 ) ;
536- } catch ( err ) {
537- showMsg ( err . message , 'error' ) ;
538- btn . disabled = false ;
539- btn . innerHTML = 'Suspend' ;
540- }
517+ $a ( '#admin-btn-suspend' ) ?. addEventListener ( 'click' , ( ) => {
518+ showSuspendModal ( serverId ) ;
541519 } ) ;
542520
543521 $a ( '#admin-btn-unsuspend' ) ?. addEventListener ( 'click' , async ( ) => {
@@ -577,24 +555,6 @@ function initAdminActions(serverId) {
577555 }
578556 } ) ;
579557
580- $a ( '#admin-btn-renew-now' ) ?. addEventListener ( 'click' , async ( ) => {
581- const btn = $a ( '#admin-btn-renew-now' ) ;
582- btn . disabled = true ;
583- btn . innerHTML = '<span class="spinner"></span> Expiring...' ;
584- clearMsg ( ) ;
585- try {
586- await adminApi ( `/servers/${ serverId } /renew-now` , {
587- method : 'POST' ,
588- } ) ;
589- showMsg ( 'Server has been expired. The user can renew to reactivate it.' ) ;
590- setTimeout ( ( ) => renderAdminServerDetail ( serverId ) , 1500 ) ;
591- } catch ( err ) {
592- showMsg ( err . message , 'error' ) ;
593- btn . disabled = false ;
594- btn . innerHTML = 'Renew Now' ;
595- }
596- } ) ;
597-
598558 $a ( '#admin-btn-delete' ) ?. addEventListener ( 'click' , async ( ) => {
599559 if ( ! confirm ( 'Are you sure you want to permanently delete this server? This action cannot be undone.' ) ) return ;
600560 const btn = $a ( '#admin-btn-delete' ) ;
@@ -615,6 +575,80 @@ function initAdminActions(serverId) {
615575 } ) ;
616576}
617577
578+ // ─── Suspend Modal ─────────────────────────────────────
579+ function closeAdminModal ( ) {
580+ $a ( '#admin-modal-overlay' ) . style . display = 'none' ;
581+ }
582+
583+ function showSuspendModal ( serverId ) {
584+ const content = $a ( '#admin-modal-content' ) ;
585+ content . innerHTML = ahtml `
586+ <div style="text-align:center">
587+ <h3 style="margin:0 0 20px 0;color:var(--text-primary)">Suspend Server</h3>
588+ <div style="display:flex;flex-direction:column;gap:12px">
589+ <button class="btn btn-danger btn-full" id="admin-modal-expire-now" style="justify-content:center">Expire Now</button>
590+ <button class="btn btn-ghost btn-full" id="admin-modal-suspend-admin" style="justify-content:center">Suspend Admin</button>
591+ <button class="btn btn-ghost btn-full" onclick="closeAdminModal()" style="justify-content:center;color:var(--text-secondary)">Cancel</button>
592+ </div>
593+ </div>
594+ ` ;
595+ $a ( '#admin-modal-overlay' ) . style . display = 'flex' ;
596+
597+ $a ( '#admin-modal-expire-now' ) . addEventListener ( 'click' , async ( ) => {
598+ const btn = $a ( '#admin-modal-expire-now' ) ;
599+ btn . disabled = true ;
600+ btn . innerHTML = '<span class="spinner"></span>' ;
601+ try {
602+ await adminApi ( `/servers/${ serverId } /renew-now` , { method : 'POST' } ) ;
603+ closeAdminModal ( ) ;
604+ renderAdminServerDetail ( serverId ) ;
605+ } catch ( err ) {
606+ btn . disabled = false ;
607+ btn . innerHTML = 'Expire Now' ;
608+ closeAdminModal ( ) ;
609+ const msgEl = $a ( '#admin-action-msg' ) ;
610+ if ( msgEl ) { msgEl . textContent = err . message ; msgEl . style . display = 'block' ; msgEl . style . color = 'var(--accent-red)' ; }
611+ }
612+ } ) ;
613+
614+ $a ( '#admin-modal-suspend-admin' ) . addEventListener ( 'click' , ( ) => {
615+ content . innerHTML = ahtml `
616+ <div>
617+ <h3 style="margin:0 0 16px 0;color:var(--text-primary)">Suspend Admin</h3>
618+ <div class="form-group" style="margin-bottom:16px">
619+ <label for="admin-modal-reason">Reason (optional)</label>
620+ <textarea id="admin-modal-reason" rows="2" placeholder="Enter reason for suspension..." style="resize:vertical;width:100%;padding:10px 14px;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-primary);font-family:inherit;font-size:0.88rem;margin-top:6px;box-sizing:border-box"></textarea>
621+ </div>
622+ <div style="display:flex;gap:8px">
623+ <button class="btn btn-primary btn-full" id="admin-modal-confirm-suspend" style="justify-content:center">Confirm Suspend</button>
624+ <button class="btn btn-ghost btn-full" onclick="showSuspendModal(${ serverId } )" style="justify-content:center">Back</button>
625+ </div>
626+ </div>
627+ ` ;
628+
629+ $a ( '#admin-modal-confirm-suspend' ) . addEventListener ( 'click' , async ( ) => {
630+ const btn = $a ( '#admin-modal-confirm-suspend' ) ;
631+ const reason = $a ( '#admin-modal-reason' ) ?. value ?. trim ( ) || '' ;
632+ btn . disabled = true ;
633+ btn . innerHTML = '<span class="spinner"></span>' ;
634+ try {
635+ await adminApi ( `/servers/${ serverId } /suspend` , {
636+ method : 'POST' ,
637+ body : JSON . stringify ( { reason : reason || undefined } ) ,
638+ } ) ;
639+ closeAdminModal ( ) ;
640+ renderAdminServerDetail ( serverId ) ;
641+ } catch ( err ) {
642+ btn . disabled = false ;
643+ btn . innerHTML = 'Confirm Suspend' ;
644+ closeAdminModal ( ) ;
645+ const msgEl = $a ( '#admin-action-msg' ) ;
646+ if ( msgEl ) { msgEl . textContent = err . message ; msgEl . style . display = 'block' ; msgEl . style . color = 'var(--accent-red)' ; }
647+ }
648+ } ) ;
649+ } ) ;
650+ }
651+
618652// ─── Dashboard ──────────────────────────────────────────
619653async function renderAdminDashboard ( ) {
620654 document . querySelectorAll ( '.admin-page' ) . forEach ( p => p . classList . remove ( 'active' ) ) ;
0 commit comments