@@ -128,6 +128,45 @@ class PwnedManager {
128128 console . warn ( "⚠️ WebSocket not ready." ) ;
129129 }
130130 }
131+
132+ /**
133+ * Displays vanilla toast with a success or fail message.
134+ * This function updates the snackbar text, applies the correct styling,
135+ * and animates a progress bar that disappears after 3 seconds.
136+ *
137+ * @param {string } message - The message to display inside the snackbar.
138+ * @param {"success" | "fail" } type - Determines the appearance of the snackbar: green for success, red for fail.
139+ *
140+ * @returns {void } This function does not return a value.
141+ */
142+ public showAlert ( message : string , type : "success" | "fail" ) : void {
143+ const snackbar = document . getElementById ( "snackbar" ) ;
144+ const textElement = document . getElementById ( "snackbar-text" ) ;
145+ const progressBar = document . querySelector ( ".progress-bar" ) as HTMLElement ;
146+
147+ if ( ! snackbar || ! textElement || ! progressBar ) {
148+ console . error ( "Snackbar elements not found." ) ;
149+ return ;
150+ }
151+
152+ snackbar . className = `show ${ type } ` ;
153+
154+ if ( type === "success" ) {
155+ textElement . textContent = `✅ ${ message } ` ;
156+ } else {
157+ textElement . textContent = `❌ ${ message } ` ;
158+ }
159+
160+ progressBar . style . width = "0%" ;
161+ progressBar . style . transition = "none" ;
162+ void progressBar . offsetWidth ;
163+ progressBar . style . transition = "width 3s linear" ;
164+ progressBar . style . width = "100%" ;
165+
166+ setTimeout ( ( ) => {
167+ snackbar . classList . remove ( "show" , "success" , "fail" ) ;
168+ } , 3000 ) ;
169+ }
131170}
132171
133172const accountManager = new PwnedManager ( ) ;
@@ -177,6 +216,15 @@ Neutralino.events.on("ready", async () => {
177216 // eslint-disable-next-line @typescript-eslint/no-explicit-any
178217 } as unknown as any ) ;
179218
219+ if ( ! file || file . length === 0 ) {
220+ console . warn ( "⚠️ No file selected." ) ;
221+ return ;
222+ }
223+ if ( ! file [ 0 ] . includes ( "nikke_launcher.exe" ) ) {
224+ await Neutralino . os . showNotification ( "Oops :/" , "Please select nikke_launcher.exe" , "ERROR" ) ;
225+ accountManager . showAlert ( "Please select nikke_launcher.exe" , "fail" ) ;
226+ return ;
227+ }
180228 if ( file && file . length > 0 ) {
181229 launcherPath = file [ 0 ] ; // Store selected path in global variable
182230 await Neutralino . storage . setData ( "nikkeLauncherPath" , launcherPath ) ;
@@ -186,6 +234,7 @@ Neutralino.events.on("ready", async () => {
186234 } catch ( error ) {
187235 console . error ( "Error selecting file:" , error ) ;
188236 await Neutralino . os . showNotification ( "Oops :/" , "Failed to select file." , "ERROR" ) ;
237+ accountManager . showAlert ( "Failed to select file." , "fail" ) ;
189238 }
190239 } ) ;
191240
@@ -225,11 +274,12 @@ Neutralino.events.on("ready", async () => {
225274
226275 const updatedAccounts = Array . from ( accountMap . values ( ) ) ;
227276 await Neutralino . storage . setData ( "accounts" , JSON . stringify ( updatedAccounts ) ) ;
228- alert ( "✅ Accounts Registered!") ;
277+ accountManager . showAlert ( " Accounts Registered!" , "success ") ;
229278 await accountManager . loadAccounts ( ) ;
230279 } catch ( e ) {
231280 console . error ( "Invalid JSON format!" , e ) ;
232281 await Neutralino . os . showNotification ( "Oops :/" , "Invalid JSON format! Please correct it." , "ERROR" ) ;
282+ accountManager . showAlert ( "Invalid JSON format! Please correct it." , "fail" ) ;
233283 }
234284 } ) ;
235285
@@ -253,13 +303,14 @@ Neutralino.events.on("ready", async () => {
253303
254304 if ( selectedIndex === "" ) {
255305 await Neutralino . os . showNotification ( ">:(" , "Please select an account!" , "ERROR" ) ;
306+ accountManager . showAlert ( "Please select an account!" , "fail" ) ;
256307 return ;
257308 }
258309
259310 try {
260311 const data = await Neutralino . storage . getData ( "accounts" ) ;
261312 if ( ! data ) {
262- alert ( "No accounts found! Register first." ) ;
313+ accountManager . showAlert ( "No accounts found! Register first." , "fail ") ;
263314 return ;
264315 }
265316 const accounts = JSON . parse ( data ) ;
@@ -275,6 +326,7 @@ Neutralino.events.on("ready", async () => {
275326 await Neutralino . os . execCommand ( `powershell -ExecutionPolicy Bypass -Command "Add-Type -AssemblyName System.Windows.Forms; Start-Sleep -Seconds 5; [System.Windows.Forms.SendKeys]::SendWait('{TAB}${ emailFixed } {TAB}${ passwordFixed } {ENTER}')"` ) ;
276327 console . log ( "✅ Login complete!" ) ;
277328 await Neutralino . os . showNotification ( `${ account . nickname } ` , "Successfully logged in!" ) ;
329+ accountManager . showAlert ( `Logged in as ${ account . nickname } !` , "success" ) ;
278330
279331 accountManager . updateDiscordRPC ( `Playing NIKKE ${ currentArray } / ${ accounts . length } accounts` , `Logged in as ${ account . nickname } ` ) ;
280332 } catch ( error ) {
@@ -299,7 +351,8 @@ Neutralino.events.on("ready", async () => {
299351 ( document . getElementById ( "removeBtn" ) as HTMLButtonElement ) . addEventListener ( "click" , async ( ) => {
300352 const selectedEmail = ( document . getElementById ( "accountSelect" ) as HTMLSelectElement ) . value ;
301353 if ( ! selectedEmail ) {
302- alert ( "Please select an account to remove." ) ;
354+ accountManager . showAlert ( "Please select an account!" , "fail" ) ;
355+
303356 return ;
304357 }
305358
@@ -308,7 +361,7 @@ Neutralino.events.on("ready", async () => {
308361 const updatedAccounts = accounts . filter ( ( acc : Account ) => acc . email !== selectedEmail ) ;
309362
310363 await Neutralino . storage . setData ( "accounts" , JSON . stringify ( updatedAccounts ) ) ;
311- alert ( `❌ Account ${ selectedEmail } removed!`) ;
364+ accountManager . showAlert ( ` Account ${ selectedEmail } removed!`, "success" ) ;
312365 await accountManager . loadAccounts ( ) ;
313366 } ) ;
314367} ) ;
0 commit comments