@@ -2917,6 +2917,122 @@ function isValidServerName(name) {
29172917 return name && name . length >= 1 && name . length <= 255 && / ^ [ a - z A - Z 0 - 9 _ . - ] + $ / . test ( name ) ;
29182918}
29192919
2920+ function showVerificationPage ( name ) {
2921+ const overlay = document . createElement ( 'div' ) ;
2922+ overlay . id = 'verification-overlay' ;
2923+ overlay . className = 'verification-overlay' ;
2924+ overlay . innerHTML = html `
2925+ < div class ="verification-card ">
2926+ < div class ="verification-spinner "> </ div >
2927+ < h2 class ="verification-title "> Creating "${ escapeHtml ( name ) } "</ h2 >
2928+ < p class ="verification-subtitle "> Performing security checks...</ p >
2929+ < div class ="verification-steps " id ="verification-steps ">
2930+ < div class ="verification-step active " id ="vstep-vpn ">
2931+ < div class ="verification-step-icon "> < span class ="vstep-spinner "> </ span > </ div >
2932+ < span > Checking connection security</ span >
2933+ </ div >
2934+ < div class ="verification-step " id ="vstep-ua ">
2935+ < div class ="verification-step-icon "> < span class ="vstep-pending "> </ span > </ div >
2936+ < span > Verifying browser</ span >
2937+ </ div >
2938+ < div class ="verification-step " id ="vstep-email ">
2939+ < div class ="verification-step-icon "> < span class ="vstep-pending "> </ span > </ div >
2940+ < span > Checking email verification</ span >
2941+ </ div >
2942+ < div class ="verification-step " id ="vstep-country ">
2943+ < div class ="verification-step-icon "> < span class ="vstep-pending "> </ span > </ div >
2944+ < span > Verifying region</ span >
2945+ </ div >
2946+ < div class ="verification-step " id ="vstep-create ">
2947+ < div class ="verification-step-icon "> < span class ="vstep-pending "> </ span > </ div >
2948+ < span > Creating server</ span >
2949+ </ div >
2950+ </ div >
2951+ </ div >
2952+ ` ;
2953+ document . body . appendChild ( overlay ) ;
2954+ requestAnimationFrame ( ( ) => overlay . classList . add ( 'open' ) ) ;
2955+
2956+ let stepIndex = 0 ;
2957+ const steps = [ 'vstep-vpn' , 'vstep-ua' , 'vstep-email' , 'vstep-country' , 'vstep-create' ] ;
2958+ const interval = setInterval ( ( ) => {
2959+ if ( stepIndex < steps . length ) {
2960+ const el = document . getElementById ( steps [ stepIndex ] ) ;
2961+ if ( el ) {
2962+ el . classList . remove ( 'active' ) ;
2963+ el . classList . add ( 'done' ) ;
2964+ el . querySelector ( '.vstep-spinner, .vstep-pending' ) . outerHTML = '<svg class="vstep-check" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--accent-green)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>' ;
2965+ }
2966+ stepIndex ++ ;
2967+ if ( stepIndex < steps . length ) {
2968+ const next = document . getElementById ( steps [ stepIndex ] ) ;
2969+ if ( next ) {
2970+ next . classList . add ( 'active' ) ;
2971+ next . querySelector ( '.vstep-pending' ) . outerHTML = '<span class="vstep-spinner"></span>' ;
2972+ }
2973+ }
2974+ } else {
2975+ clearInterval ( interval ) ;
2976+ }
2977+ } , 600 ) ;
2978+
2979+ overlay . _interval = interval ;
2980+ }
2981+
2982+ function showVerificationSuccess ( name ) {
2983+ const overlay = document . getElementById ( 'verification-overlay' ) ;
2984+ if ( ! overlay ) return ;
2985+ clearInterval ( overlay . _interval ) ;
2986+
2987+ const steps = overlay . querySelectorAll ( '.verification-step' ) ;
2988+ steps . forEach ( s => {
2989+ s . classList . remove ( 'active' ) ;
2990+ s . classList . add ( 'done' ) ;
2991+ const icon = s . querySelector ( '.vstep-spinner, .vstep-pending' ) ;
2992+ if ( icon ) icon . outerHTML = '<svg class="vstep-check" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--accent-green)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>' ;
2993+ } ) ;
2994+
2995+ overlay . querySelector ( '.verification-card' ) . innerHTML = html `
2996+ < svg class ="verification-success-icon " width ="56 " height ="56 " viewBox ="0 0 24 24 " fill ="none " stroke ="var(--accent-green) " stroke-width ="2 " stroke-linecap ="round " stroke-linejoin ="round "> < path d ="M22 11.08V12a10 10 0 1 1-5.93-9.14 "/> < polyline points ="22 4 12 14.01 9 11.01 "/> </ svg >
2997+ < h2 class ="verification-title "> Server Created!</ h2 >
2998+ < p class ="verification-subtitle "> "${ escapeHtml ( name ) } " is now being set up.</ p >
2999+ ` ;
3000+ }
3001+
3002+ function showVerificationError ( message ) {
3003+ const overlay = document . getElementById ( 'verification-overlay' ) ;
3004+ if ( ! overlay ) return ;
3005+ clearInterval ( overlay . _interval ) ;
3006+
3007+ const steps = overlay . querySelectorAll ( '.verification-step.active' ) ;
3008+ steps . forEach ( s => {
3009+ s . classList . remove ( 'active' ) ;
3010+ s . classList . add ( 'failed' ) ;
3011+ const icon = s . querySelector ( '.vstep-spinner' ) ;
3012+ if ( icon ) icon . outerHTML = '<svg class="vstep-cross" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--accent-red)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>' ;
3013+ } ) ;
3014+
3015+ const card = overlay . querySelector ( '.verification-card' ) ;
3016+ card . innerHTML = html `
3017+ < svg class ="verification-error-icon " width ="56 " height ="56 " viewBox ="0 0 24 24 " fill ="none " stroke ="var(--accent-red) " stroke-width ="2 " stroke-linecap ="round " stroke-linejoin ="round "> < circle cx ="12 " cy ="12 " r ="10 "/> < line x1 ="15 " y1 ="9 " x2 ="9 " y2 ="15 "/> < line x1 ="9 " y1 ="9 " x2 ="15 " y2 ="15 "/> </ svg >
3018+ < h2 class ="verification-title " style ="color:var(--accent-red) "> Verification Failed</ h2 >
3019+ < p class ="verification-subtitle "> ${ escapeHtml ( message ) } </ p >
3020+ < button class ="btn btn-primary " id ="verification-retry-btn " style ="margin-top:16px "> Go Back</ button >
3021+ ` ;
3022+
3023+ document . getElementById ( 'verification-retry-btn' ) . addEventListener ( 'click' , ( ) => {
3024+ overlay . remove ( ) ;
3025+ } ) ;
3026+ }
3027+
3028+ function removeVerificationOverlay ( ) {
3029+ const overlay = document . getElementById ( 'verification-overlay' ) ;
3030+ if ( overlay ) {
3031+ clearInterval ( overlay . _interval ) ;
3032+ overlay . remove ( ) ;
3033+ }
3034+ }
3035+
29203036async function handleWizardCreate ( ) {
29213037 const btn = $ ( '#wizard-create-btn' ) ;
29223038 btn . disabled = true ;
@@ -2935,16 +3051,21 @@ async function handleWizardCreate() {
29353051 const environment = { } ;
29363052 const dockerImage = createState . selectedDockerImage || '' ;
29373053
3054+ showVerificationPage ( name ) ;
3055+
29383056 try {
29393057 const capToken = document . querySelector ( '[name="cap-token"]' ) ?. value || '' ;
29403058 await api ( '/servers/create' , {
29413059 method : 'POST' ,
29423060 body : JSON . stringify ( { name, nestId : nest . pteroNestId , eggId : egg . eggId , environment, capToken, dockerImage } ) ,
29433061 } ) ;
2944- showToast ( `Server "${ name } " created successfully!` , 'success' ) ;
2945- navigateTo ( 'servers' ) ;
3062+ showVerificationSuccess ( name ) ;
3063+ setTimeout ( ( ) => {
3064+ removeVerificationOverlay ( ) ;
3065+ navigateTo ( 'servers' ) ;
3066+ } , 2000 ) ;
29463067 } catch ( err ) {
2947- showToast ( err . message , 'error' ) ;
3068+ showVerificationError ( err . message ) ;
29483069 btn . disabled = false ;
29493070 btn . innerHTML = '<i data-lucide="plus" style="width:16px;height:16px"></i> Create Server' ;
29503071 initIcons ( ) ;
0 commit comments