From 8dad77b1ff26e571ddb7493ebe4f667d3fd48e1f Mon Sep 17 00:00:00 2001
From: YongJunXi
Date: Mon, 13 Jul 2026 15:24:17 +0800
Subject: [PATCH 1/3] Add support email to config data
---
src/main/java/teammates/ui/output/ConfigData.java | 6 ++++++
src/web/types/api-output.ts | 1 +
2 files changed, 7 insertions(+)
diff --git a/src/main/java/teammates/ui/output/ConfigData.java b/src/main/java/teammates/ui/output/ConfigData.java
index f568fe50f51..a4f75906b84 100644
--- a/src/main/java/teammates/ui/output/ConfigData.java
+++ b/src/main/java/teammates/ui/output/ConfigData.java
@@ -10,16 +10,22 @@
public class ConfigData implements ApiOutput {
private final Set loginMethods;
private final String frontendUrl;
+ private final String supportEmail;
public ConfigData() {
this.loginMethods = Config.getSupportedLoginMethods();
this.frontendUrl = Config.APP_FRONTEND_URL;
+ this.supportEmail = Config.SUPPORT_EMAIL;
}
public Set getLoginMethods() {
return loginMethods;
}
+ public String getSupportEmail() {
+ return supportEmail;
+ }
+
public String getFrontendUrl() {
return frontendUrl;
}
diff --git a/src/web/types/api-output.ts b/src/web/types/api-output.ts
index 89bfd5d74ff..4ef3a5da524 100644
--- a/src/web/types/api-output.ts
+++ b/src/web/types/api-output.ts
@@ -38,6 +38,7 @@ export interface AuthInfo extends ApiOutput {
export interface Config extends ApiOutput {
loginMethods: LoginMethod[];
frontendUrl: string;
+ supportEmail: string;
}
export interface ConstsumOptionRow {
From f5480f8a8482cfb575095e0d5de243e89f9d8b30 Mon Sep 17 00:00:00 2001
From: YongJunXi
Date: Mon, 13 Jul 2026 15:36:15 +0800
Subject: [PATCH 2/3] Call config service
---
.../error-report.component.spec.ts.snap | 3 ++-
.../error-report/error-report.component.html | 2 +-
.../error-report/error-report.component.ts | 9 +++++++--
.../reject-request-modal.component.html | 2 +-
.../reject-request-modal.component.ts | 9 +++++++--
.../instructor-help-courses-section.component.html | 2 +-
.../instructor-help-courses-section.component.ts | 12 +++++++++---
.../instructor-help-getting-started.component.html | 2 +-
.../instructor-help-getting-started.component.ts | 9 +++++++--
.../instructor-help-page.component.html | 4 ++--
.../instructor-help-page.component.ts | 9 +++++++--
.../instructor-help-sessions-section.component.html | 7 ++++---
.../instructor-help-sessions-section.component.ts | 12 +++++++++---
.../instructor-help-students-section.component.html | 2 +-
.../instructor-help-students-section.component.ts | 12 +++++++++---
.../student-help-page.component.html | 6 +++---
.../student-help-page/student-help-page.component.ts | 12 +++++++++---
.../contact-page/contact-page.component.html | 2 +-
.../contact-page/contact-page.component.ts | 12 +++++++++---
src/web/services/config.service.spec.ts | 3 ++-
20 files changed, 92 insertions(+), 39 deletions(-)
diff --git a/src/web/app/components/error-report/__snapshots__/error-report.component.spec.ts.snap b/src/web/app/components/error-report/__snapshots__/error-report.component.spec.ts.snap
index 7d608889a47..29016168fd8 100644
--- a/src/web/app/components/error-report/__snapshots__/error-report.component.spec.ts.snap
+++ b/src/web/app/components/error-report/__snapshots__/error-report.component.spec.ts.snap
@@ -2,6 +2,7 @@
exports[`ErrorReportComponent > should snap with default view 1`] = `
should snap with default view 1`] = `
sendButtonEnabled={[Function Boolean]}
statusMessageService={[Function _StatusMessageService]}
subject={[Function String]}
- supportEmail={[Function String]}
+ supportEmail={[Function Function]}
>
Uh oh! Something went wrong.
For further support, please contact our email address at
- {{ supportEmail }}{{ supportEmail() }}.
diff --git a/src/web/app/components/error-report/error-report.component.ts b/src/web/app/components/error-report/error-report.component.ts
index 26fc3fbea09..084651acf4e 100644
--- a/src/web/app/components/error-report/error-report.component.ts
+++ b/src/web/app/components/error-report/error-report.component.ts
@@ -1,7 +1,9 @@
import { Component, OnInit, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap/modal';
-import { environment } from '../../../environments/environment';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../services/config.service';
import { ErrorReportService } from '../../../services/error-report.service';
import { StatusMessageService } from '../../../services/status-message.service';
import { ErrorReportRequest } from '../../../types/api-request';
@@ -20,6 +22,7 @@ export class ErrorReportComponent implements OnInit {
private errorReportService = inject(ErrorReportService);
private ngbActiveModal = inject(NgbActiveModal);
private statusMessageService = inject(StatusMessageService);
+ private configService = inject(ConfigService);
errorMessage = '';
subject = 'User-submitted Error Report';
@@ -29,7 +32,9 @@ export class ErrorReportComponent implements OnInit {
errorReportEnabled = true;
errorReportSubmitted = false;
csrfErrorMessages: string[] = ['Missing CSRF token.', 'Invalid CSRF token.'];
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
ngOnInit(): void {
if (this.csrfErrorMessages.includes(this.errorMessage)) {
diff --git a/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.html b/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.html
index 2349559600a..3c1b2b1a841 100644
--- a/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.html
+++ b/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.html
@@ -61,7 +61,7 @@ Reject Verification Request
}
If you believe this decision was made in error, or if you have additional information that may support your
- request, please contact us at {{ supportEmail }}.
+ request, please contact us at {{ supportEmail() }}.
Thank you for your understanding.
- The TEAMMATES Team
diff --git a/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.ts b/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.ts
index baadf40a6ea..a91141af569 100644
--- a/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.ts
+++ b/src/web/app/pages-admin/admin-account-verification-request-page/reject-request-modal/reject-request-modal.component.ts
@@ -1,7 +1,9 @@
import { ChangeDetectionStrategy, Component, Input, computed, inject, signal } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap/modal';
-import { environment } from '../../../../environments/environment';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../../services/config.service';
import { AccountVerificationRequestRejectionType } from '../../../../types/api-request';
@Component({
@@ -12,6 +14,7 @@ import { AccountVerificationRequestRejectionType } from '../../../../types/api-r
})
export class RejectRequestModalComponent {
readonly activeModal = inject(NgbActiveModal);
+ private readonly configService = inject(ConfigService);
@Input() instituteName = '';
@@ -52,7 +55,9 @@ export class RejectRequestModalComponent {
return { reason, comments };
});
- readonly supportEmail = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
confirm(): void {
const rejectionType = this.selectedRejectionType();
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.html b/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.html
index 1fb37757503..1d05c130162 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.html
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.html
@@ -317,7 +317,7 @@ Managing Courses
The most likely reason for this is that the student has signed in with a different account. Please ask the student
to email
- {{ supportEmail }} so that we help to rectify the problem.
+ {{ supportEmail() }} so that we help to rectify the problem.
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.ts b/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.ts
index 1a8e9a96b0a..d43fcb9b0e7 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.ts
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-courses-section/instructor-help-courses-section.component.ts
@@ -1,7 +1,9 @@
-import { Component, EventEmitter, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, OnInit, Output, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { CoursesSectionQuestions } from './courses-section-questions';
-import { environment } from '../../../../environments/environment';
import { RouterLink } from '@angular/router';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../../services/config.service';
import { InstructorHelpPanelComponent } from '../instructor-help-panel/instructor-help-panel.component';
import { InstructorHelpSectionComponent } from '../instructor-help-section.component';
import { Sections } from '../sections';
@@ -16,11 +18,15 @@ import { Sections } from '../sections';
imports: [InstructorHelpPanelComponent, RouterLink],
})
export class InstructorHelpCoursesSectionComponent extends InstructorHelpSectionComponent implements OnInit {
+ private readonly configService = inject(ConfigService);
+
// enums
CoursesSectionQuestions!: typeof CoursesSectionQuestions;
Sections!: typeof Sections;
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
readonly questionsOrder: string[] = [
CoursesSectionQuestions.COURSE_ADD_STUDENTS,
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.html b/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.html
index 30a1e5d902d..a962452a525 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.html
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.html
@@ -355,7 +355,7 @@
If you have doubts, comments, or questions about using TEAMMATES, just
- email us. We usually respond within 24 hours.
+ email us. We usually respond within 24 hours.
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.ts b/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.ts
index 713bf0c3809..8f4b10d123c 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.ts
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-getting-started/instructor-help-getting-started.component.ts
@@ -1,8 +1,10 @@
import { Component, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';
-import { environment } from '../../../../environments/environment';
+import { map } from 'rxjs/operators';
import { CourseEditFormMode } from '../../../components/course-edit-form/course-edit-form-model';
import { CourseEditFormComponent } from '../../../components/course-edit-form/course-edit-form.component';
+import { ConfigService } from '../../../../services/config.service';
import { PageScrollService } from '../../../../services/page-scroll.service';
import { RouterLink } from '@angular/router';
import { ExampleBoxComponent } from '../example-box/example-box.component';
@@ -24,6 +26,7 @@ import { Sections } from '../sections';
export class InstructorHelpGettingStartedComponent {
private readonly route = inject(ActivatedRoute);
private readonly pageScrollService = inject(PageScrollService);
+ private readonly configService = inject(ConfigService);
// enum
StudentsSectionQuestions!: typeof StudentsSectionQuestions;
@@ -33,7 +36,9 @@ export class InstructorHelpGettingStartedComponent {
CourseEditFormMode!: typeof CourseEditFormMode;
Sections!: typeof Sections;
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
instructorHelpPath = '';
constructor() {
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.html b/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.html
index de7bc7f9fd0..7dd78013824 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.html
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.html
@@ -9,8 +9,8 @@ Help for Instructors
If you are new to TEAMMATES, our Getting Started guide
will introduce you to the basic functions of TEAMMATES.
- If you have any remaining questions, don't hesitate to email us. We
- usually respond within 24 hours.
+ If you have any remaining questions, don't hesitate to email us.
+ We usually respond within 24 hours.
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.ts b/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.ts
index 7c66b0b7e87..5713d9444d8 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.ts
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-page.component.ts
@@ -1,4 +1,5 @@
import { AfterViewInit, Component, ViewChild, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { ActivatedRoute, Data, Params } from '@angular/router';
import { InstructorHelpCoursesSectionComponent } from './instructor-help-courses-section/instructor-help-courses-section.component';
@@ -9,7 +10,8 @@ import { SessionsSectionQuestions } from './instructor-help-sessions-section/ses
import { InstructorHelpStudentsSectionComponent } from './instructor-help-students-section/instructor-help-students-section.component';
import { StudentsSectionQuestions } from './instructor-help-students-section/students-section-questions';
import { Sections } from './sections';
-import { environment } from '../../../environments/environment';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../services/config.service';
import { PageScrollService } from '../../../services/page-scroll.service';
import { RouterLink } from '@angular/router';
@@ -33,10 +35,13 @@ import { RouterLink } from '@angular/router';
export class InstructorHelpPageComponent implements AfterViewInit {
private readonly route = inject(ActivatedRoute);
private readonly pageScrollService = inject(PageScrollService);
+ private readonly configService = inject(ConfigService);
// enum
Sections!: typeof Sections;
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
instructorGettingStartedPath = '';
searchTerm = '';
key = '';
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.html b/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.html
index 7fe4b7db1b4..ece6e28eab9 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.html
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.html
@@ -302,7 +302,7 @@
Setting Up Sessions
spam box.
- Failing all above, ask students to email us at {{ supportEmail }}{{ supportEmail() }}. We can resend the email using an alternate means. When they email us, they should use the email address
currently registered in TEAMMATES (for identification).
@@ -460,7 +460,8 @@
Managing Session Responses
[(isPanelExpanded)]="questionsToCollapsed[SessionsSectionQuestions.STUDENT_ACCESS_SUBMISSION_PAGE]"
>
- Not at the moment. If there is such a need, email us at {{ supportEmail }}{{ supportEmail() }}, and we'll try to find that information for you.
@@ -624,7 +625,7 @@
Managing Session Responses
specific students. Make sure the session results are published if you are unable to see the option.
- Failing all above, ask students to email us at {{ supportEmail }}{{ supportEmail() }}. We can resend the email using an alternate means. When they email us, they should use the email address
currently registered in TEAMMATES (for identification).
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.ts b/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.ts
index 52277c01a94..42fbbb152ac 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.ts
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-sessions-section/instructor-help-sessions-section.component.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap/collapse';
import {
EXAMPLE_COMMENT_EDIT_FORM_MODEL,
@@ -16,7 +17,8 @@ import {
EXAMPLE_TEMPLATE_SESSIONS,
} from './instructor-help-sessions-data';
import { SessionsSectionQuestions } from './sessions-section-questions';
-import { environment } from '../../../../environments/environment';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../../services/config.service';
import { Course, FeedbackSession, Instructor, ResponseOutput, Student } from '../../../../types/api-output';
import { AddingQuestionPanelComponent } from '../../../components/adding-question-panel/adding-question-panel.component';
import type { CommentEditFormModel } from '../../../components/comment-box/comment.model';
@@ -78,6 +80,8 @@ import { TemplateSession } from '../../../../data/template-sessions';
],
})
export class InstructorHelpSessionsSectionComponent extends InstructorHelpSectionComponent implements OnInit {
+ private readonly configService = inject(ConfigService);
+
// enums
CommentRowMode!: typeof CommentRowMode;
SessionEditFormMode!: typeof SessionEditFormMode;
@@ -86,7 +90,9 @@ export class InstructorHelpSessionsSectionComponent extends InstructorHelpSectio
SessionsSectionQuestions!: typeof SessionsSectionQuestions;
Sections!: typeof Sections;
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
readonly exampleCommentEditFormModel: CommentEditFormModel = EXAMPLE_COMMENT_EDIT_FORM_MODEL;
readonly exampleSessionEditFormModel: SessionEditFormModel = EXAMPLE_SESSION_EDIT_FORM_MODEL;
readonly exampleResponse: ResponseOutput = EXAMPLE_RESPONSE;
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.html b/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.html
index 67d2f407619..894b6e6fd13 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.html
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.html
@@ -213,7 +213,7 @@
Student Accounts
At the moment, there is no way for students to update their own (or instructors to update their students') account
emails.
- Please ask the student to
contact us for assistance changing his/her
+ Please ask the student to
contact us for assistance changing his/her
account email.
diff --git a/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.ts b/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.ts
index 35794961baf..a2ee9b11bd2 100644
--- a/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.ts
+++ b/src/web/app/pages-help/instructor-help-page/instructor-help-students-section/instructor-help-students-section.component.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap/collapse';
import {
EXAMPLE_MULTIPLE_STUDENT_RESULT_TABLES,
@@ -6,7 +7,8 @@ import {
EXAMPLE_STUDENT_ATTRIBUTES,
} from './instructor-help-students-data';
import { StudentsSectionQuestions } from './students-section-questions';
-import { environment } from '../../../../environments/environment';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../../services/config.service';
import { Student } from '../../../../types/api-output';
import { CourseRelatedInfoComponent } from '../../../components/course-related-info/course-related-info.component';
import { InstructorCourseStudentEditPageComponent } from '../../../pages-instructor/instructor-course-student-edit-page/instructor-course-student-edit-page.component';
@@ -38,11 +40,15 @@ import { Sections } from '../sections';
],
})
export class InstructorHelpStudentsSectionComponent extends InstructorHelpSectionComponent implements OnInit {
+ private readonly configService = inject(ConfigService);
+
// enums
StudentsSectionQuestions!: typeof StudentsSectionQuestions;
Sections!: typeof Sections;
- readonly supportEmail: string = environment.supportEmail;
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
readonly exampleStudentAttributes: Student = EXAMPLE_STUDENT_ATTRIBUTES;
readonly exampleSingleStudentResultTables: SearchStudentsListRowTable[] = EXAMPLE_SINGLE_STUDENT_RESULT_TABLES;
readonly exampleMultipleStudentResultTables: SearchStudentsListRowTable[] = EXAMPLE_MULTIPLE_STUDENT_RESULT_TABLES;
diff --git a/src/web/app/pages-help/student-help-page/student-help-page.component.html b/src/web/app/pages-help/student-help-page/student-help-page.component.html
index 0dbcc91f405..23404308c9f 100644
--- a/src/web/app/pages-help/student-help-page/student-help-page.component.html
+++ b/src/web/app/pages-help/student-help-page/student-help-page.component.html
@@ -37,13 +37,13 @@
Frequently Asked Questions
instead.
- Please email
{{ supportEmail }} for assistance.
+ Please email
{{ supportEmail() }} for assistance.
What should I do if I'm unable to submit my response?
-
Email us so that we can assist you with your submission. Note that we
+
Email us so that we can assist you with your submission. Note that we
cannot do much if the submission deadline is over. It is not up to us (the TEAMMATES team) to accept overdue
submissions.
@@ -61,7 +61,7 @@ Frequently Asked Questions
you're unsure.
- If none of the options above works, email us and we will resend the
+ If none of the options above works, email us and we will resend the
email using an alternate means. For identification purpose, you should use the email address that was used to
enroll you in the course.
diff --git a/src/web/app/pages-help/student-help-page/student-help-page.component.ts b/src/web/app/pages-help/student-help-page/student-help-page.component.ts
index 9856d7dbb63..b6bf51dae27 100644
--- a/src/web/app/pages-help/student-help-page/student-help-page.component.ts
+++ b/src/web/app/pages-help/student-help-page/student-help-page.component.ts
@@ -1,6 +1,8 @@
-import { Component } from '@angular/core';
-import { environment } from '../../../environments/environment';
+import { Component, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
import { RouterLink } from '@angular/router';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../services/config.service';
/**
* Student help page.
@@ -12,5 +14,9 @@ import { RouterLink } from '@angular/router';
imports: [RouterLink],
})
export class StudentHelpPageComponent {
- readonly supportEmail: string = environment.supportEmail;
+ private readonly configService = inject(ConfigService);
+
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
}
diff --git a/src/web/app/pages-static/contact-page/contact-page.component.html b/src/web/app/pages-static/contact-page/contact-page.component.html
index 86ce5b01d56..5d3d78c19b9 100644
--- a/src/web/app/pages-static/contact-page/contact-page.component.html
+++ b/src/web/app/pages-static/contact-page/contact-page.component.html
@@ -2,7 +2,7 @@
Contact Us
Email: You can contact us at the following email address:
- {{ supportEmail }}{{ supportEmail() }}.
diff --git a/src/web/app/pages-static/contact-page/contact-page.component.ts b/src/web/app/pages-static/contact-page/contact-page.component.ts
index 8036efa1623..6c14c95feb6 100644
--- a/src/web/app/pages-static/contact-page/contact-page.component.ts
+++ b/src/web/app/pages-static/contact-page/contact-page.component.ts
@@ -1,5 +1,7 @@
-import { Component } from '@angular/core';
-import { environment } from '../../../environments/environment';
+import { Component, inject } from '@angular/core';
+import { toSignal } from '@angular/core/rxjs-interop';
+import { map } from 'rxjs/operators';
+import { ConfigService } from '../../../services/config.service';
/**
* Contact page.
@@ -10,5 +12,9 @@ import { environment } from '../../../environments/environment';
styleUrls: ['./contact-page.component.scss'],
})
export class ContactPageComponent {
- readonly supportEmail: string = environment.supportEmail;
+ private readonly configService = inject(ConfigService);
+
+ readonly supportEmail = toSignal(this.configService.getConfig().pipe(map((config) => config.supportEmail)), {
+ initialValue: '',
+ });
}
diff --git a/src/web/services/config.service.spec.ts b/src/web/services/config.service.spec.ts
index 251971c9ef8..648f9a1243b 100644
--- a/src/web/services/config.service.spec.ts
+++ b/src/web/services/config.service.spec.ts
@@ -1,4 +1,5 @@
import { TestBed } from '@angular/core/testing';
+import { of } from 'rxjs';
import { ConfigService } from './config.service';
import { createMockHttpRequestService, MockHttpRequestService } from '../test-helpers/mock-http-request';
import { HttpRequestService } from './http-request.service';
@@ -21,7 +22,7 @@ describe('ConfigService', () => {
});
it('should execute GET on config endpoint', () => {
- spyHttpRequestService.get.mockReturnValue({});
+ spyHttpRequestService.get.mockReturnValue(of({}));
service.getConfig();
expect(spyHttpRequestService.get).toHaveBeenCalledWith(ResourceEndpoints.CONFIG);
});
From 987ddb2aaf958cd49ffcf0db455573cf4f730990 Mon Sep 17 00:00:00 2001
From: YongJunXi
Date: Mon, 13 Jul 2026 15:38:10 +0800
Subject: [PATCH 3/3] Remove supportEmail from environment model
---
src/web/environments/config.template.ts | 5 -----
src/web/environments/environment.model.ts | 1 -
2 files changed, 6 deletions(-)
diff --git a/src/web/environments/config.template.ts b/src/web/environments/config.template.ts
index e2e59a9792b..95b8b84033a 100644
--- a/src/web/environments/config.template.ts
+++ b/src/web/environments/config.template.ts
@@ -4,11 +4,6 @@ import { AppConfig } from './environment.model';
* Contains some configuration values required to build and run the web application.
*/
export const config: AppConfig = {
- /**
- * The support email shown to the user in various pages of the web application.
- */
- supportEmail: 'teammates@comp.nus.edu.sg',
-
/**
* The public site key for the reCAPTCHA on the recover session links page.
* You can get a pair of keys from the Google reCAPTCHA website.
diff --git a/src/web/environments/environment.model.ts b/src/web/environments/environment.model.ts
index 6f42f71a403..c18c9a00159 100644
--- a/src/web/environments/environment.model.ts
+++ b/src/web/environments/environment.model.ts
@@ -1,5 +1,4 @@
export interface AppConfig {
- supportEmail: string;
captchaSiteKey: string;
maintenance: boolean;
}