diff --git a/frontend/src/ts/elements/input-indicator.ts b/frontend/src/ts/elements/input-indicator.ts index 756225d03..4ed716e5c 100644 --- a/frontend/src/ts/elements/input-indicator.ts +++ b/frontend/src/ts/elements/input-indicator.ts @@ -8,6 +8,7 @@ interface InputIndicatorOption { export class InputIndicator { private parentElement: JQuery; private options: Record; + private currentStatus: keyof typeof this.options | null; constructor( parentElement: JQuery, @@ -18,6 +19,7 @@ export class InputIndicator { } this.parentElement = parentElement; this.options = options; + this.currentStatus = null; let indicator = `
`; @@ -50,11 +52,14 @@ export class InputIndicator { hide(): void { this.parentElement.find(".statusIndicator div").addClass("hidden"); + this.currentStatus = null; } show(optionId: keyof typeof this.options, messageOverride?: string): void { this.hide(); + this.currentStatus = optionId; + const indicator = this.parentElement.find(`[data-option-id="${optionId}"]`); indicator.removeClass("hidden"); @@ -68,4 +73,8 @@ export class InputIndicator { indicator.attr("aria-label", messageOverride); } } + + get(): keyof typeof this.options | null { + return this.currentStatus; + } } diff --git a/frontend/src/ts/pages/login.ts b/frontend/src/ts/pages/login.ts index 6a73c6896..2e302aed8 100644 --- a/frontend/src/ts/pages/login.ts +++ b/frontend/src/ts/pages/login.ts @@ -22,56 +22,79 @@ export function hidePreloader(): void { $(".pageLogin .preloader").addClass("hidden"); } +const updateSignupButton = (): void => { + const $button = $(".page.pageLogin .register.side .button"); + + if ( + nameIndicator.get() !== "available" || + emailIndicator.get() !== "valid" || + verifyEmailIndicator.get() !== "match" || + passwordIndicator.get() !== "good" || + verifyPasswordIndicator.get() !== "match" + ) { + $button.addClass("disabled"); + } else { + $button.removeClass("disabled"); + } +}; + const checkNameDebounced = debounce(1000, async () => { const val = $( ".page.pageLogin .register.side .usernameInput" ).val() as string; - if (!val) return; + + if (!val) { + updateSignupButton(); + return; + } const response = await Ape.users.getNameAvailability(val); if (response.status === 200) { nameIndicator.show("available", response.message); - return; - } - - if (response.status == 422) { + } else if (response.status === 422) { nameIndicator.show("unavailable", response.message); - return; - } - - if (response.status == 409) { + } else if (response.status === 409) { nameIndicator.show("taken", response.message); - return; - } - - if (response.status !== 200) { + } else { nameIndicator.show("unavailable", response.message); - return Notifications.add( + Notifications.add( "Failed to check name availability: " + response.message, -1 ); } -}); -const checkEmailsMatch = (): void => { - const email = $(".page.pageLogin .register.side .emailInput").val(); - const verifyEmail = $( - ".page.pageLogin .register.side .verifyEmailInput" - ).val(); - verifyEmailIndicator.show(email === verifyEmail ? "match" : "mismatch"); -}; + updateSignupButton(); +}); const checkEmail = (): void => { const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const email = $(".page.pageLogin .register.side .emailInput").val() as string; + if (emailRegex.test(email)) { + emailIndicator.show("valid"); + } else { + emailIndicator.show("invalid"); + } - emailIndicator.show(emailRegex.test(email) ? "valid" : "invalid"); + updateSignupButton(); +}; + +const checkEmailsMatch = (): void => { + const email = $(".page.pageLogin .register.side .emailInput").val(); + const verifyEmail = $( + ".page.pageLogin .register.side .verifyEmailInput" + ).val(); + if (email === verifyEmail) { + verifyEmailIndicator.show("match"); + } else { + verifyEmailIndicator.show("mismatch"); + } + + updateSignupButton(); }; const checkPassword = (): void => { - passwordIndicator.show("good"); const password = $( ".page.pageLogin .register.side .passwordInput" ).val() as string; @@ -80,20 +103,20 @@ const checkPassword = (): void => { if (password.length < 8) { passwordIndicator.show("short", "Password must be at least 8 characters"); return; + } else { + const hasCapital = password.match(/[A-Z]/); + const hasNumber = password.match(/[\d]/); + const hasSpecial = password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/); + if (!hasCapital || !hasNumber || !hasSpecial) { + passwordIndicator.show( + "weak", + "Password must contain at least one capital letter, number, and special character" + ); + } else { + passwordIndicator.show("good", "Password is good"); + } } - - const hasCapital = password.match(/[A-Z]/); - const hasNumber = password.match(/[\d]/); - const hasSpecial = password.match(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/); - if (!hasCapital || !hasNumber || !hasSpecial) { - passwordIndicator.show( - "weak", - "Password must contain at least one capital letter, number, and special character" - ); - return; - } - - passwordIndicator.show("good", "Password is good"); + updateSignupButton(); }; const checkPasswordsMatch = (): void => { @@ -101,9 +124,13 @@ const checkPasswordsMatch = (): void => { const verifyPassword = $( ".page.pageLogin .register.side .verifyPasswordInput" ).val(); - verifyPasswordIndicator.show( - password === verifyPassword ? "match" : "mismatch" - ); + if (password === verifyPassword) { + verifyPasswordIndicator.show("match"); + } else { + verifyPasswordIndicator.show("mismatch"); + } + + updateSignupButton(); }; const nameIndicator = new InputIndicator( diff --git a/frontend/static/html/pages/login.html b/frontend/static/html/pages/login.html index cd06dc16d..38d67b766 100644 --- a/frontend/static/html/pages/login.html +++ b/frontend/static/html/pages/login.html @@ -47,7 +47,7 @@ name="verify-password" />
-
+
Sign Up