From 859aa99102c63b2dd44031312af02b4b50927a61 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Tue, 14 Jul 2026 22:56:53 -0700
Subject: [PATCH 01/14] Handle basic email verification
---
src/app/domain/user.ts | 1 +
src/app/login/login-home/login-home.component.html | 5 +++++
src/app/login/login-home/login-home.component.ts | 13 +++++++++++++
src/app/services/user.service.ts | 7 +++++++
4 files changed, 26 insertions(+)
diff --git a/src/app/domain/user.ts b/src/app/domain/user.ts
index cb64a9233ce..29b973cd666 100644
--- a/src/app/domain/user.ts
+++ b/src/app/domain/user.ts
@@ -5,6 +5,7 @@ export class User {
isGoogleUser: boolean = false;
isRecaptchaInvalid: boolean = false;
isRecaptchaRequired: boolean;
+ isVerified: boolean;
language: string;
lastName: string;
microsoftUserId: string;
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index afc553f51f7..8a6a8d7fc1e 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -56,6 +56,11 @@ Sign in to WISE
>
}
}
+ @if (isTeacherVerificationFailed) {
+
+ Your email has not been verified. Check your email for a verification link.
+
+ }
{
+ if (isVerified) {
+ this.authenticateUser();
+ } else {
+ this.processing = false;
+ this.credentials.password = '';
+ this.isTeacherVerificationFailed = true;
+ }
+ });
+ }
+
+ private authenticateUser(): void {
this.userService.authenticate(this.credentials, (response: any) => {
if (this.userService.isAuthenticated) {
this.router.navigateByUrl(this.getRedirectUrl(''));
diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts
index d19e24ab221..079595c792a 100644
--- a/src/app/services/user.service.ts
+++ b/src/app/services/user.service.ts
@@ -17,6 +17,7 @@ export class UserService {
private googleUserUrl = '/api/google-user/get-user';
private checkAuthenticationUrl = '/api/user/check-authentication';
private changePasswordUrl = '/api/user/password';
+ private checkVerifiedUrl = '/api/user/is-verified';
private languagesUrl = '/api/user/languages';
private contactUrl = '/api/contact';
private unlinkGoogleAccountUrl = '/api/google-user/unlink-account';
@@ -76,6 +77,12 @@ export class UserService {
return this.getUser().getValue().isGoogleUser;
}
+ isVerified(username: string): Observable {
+ return this.http.get(this.checkVerifiedUrl, {
+ params: new HttpParams().set('username', username)
+ });
+ }
+
retrieveUserPromise(): Promise {
return this.retrieveUser().toPromise();
}
From 66628fc4445691462e8751b7549e53b9b27b6089 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Wed, 15 Jul 2026 15:40:01 -0700
Subject: [PATCH 02/14] Removed sign in button and updated text on teacher
registration complete page
---
.../register-teacher-complete.component.html | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/app/register/register-teacher-complete/register-teacher-complete.component.html b/src/app/register/register-teacher-complete/register-teacher-complete.component.html
index 4874a2e7919..26416c08cd4 100644
--- a/src/app/register/register-teacher-complete/register-teacher-complete.component.html
+++ b/src/app/register/register-teacher-complete/register-teacher-complete.component.html
@@ -7,11 +7,15 @@ Your WISE account has been created!.
}
- You should receive an email with your account details shortly.
+ @if (!socialAccount) {
+ To sign in, you must verify your account.
+
+ You should receive an email shortly with instructions to complete your registration.
+
+ } @else {
+ You should receive an email with your account details shortly.
+ }
- @if (!socialAccount) {
- Sign In to Get Started
- }
@if (isUsingGoogleId) {
Date: Wed, 15 Jul 2026 15:40:57 -0700
Subject: [PATCH 03/14] Show a confirmation when a user's account has just been
verified
---
src/app/login/login-home/login-home.component.html | 3 +++
src/app/login/login-home/login-home.component.ts | 5 +++++
2 files changed, 8 insertions(+)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index 8a6a8d7fc1e..f544d2f71a9 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -61,6 +61,9 @@ Sign in to WISE
Your email has not been verified. Check your email for a verification link.
}
+ @if (showVerifiedConfirmation) {
+ Your email has been verified.
+ }
{
this.processing = true;
this.passwordError = false;
+ this.showVerifiedConfirmation = false;
if (this.isRecaptchaEnabled) {
this.credentials.recaptchaResponse = await lastValueFrom(
this.recaptchaV3Service.execute('importantAction')
From bc048abe5cb9f985cc55367233ea2ff73629ee68 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Thu, 16 Jul 2026 15:50:03 -0700
Subject: [PATCH 04/14] Allow teachers to resend the verification email
---
.../login-home/login-home.component.html | 18 ++++++-
.../login/login-home/login-home.component.ts | 49 ++++++++++++++++---
2 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index f544d2f71a9..f457fe2c161 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -56,12 +56,20 @@ Sign in to WISE
>
}
}
- @if (isTeacherVerificationFailed) {
+ @if (showTeacherVerificationFailed()) {
Your email has not been verified. Check your email for a verification link.
+ @if (allowResendEmail()) {
+ Click here resend the verification email.
+ } @else {
+ Please wait to send another verification email ({{ resendEmailWaitSeconds() }}).
+ }
}
- @if (showVerifiedConfirmation) {
+ @if (showEmailSentConfirmation()) {
+ A verification email has been sent.
+ }
+ @if (showVerifiedConfirmation()) {
Your email has been verified.
}
@@ -114,6 +122,12 @@
Sign in to WISE
Forgot username or password?
+
+
+
New to WISE? Join for free!
diff --git a/src/app/login/login-home/login-home.component.ts b/src/app/login/login-home/login-home.component.ts
index b2543e2700d..89fedde8d55 100644
--- a/src/app/login/login-home/login-home.component.ts
+++ b/src/app/login/login-home/login-home.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, OnInit, signal, ViewChild } from '@angular/core';
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
import { UserService } from '../../services/user.service';
import { ConfigService } from '../../services/config.service';
@@ -11,6 +11,7 @@ import { MatInput } from '@angular/material/input';
import { MatButton } from '@angular/material/button';
import { MatProgressBar } from '@angular/material/progress-bar';
import { MatDivider } from '@angular/material/divider';
+import { HttpClient, HttpParams } from '@angular/common/http';
@Component({
imports: [
@@ -38,16 +39,22 @@ export class LoginHomeComponent implements OnInit {
isRecaptchaEnabled: boolean = false;
isRecaptchaVerificationFailed: boolean = false;
isReLoginDueToErrorSavingData: boolean;
- protected isTeacherVerificationFailed: boolean = false;
protected microsoftAuthenticationEnabled: boolean;
passwordError: boolean = false;
processing: boolean = false;
@ViewChild('recaptchaRef', { static: false }) recaptchaRef: any;
+ private resendEmailEndpoint = '/api/teacher/verify-email';
+ private resendEmailInterval: any;
+ protected resendEmailWaitSeconds = signal(0);
+ protected showEmailSentConfirmation = signal(false);
+ protected showTeacherVerificationFailed = signal(false);
protected showSocialLogin: boolean;
- protected showVerifiedConfirmation: boolean = false;
+ protected showVerificationResend = signal(false);
+ protected showVerifiedConfirmation = signal(false);
constructor(
private configService: ConfigService,
+ private http: HttpClient,
private router: Router,
private route: ActivatedRoute,
private recaptchaV3Service: ReCaptchaV3Service,
@@ -80,11 +87,19 @@ export class LoginHomeComponent implements OnInit {
this.accessCode = params['accessCode'];
}
if (params['verified'] != null) {
- this.showVerifiedConfirmation = params['verified'] === 'true';
+ this.showVerifiedConfirmation.set(params['verified'] === 'true');
}
});
this.isReLoginDueToErrorSavingData = this.isRedirectToAppRoutes();
this.isRecaptchaEnabled = this.configService.isRecaptchaEnabled();
+
+ this.resendEmailInterval = setInterval(() => {
+ this.resendEmailWaitSeconds.update((current) => current - 1);
+ }, 1000);
+ }
+
+ ngOnDestroy(): void {
+ clearInterval(this.resendEmailInterval);
}
private isRedirectToAppRoutes(): boolean {
@@ -95,7 +110,8 @@ export class LoginHomeComponent implements OnInit {
async login(): Promise {
this.processing = true;
this.passwordError = false;
- this.showVerifiedConfirmation = false;
+ this.showVerifiedConfirmation.set(false);
+ this.showEmailSentConfirmation.set(false);
if (this.isRecaptchaEnabled) {
this.credentials.recaptchaResponse = await lastValueFrom(
this.recaptchaV3Service.execute('importantAction')
@@ -107,7 +123,7 @@ export class LoginHomeComponent implements OnInit {
} else {
this.processing = false;
this.credentials.password = '';
- this.isTeacherVerificationFailed = true;
+ this.showTeacherVerificationFailed.set(true);
}
});
}
@@ -154,4 +170,25 @@ export class LoginHomeComponent implements OnInit {
private appendAccessCodeParameter(url: string): string {
return `${url}${url.includes('?') ? '&' : '?'}accessCode=${this.accessCode}`;
}
+
+ protected toggleShowVerificationResend(e: Event): void {
+ e.preventDefault();
+ this.showVerificationResend.update((current) => !current);
+ }
+
+ protected allowResendEmail(): boolean {
+ return this.resendEmailWaitSeconds() <= 0;
+ }
+
+ protected resendEmail(e: Event): void {
+ e.preventDefault();
+ const params = new HttpParams().set('username', this.credentials.username);
+ this.http
+ .post(`${this.resendEmailEndpoint}`, null, { params })
+ .subscribe((response) => {
+ this.showTeacherVerificationFailed.set(false);
+ this.resendEmailWaitSeconds.set(10);
+ this.showEmailSentConfirmation.set(true);
+ });
+ }
}
From 7c686625ed0b40d132995be0fbd2e4e141840c58 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Fri, 17 Jul 2026 12:35:53 -0700
Subject: [PATCH 05/14] Update endpoints
---
src/app/login/login-home/login-home.component.ts | 2 +-
src/app/services/user.service.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.ts b/src/app/login/login-home/login-home.component.ts
index 89fedde8d55..d94fc8518ce 100644
--- a/src/app/login/login-home/login-home.component.ts
+++ b/src/app/login/login-home/login-home.component.ts
@@ -43,7 +43,7 @@ export class LoginHomeComponent implements OnInit {
passwordError: boolean = false;
processing: boolean = false;
@ViewChild('recaptchaRef', { static: false }) recaptchaRef: any;
- private resendEmailEndpoint = '/api/teacher/verify-email';
+ private resendEmailEndpoint = '/api/teacher/register/send-verify-email';
private resendEmailInterval: any;
protected resendEmailWaitSeconds = signal(0);
protected showEmailSentConfirmation = signal(false);
diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts
index 079595c792a..cb3abfa70b9 100644
--- a/src/app/services/user.service.ts
+++ b/src/app/services/user.service.ts
@@ -17,7 +17,7 @@ export class UserService {
private googleUserUrl = '/api/google-user/get-user';
private checkAuthenticationUrl = '/api/user/check-authentication';
private changePasswordUrl = '/api/user/password';
- private checkVerifiedUrl = '/api/user/is-verified';
+ private checkVerifiedUrl = '/api/teacher/is-verified';
private languagesUrl = '/api/user/languages';
private contactUrl = '/api/contact';
private unlinkGoogleAccountUrl = '/api/google-user/unlink-account';
From 5c3bd8b9ee6edc09b1b9f58eb472e54fb96750fd Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Fri, 17 Jul 2026 12:56:04 -0700
Subject: [PATCH 06/14] Show email sent confirmation if email was successful,
otherwise show error message
---
.../login/login-home/login-home.component.html | 4 ++++
.../login/login-home/login-home.component.ts | 17 +++++++++++------
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index f457fe2c161..68969e7c2f1 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -68,6 +68,10 @@ Sign in to WISE
}
@if (showEmailSentConfirmation()) {
A verification email has been sent.
+ } @else if (showEmailSentError()) {
+
+ There was an error sending the verification email. Please try again later.
+
}
@if (showVerifiedConfirmation()) {
Your email has been verified.
diff --git a/src/app/login/login-home/login-home.component.ts b/src/app/login/login-home/login-home.component.ts
index d94fc8518ce..15213cdd6af 100644
--- a/src/app/login/login-home/login-home.component.ts
+++ b/src/app/login/login-home/login-home.component.ts
@@ -47,6 +47,7 @@ export class LoginHomeComponent implements OnInit {
private resendEmailInterval: any;
protected resendEmailWaitSeconds = signal(0);
protected showEmailSentConfirmation = signal(false);
+ protected showEmailSentError = signal(false);
protected showTeacherVerificationFailed = signal(false);
protected showSocialLogin: boolean;
protected showVerificationResend = signal(false);
@@ -112,6 +113,7 @@ export class LoginHomeComponent implements OnInit {
this.passwordError = false;
this.showVerifiedConfirmation.set(false);
this.showEmailSentConfirmation.set(false);
+ this.showEmailSentError.set(false);
if (this.isRecaptchaEnabled) {
this.credentials.recaptchaResponse = await lastValueFrom(
this.recaptchaV3Service.execute('importantAction')
@@ -182,13 +184,16 @@ export class LoginHomeComponent implements OnInit {
protected resendEmail(e: Event): void {
e.preventDefault();
+ this.resendEmailWaitSeconds.set(60);
+ this.showTeacherVerificationFailed.set(false);
const params = new HttpParams().set('username', this.credentials.username);
- this.http
- .post(`${this.resendEmailEndpoint}`, null, { params })
- .subscribe((response) => {
- this.showTeacherVerificationFailed.set(false);
- this.resendEmailWaitSeconds.set(10);
+ this.http.post(`${this.resendEmailEndpoint}`, null, { params }).subscribe({
+ next: () => {
this.showEmailSentConfirmation.set(true);
- });
+ },
+ error: () => {
+ this.showEmailSentError.set(true);
+ }
+ });
}
}
From 0933bacf86f05b35adeb3df9455895a2b1bd9d16 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Mon, 20 Jul 2026 17:17:59 -0700
Subject: [PATCH 07/14] Combine signals into one state signal
---
.../login-home/login-home.component.html | 16 +++--------
.../login/login-home/login-home.component.ts | 27 +++++++------------
2 files changed, 13 insertions(+), 30 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index 68969e7c2f1..903c5ed6cb1 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -56,7 +56,7 @@ Sign in to WISE
>
}
}
- @if (showTeacherVerificationFailed()) {
+ @if (verificationState() === 'unverified') {
Your email has not been verified. Check your email for a verification link.
@if (allowResendEmail()) {
@@ -65,15 +65,13 @@
Sign in to WISE
Please wait to send another verification email ({{ resendEmailWaitSeconds() }}).
}
- }
- @if (showEmailSentConfirmation()) {
+ } @else if (verificationState() === 'emailSent') {
A verification email has been sent.
- } @else if (showEmailSentError()) {
+ } @else if (verificationState() === 'emailError') {
There was an error sending the verification email. Please try again later.
- }
- @if (showVerifiedConfirmation()) {
+ } @else if (verificationState() === 'confirmVerified') {
Your email has been verified.
}
@@ -126,12 +124,6 @@
Sign in to WISE
Forgot username or password?
-
-
-
New to WISE? Join for free!
diff --git a/src/app/login/login-home/login-home.component.ts b/src/app/login/login-home/login-home.component.ts
index 15213cdd6af..e177c73ba4b 100644
--- a/src/app/login/login-home/login-home.component.ts
+++ b/src/app/login/login-home/login-home.component.ts
@@ -46,12 +46,10 @@ export class LoginHomeComponent implements OnInit {
private resendEmailEndpoint = '/api/teacher/register/send-verify-email';
private resendEmailInterval: any;
protected resendEmailWaitSeconds = signal(0);
- protected showEmailSentConfirmation = signal(false);
- protected showEmailSentError = signal(false);
- protected showTeacherVerificationFailed = signal(false);
protected showSocialLogin: boolean;
- protected showVerificationResend = signal(false);
- protected showVerifiedConfirmation = signal(false);
+ protected verificationState = signal<
+ 'none' | 'confirmVerified' | 'emailSent' | 'emailError' | 'unverified'
+ >('none');
constructor(
private configService: ConfigService,
@@ -88,7 +86,7 @@ export class LoginHomeComponent implements OnInit {
this.accessCode = params['accessCode'];
}
if (params['verified'] != null) {
- this.showVerifiedConfirmation.set(params['verified'] === 'true');
+ this.verificationState.set('confirmVerified');
}
});
this.isReLoginDueToErrorSavingData = this.isRedirectToAppRoutes();
@@ -111,9 +109,7 @@ export class LoginHomeComponent implements OnInit {
async login(): Promise {
this.processing = true;
this.passwordError = false;
- this.showVerifiedConfirmation.set(false);
- this.showEmailSentConfirmation.set(false);
- this.showEmailSentError.set(false);
+ this.verificationState.set('none');
if (this.isRecaptchaEnabled) {
this.credentials.recaptchaResponse = await lastValueFrom(
this.recaptchaV3Service.execute('importantAction')
@@ -125,7 +121,7 @@ export class LoginHomeComponent implements OnInit {
} else {
this.processing = false;
this.credentials.password = '';
- this.showTeacherVerificationFailed.set(true);
+ this.verificationState.set('unverified');
}
});
}
@@ -173,11 +169,6 @@ export class LoginHomeComponent implements OnInit {
return `${url}${url.includes('?') ? '&' : '?'}accessCode=${this.accessCode}`;
}
- protected toggleShowVerificationResend(e: Event): void {
- e.preventDefault();
- this.showVerificationResend.update((current) => !current);
- }
-
protected allowResendEmail(): boolean {
return this.resendEmailWaitSeconds() <= 0;
}
@@ -185,14 +176,14 @@ export class LoginHomeComponent implements OnInit {
protected resendEmail(e: Event): void {
e.preventDefault();
this.resendEmailWaitSeconds.set(60);
- this.showTeacherVerificationFailed.set(false);
+ this.verificationState.set('none');
const params = new HttpParams().set('username', this.credentials.username);
this.http.post(`${this.resendEmailEndpoint}`, null, { params }).subscribe({
next: () => {
- this.showEmailSentConfirmation.set(true);
+ this.verificationState.set('emailSent');
},
error: () => {
- this.showEmailSentError.set(true);
+ this.verificationState.set('emailError');
}
});
}
From 53c59d95cd04443d977a0d598ad3c163b0f53bcc Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Mon, 20 Jul 2026 17:23:10 -0700
Subject: [PATCH 08/14] Write/Fix tests
---
.../login-home/login-home.component.spec.ts | 63 +++++++++++++++----
1 file changed, 51 insertions(+), 12 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.spec.ts b/src/app/login/login-home/login-home.component.spec.ts
index 5e1870b21e1..0807b468171 100644
--- a/src/app/login/login-home/login-home.component.spec.ts
+++ b/src/app/login/login-home/login-home.component.spec.ts
@@ -8,6 +8,7 @@ import { By } from '@angular/platform-browser';
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { provideRouter, Router } from '@angular/router';
import { getErrorMessage } from '../../common/test-helper';
+import { DebugElement } from '@angular/core';
let component: LoginHomeComponent;
let configService: ConfigService;
@@ -76,35 +77,36 @@ function loginWithRecaptchaDisabled() {
component.isRecaptchaEnabled = false;
});
incorrectPassword();
- correctPassword();
+ correctPasswordVerifiedAccount();
+ unverifiedAccount();
+ unverifiedAccountWaitToResendEmail();
});
}
function incorrectPassword() {
describe('user enters incorrect password', () => {
- it('should show error message', fakeAsync(() => {
+ it('should show authentication error message', fakeAsync(() => {
spyOn(http, 'post').and.returnValue(of({}));
spyOn(http, 'get').and.returnValue(of(null));
+ spyOn(userService, 'isVerified').and.returnValue(of(true));
component.login();
tickAndDetectChanges();
- const errorMessageElement = fixture.debugElement
- .queryAll(By.css('p'))
- .find(
- (element) =>
- element.nativeElement.textContent.trim() ===
- 'Username and password not recognized. Please try again.'
- );
- expect(errorMessageElement.nativeElement.classList.contains('warn')).toBeTruthy();
+ const errorMessageElement = getErrorMessageElement(
+ 'Username and password not recognized. Please try again.'
+ );
+ expect(errorMessageElement).toBeDefined();
+ expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
expect(component.credentials.password).toEqual('');
}));
});
}
-function correctPassword() {
- describe('user enters correct password', () => {
+function correctPasswordVerifiedAccount() {
+ describe('user enters correct password and account is verified', () => {
it('should navigate to home page', fakeAsync(() => {
spyOn(http, 'post').and.returnValue(of({}));
spyOn(http, 'get').and.returnValue(of({ id: 1 }));
+ spyOn(userService, 'isVerified').and.returnValue(of(true));
const routerNavigateSpy = spyOn(router, 'navigateByUrl');
component.login();
tickAndDetectChanges();
@@ -113,6 +115,37 @@ function correctPassword() {
});
}
+function unverifiedAccount() {
+ describe('login attempt with unverified account', () => {
+ it('should show verification error message', fakeAsync(() => {
+ spyOn(userService, 'isVerified').and.returnValue(of(false));
+ component.login();
+ tickAndDetectChanges();
+ const errorMessageElement = getErrorMessageElement(
+ 'Your email has not been verified. Check your email for a verification link. Click here resend the verification email.'
+ );
+ expect(errorMessageElement).toBeDefined();
+ expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
+ }));
+ });
+}
+
+function unverifiedAccountWaitToResendEmail() {
+ describe('login attempt with unverified account and must wait to resend the email', () => {
+ it('should show verification error message with countdown to resend', fakeAsync(() => {
+ spyOn(userService, 'isVerified').and.returnValue(of(false));
+ component['resendEmailWaitSeconds'].set(60);
+ component.login();
+ tickAndDetectChanges();
+ const errorMessageElement = getErrorMessageElement(
+ 'Your email has not been verified. Check your email for a verification link. Please wait to send another verification email (60).'
+ );
+ expect(errorMessageElement).toBeDefined();
+ expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
+ }));
+ });
+}
+
function loginWithRecaptchaEnabled() {
xdescribe('recaptcha is enabled', () => {
beforeEach(() => {
@@ -138,3 +171,9 @@ function tickAndDetectChanges() {
tick();
fixture.detectChanges();
}
+
+function getErrorMessageElement(errorMsg: string): DebugElement | undefined {
+ return fixture.debugElement
+ .queryAll(By.css('p'))
+ .find((element) => element.nativeElement.textContent.trim() === errorMsg);
+}
From 03fc2a75d8a8e3e8ce34bad1f2cbed5a7141d3b3 Mon Sep 17 00:00:00 2001
From: Aaron Detre
Date: Mon, 20 Jul 2026 21:47:32 -0700
Subject: [PATCH 09/14] Show error if verification code does not match any user
in database
---
.../login/login-home/login-home.component.html | 18 +++++++++++-------
.../login/login-home/login-home.component.ts | 10 +++++++---
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index 903c5ed6cb1..19293e2f818 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -56,7 +56,15 @@ Sign in to WISE
>
}
}
- @if (verificationState() === 'unverified') {
+ @if (verificationState() === 'confirmVerified') {
+ Your email has been verified.
+ } @else if (verificationState() === 'emailError') {
+
+ There was an error sending the verification email. Please try again later.
+
+ } @else if (verificationState() === 'emailSent') {
+ A verification email has been sent.
+ } @else if (verificationState() === 'unverified') {
Your email has not been verified. Check your email for a verification link.
@if (allowResendEmail()) {
@@ -65,14 +73,10 @@
Sign in to WISE
Please wait to send another verification email ({{ resendEmailWaitSeconds() }}).
}
- } @else if (verificationState() === 'emailSent') {
- A verification email has been sent.
- } @else if (verificationState() === 'emailError') {
+ } @else if (verificationState() === 'verificationError') {
- There was an error sending the verification email. Please try again later.
+ Your account could not be verified. Make sure you click the link sent to your email.
- } @else if (verificationState() === 'confirmVerified') {
- Your email has been verified.
}
(0);
protected showSocialLogin: boolean;
protected verificationState = signal<
- 'none' | 'confirmVerified' | 'emailSent' | 'emailError' | 'unverified'
+ 'none' | 'confirmVerified' | 'emailError' | 'emailSent' | 'unverified' | 'verificationError'
>('none');
constructor(
@@ -85,8 +85,12 @@ export class LoginHomeComponent implements OnInit {
if (params['accessCode'] != null) {
this.accessCode = params['accessCode'];
}
- if (params['verified'] != null) {
- this.verificationState.set('confirmVerified');
+ if (params['verified']) {
+ if (params['verified'] === 'true') {
+ this.verificationState.set('confirmVerified');
+ } else if (params['verified'] === 'error') {
+ this.verificationState.set('verificationError');
+ }
}
});
this.isReLoginDueToErrorSavingData = this.isRedirectToAppRoutes();
From 71a91f5268338df4a23f7de8818a9b4c75a2be86 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Tue, 21 Jul 2026 18:49:32 +0000
Subject: [PATCH 10/14] Updated messages
---
src/messages.xlf | 68 +++++++++++++++++++++++++++++++++++++-----------
1 file changed, 53 insertions(+), 15 deletions(-)
diff --git a/src/messages.xlf b/src/messages.xlf
index 2abb06b8688..16141a41cdd 100644
--- a/src/messages.xlf
+++ b/src/messages.xlf
@@ -3271,7 +3271,7 @@
src/app/login/login-home/login-home.component.html
- 70,74
+ 88,92
src/app/modules/mobile-menu/mobile-menu.component.html
@@ -5670,7 +5670,7 @@
Recaptcha failed. Please reload the page and try again!
src/app/login/login-home/login-home.component.html
- 55,61
+ 55,59
src/app/register/register-student-form/register-student-form.component.html
@@ -5681,11 +5681,39 @@
160,164
+
+ Your email has not been verified. Check your email for a verification link. Click here resend the verification email. Please wait to send another verification email ( ).
+
+ src/app/login/login-home/login-home.component.html
+ 61,68
+
+
+
+ A verification email has been sent.
+
+ src/app/login/login-home/login-home.component.html
+ 69,71
+
+
+
+ There was an error sending the verification email. Please try again later.
+
+ src/app/login/login-home/login-home.component.html
+ 72,74
+
+
+
+ Your email has been verified.
+
+ src/app/login/login-home/login-home.component.html
+ 75,80
+
+
Sign in with Google
src/app/login/login-home/login-home.component.html
- 86,90
+ 104,108
src/app/register/register-google-user-already-exists/register-google-user-already-exists.component.html
@@ -5697,14 +5725,14 @@
src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 24,28
+ 28,32
Sign in with Microsoft
src/app/login/login-home/login-home.component.html
- 99,103
+ 117,121
src/app/register/register-microsoft-user-already-exists/register-microsoft-user-already-exists.component.html
@@ -5716,21 +5744,21 @@
src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 36,41
+ 40,45
Forgot username or password?
src/app/login/login-home/login-home.component.html
- 108,109
+ 126,127
New to WISE? Join for free!
src/app/login/login-home/login-home.component.html
- 109,110
+ 127,128
@@ -6935,7 +6963,7 @@
src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 22,24
+ 26,28
src/app/student/account/edit-profile/edit-profile.component.html
@@ -7844,7 +7872,7 @@
src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 35,37
+ 39,41
@@ -7871,10 +7899,6 @@
src/app/register/register-student-complete/register-student-complete.component.html
15,19
-
- src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 13,17
-
Create Student Account
@@ -8012,11 +8036,25 @@
31,36
+
+ To sign in, you must verify your account.
+
+ src/app/register/register-teacher-complete/register-teacher-complete.component.html
+ 11,13
+
+
+
+ You should receive an email shortly with instructions to complete your registration.
+
+ src/app/register/register-teacher-complete/register-teacher-complete.component.html
+ 13,16
+
+
You should receive an email with your account details shortly.
src/app/register/register-teacher-complete/register-teacher-complete.component.html
- 10,13
+ 16,21
From 8270965bec2d0c311f421901446a0cf7d23ae288 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Tue, 21 Jul 2026 20:02:21 +0000
Subject: [PATCH 11/14] Updated messages
---
src/messages.xlf | 37 ++++++++++++++++++++++---------------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/src/messages.xlf b/src/messages.xlf
index eab92f37308..bb587076051 100644
--- a/src/messages.xlf
+++ b/src/messages.xlf
@@ -3271,7 +3271,7 @@
src/app/login/login-home/login-home.component.html
- 88,92
+ 92,96
src/app/modules/mobile-menu/mobile-menu.component.html
@@ -5681,39 +5681,46 @@
160,164
-
- Your email has not been verified. Check your email for a verification link. Click here resend the verification email. Please wait to send another verification email ( ).
+
+ Your email has been verified.
+
+ src/app/login/login-home/login-home.component.html
+ 60,62
+
+
+
+ There was an error sending the verification email. Please try again later.
src/app/login/login-home/login-home.component.html
- 61,68
+ 63,65
A verification email has been sent.
src/app/login/login-home/login-home.component.html
- 69,71
+ 66,68
-
- There was an error sending the verification email. Please try again later.
+
+ Your email has not been verified. Check your email for a verification link. Click here resend the verification email. Please wait to send another verification email ( ).
src/app/login/login-home/login-home.component.html
- 72,74
+ 69,76
-
- Your email has been verified.
+
+ Your account could not be verified. Make sure you click the link sent to your email.
src/app/login/login-home/login-home.component.html
- 75,80
+ 78,83
Sign in with Google
src/app/login/login-home/login-home.component.html
- 104,108
+ 108,112
src/app/register/register-google-user-already-exists/register-google-user-already-exists.component.html
@@ -5732,7 +5739,7 @@
Sign in with Microsoft
src/app/login/login-home/login-home.component.html
- 117,121
+ 121,125
src/app/register/register-microsoft-user-already-exists/register-microsoft-user-already-exists.component.html
@@ -5751,14 +5758,14 @@
Forgot username or password?
src/app/login/login-home/login-home.component.html
- 126,127
+ 130,131
New to WISE? Join for free!
src/app/login/login-home/login-home.component.html
- 127,128
+ 131,132
From 7cb7b978dfba738025fe74ad7014d760c52cdbe8 Mon Sep 17 00:00:00 2001
From: Jonathan Lim-Breitbart
Date: Mon, 3 Aug 2026 09:31:49 -0700
Subject: [PATCH 12/14] Split verification messages into separate i18n
messages, cleaned up template
---
.../login-home/login-home.component.html | 77 ++++++++++---------
.../login-home/login-home.component.spec.ts | 14 +++-
2 files changed, 51 insertions(+), 40 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.html b/src/app/login/login-home/login-home.component.html
index 19293e2f818..e73cfa514eb 100644
--- a/src/app/login/login-home/login-home.component.html
+++ b/src/app/login/login-home/login-home.component.html
@@ -13,32 +13,28 @@ Sign in to WISE
work. We apologize for the inconvenience.
}
-
-
- Username
-
-
-
-
-
- Password
-
-
-
+
+ Username
+
+
+
+ Password
+
+
@if (isRecaptchaEnabled) {
This site is protected by reCAPTCHA and the Google
@@ -57,24 +53,31 @@
Sign in to WISE
}
}
@if (verificationState() === 'confirmVerified') {
- Your email has been verified.
+ Your email has been verified.
} @else if (verificationState() === 'emailError') {
-
+
There was an error sending the verification email. Please try again later.
} @else if (verificationState() === 'emailSent') {
- A verification email has been sent.
+ A verification email has been sent.
} @else if (verificationState() === 'unverified') {
-
- Your email has not been verified. Check your email for a verification link.
- @if (allowResendEmail()) {
- Click here resend the verification email.
- } @else {
- Please wait to send another verification email ({{ resendEmailWaitSeconds() }}).
- }
+
+ Your email has not been verified. Check your email for a verification link.
+ @if (allowResendEmail()) {
+
+ Click here to resend the verification
+ email.
+
+ } @else {
+
+ Please wait to send another verification email ({{ resendEmailWaitSeconds() }}).
+
+ }
} @else if (verificationState() === 'verificationError') {
-
+
Your account could not be verified. Make sure you click the link sent to your email.
}
diff --git a/src/app/login/login-home/login-home.component.spec.ts b/src/app/login/login-home/login-home.component.spec.ts
index 0807b468171..87385484ee1 100644
--- a/src/app/login/login-home/login-home.component.spec.ts
+++ b/src/app/login/login-home/login-home.component.spec.ts
@@ -21,7 +21,7 @@ const redirectUrl: string = `${contextPath}/api/j_acegi_security_check`;
let router: Router;
let userService: UserService;
-describe('LoginHomeComponent!', () => {
+fdescribe('LoginHomeComponent!', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [LoginHomeComponent],
@@ -122,10 +122,13 @@ function unverifiedAccount() {
component.login();
tickAndDetectChanges();
const errorMessageElement = getErrorMessageElement(
- 'Your email has not been verified. Check your email for a verification link. Click here resend the verification email.'
+ 'Your email has not been verified. Check your email for a verification link.'
);
+ const resendLinkElement = getErrorMessageElement('Click here resend the verification email.');
expect(errorMessageElement).toBeDefined();
expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
+ expect(resendLinkElement).toBeDefined();
+ expect(resendLinkElement!.nativeElement.classList.contains('warn')).toBeTruthy();
}));
});
}
@@ -138,10 +141,15 @@ function unverifiedAccountWaitToResendEmail() {
component.login();
tickAndDetectChanges();
const errorMessageElement = getErrorMessageElement(
- 'Your email has not been verified. Check your email for a verification link. Please wait to send another verification email (60).'
+ 'Your email has not been verified. Check your email for a verification link.'
+ );
+ const resendLinkElement = getErrorMessageElement(
+ 'Please wait to send another verification email (60).'
);
expect(errorMessageElement).toBeDefined();
expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
+ expect(resendLinkElement).toBeDefined();
+ expect(resendLinkElement!.nativeElement.classList.contains('warn')).toBeTruthy();
}));
});
}
From fa1b20ad369454e25bde60f424521c230e2a78c4 Mon Sep 17 00:00:00 2001
From: Jonathan Lim-Breitbart
Date: Mon, 3 Aug 2026 09:40:29 -0700
Subject: [PATCH 13/14] Fix test
---
src/app/login/login-home/login-home.component.spec.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/app/login/login-home/login-home.component.spec.ts b/src/app/login/login-home/login-home.component.spec.ts
index 87385484ee1..4b718dfff4b 100644
--- a/src/app/login/login-home/login-home.component.spec.ts
+++ b/src/app/login/login-home/login-home.component.spec.ts
@@ -21,7 +21,7 @@ const redirectUrl: string = `${contextPath}/api/j_acegi_security_check`;
let router: Router;
let userService: UserService;
-fdescribe('LoginHomeComponent!', () => {
+describe('LoginHomeComponent', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [LoginHomeComponent],
@@ -124,7 +124,9 @@ function unverifiedAccount() {
const errorMessageElement = getErrorMessageElement(
'Your email has not been verified. Check your email for a verification link.'
);
- const resendLinkElement = getErrorMessageElement('Click here resend the verification email.');
+ const resendLinkElement = getErrorMessageElement(
+ 'Click here to resend the verification email.'
+ );
expect(errorMessageElement).toBeDefined();
expect(errorMessageElement!.nativeElement.classList.contains('warn')).toBeTruthy();
expect(resendLinkElement).toBeDefined();
From ba859e6e3fb0e18bd3ce6b0e9873a8e618333f4d Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
Date: Mon, 3 Aug 2026 16:44:58 +0000
Subject: [PATCH 14/14] Updated messages
---
src/messages.xlf | 48 +++++++++++++++++++++++++++++++-----------------
1 file changed, 31 insertions(+), 17 deletions(-)
diff --git a/src/messages.xlf b/src/messages.xlf
index bb587076051..7f586ec6ab4 100644
--- a/src/messages.xlf
+++ b/src/messages.xlf
@@ -2455,7 +2455,7 @@
src/app/login/login-home/login-home.component.html
- 44,48
+ 40,44
src/app/register/register-student-form/register-student-form.component.html
@@ -3271,7 +3271,7 @@
src/app/login/login-home/login-home.component.html
- 92,96
+ 95,99
src/app/modules/mobile-menu/mobile-menu.component.html
@@ -3402,7 +3402,7 @@
src/app/login/login-home/login-home.component.html
- 18,21
+ 17,21
src/app/student/account/edit-profile/edit-profile.component.html
@@ -3801,7 +3801,7 @@
src/app/login/login-home/login-home.component.html
- 31,34
+ 28,32
src/app/register/register-user-form/register-user-form.component.ts
@@ -5663,14 +5663,14 @@
There was an error saving data. Please log in again. You may need to re-do your recent work. We apologize for the inconvenience.
src/app/login/login-home/login-home.component.html
- 12,17
+ 12,16
Recaptcha failed. Please reload the page and try again!
src/app/login/login-home/login-home.component.html
- 55,59
+ 51,55
src/app/register/register-student-form/register-student-form.component.html
@@ -5685,42 +5685,56 @@
Your email has been verified.
src/app/login/login-home/login-home.component.html
- 60,62
+ 56,58
There was an error sending the verification email. Please try again later.
src/app/login/login-home/login-home.component.html
- 63,65
+ 59,61
A verification email has been sent.
src/app/login/login-home/login-home.component.html
- 66,68
+ 62,64
+
+
+
+ Your email has not been verified. Check your email for a verification link.
+
+ src/app/login/login-home/login-home.component.html
+ 66,70
+
+
+
+ Click here to resend the verification email.
+
+ src/app/login/login-home/login-home.component.html
+ 71,73
-
- Your email has not been verified. Check your email for a verification link. Click here resend the verification email. Please wait to send another verification email ( ).
+
+ Please wait to send another verification email ( ).
src/app/login/login-home/login-home.component.html
- 69,76
+ 76,78
Your account could not be verified. Make sure you click the link sent to your email.
src/app/login/login-home/login-home.component.html
- 78,83
+ 81,86
Sign in with Google
src/app/login/login-home/login-home.component.html
- 108,112
+ 111,115
src/app/register/register-google-user-already-exists/register-google-user-already-exists.component.html
@@ -5739,7 +5753,7 @@
Sign in with Microsoft
src/app/login/login-home/login-home.component.html
- 121,125
+ 124,128
src/app/register/register-microsoft-user-already-exists/register-microsoft-user-already-exists.component.html
@@ -5758,14 +5772,14 @@
Forgot username or password?
src/app/login/login-home/login-home.component.html
- 130,131
+ 133,134
New to WISE? Join for free!
src/app/login/login-home/login-home.component.html
- 131,132
+ 134,135