Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#11878] Upgrade instructor request form UI #12928

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type InstructorRequestFormData = {
name: string;

Check failure on line 2 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 2 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
institution: string;

Check failure on line 3 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 3 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
country: string;

Check failure on line 4 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 4 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
email: string;

Check failure on line 5 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 5 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
homePage: string;

Check failure on line 6 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 6 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
comments: string;

Check failure on line 7 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Expected a comma

Check failure on line 7 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Expected a comma
}

Check failure on line 8 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Newline required at end of file but not found

Check failure on line 8 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Missing semicolon

Check failure on line 8 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Newline required at end of file but not found

Check failure on line 8 in src/web/app/pages-static/request-page/instructor-request-form/InstructorRequestFormData.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Missing semicolon
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<p aria-hidden="true">
<!-- aria-hidden as screen readers use the required attribute -->
Questions marked with an asterisk <span class="red-font">*</span> are required.
</p>
<form (ngSubmit)="onSubmit()" [formGroup]="arf">
<div class="form-group {{isFieldRequired(name) ? 'required' : ''}}">
<label for="name" id="name-label" class="qn">
Full Name
</label>
<p class="help-block">
This is the name that will be shown to your students. You may include salutation (Dr. Prof. etc.)
</p>
<input class="form-control {{getFieldValidationClasses(name)}}"
type="text"
id="name"
autocomplete="name"
[formControl]="name"
[required]="isFieldRequired(name)"
[attr.aria-invalid]="isFieldInvalid(name)"
>
<div
*ngIf="isFieldInvalid(name)"
role="alert"
aria-describedby="name-label"
tabindex="0"
class="invalid-feedback"
>
Please enter your name.
</div>
</div>
<br>
<div class="form-group {{isFieldRequired(institution) ? 'required' : ''}}">
<label for="institution" id="institution-label" class="qn">
University/school/institution
</label>
<p class="help-block">
Please give full name of the university/institution.
</p>
<input class="form-control {{getFieldValidationClasses(institution)}}"
type="text"
id="institution"
autocomplete="organization"
[formControl]="institution"
[required]="isFieldRequired(institution)"
[attr.aria-invalid]="isFieldInvalid(institution)"
>
<div
*ngIf="isFieldInvalid(institution)"
role="alert"
aria-describedby="institution-label"
tabindex="0"
class="invalid-feedback"
>
Please enter your institution.
</div>
</div>
<br>
<div class="form-group {{isFieldRequired(country) ? 'required' : ''}}">
<label for="country" id="country-label" class="qn">
Country
</label>
<p class="help-block">
Which country is your university/institution based in?
</p>
<input class="form-control {{getFieldValidationClasses(country)}}"
type="text"
id="country"
autocomplete="country-name"
[formControl]="country"
[required]="isFieldRequired(country)"
[attr.aria-invalid]="isFieldInvalid(country)"
>
<div
*ngIf="isFieldInvalid(country)"
role="alert"
aria-describedby="country-label"
tabindex="0"
class="invalid-feedback"
>
Please enter your institution's country.
</div>
</div>
<br>
<div class="form-group {{isFieldRequired(email) ? 'required' : ''}}">
<label for="email" id="email-label" class="qn">
Official email address
</label>
<p class="help-block">
Please use the email address <b>given to you by your school/university</b>
(not your personal Gmail/Hotmail address).
Note that this email address will be visible to the students you enroll in TEAMMATES.
</p>
<input class="form-control {{getFieldValidationClasses(email)}}"
type="email"
id="email"
autocomplete="email"
[formControl]="email"
[required]="isFieldRequired(email)"
[attr.aria-invalid]="isFieldInvalid(email)"
>
<div
*ngIf="isFieldInvalid(email)"
role="alert"
aria-describedby="email-label"
tabindex="0"
class="invalid-feedback"
>
Please enter a valid email address.
</div>
</div>
<br>
<div class="form-group {{isFieldRequired(homePage) ? 'required' : ''}}">
<label for="homePage" id="homePage-label" class="qn">
URL of your home page (if any)
</label>
<input class="form-control {{getFieldValidationClasses(homePage)}}"
type="url"
id="homePage"
autocomplete="url"
[formControl]="homePage"
[required]="isFieldRequired(homePage)"
[attr.aria-invalid]="isFieldInvalid(homePage)"
>
<div
*ngIf="isFieldInvalid(homePage)"
role="alert"
aria-describedby="homePage-label"
tabindex="0"
class="invalid-feedback"
>
Please enter a valid URL.
</div>
</div>
<br>
<div class="form-group {{isFieldRequired(comments) ? 'required' : ''}}">
<label for="comments" id="comments-label" class="qn">
Any other comments/queries
</label>
<textarea class="form-control {{getFieldValidationClasses(comments)}}"
[formControl]="comments"
[attr.aria-invalid]="isFieldInvalid(comments)"
></textarea>
</div>
<br>
<button type="submit" class="btn btn-primary">
Submit
</button>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
label.qn {
font-weight: bold;
font-size: 1rem;
margin-bottom: 0.3rem;
}

.form-group {
margin-bottom: 0.5rem;
}

.form-group.required > label:after {
content:"*";
color: red;
}

.help-block {
margin-bottom: 0.8rem;
}

.red-font {
color: red;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { InstructorRequestFormComponent } from './instructor-request-form.component';

describe('InstructorRequestFormComponent', () => {
let component: InstructorRequestFormComponent;
let fixture: ComponentFixture<InstructorRequestFormComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [InstructorRequestFormComponent]

Check failure on line 11 in src/web/app/pages-static/request-page/instructor-request-form/instructor-request-form.component.spec.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Missing trailing comma

Check failure on line 11 in src/web/app/pages-static/request-page/instructor-request-form/instructor-request-form.component.spec.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Missing trailing comma
});
fixture = TestBed.createComponent(InstructorRequestFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { InstructorRequestFormData } from './InstructorRequestFormData';

const URL_REGEX = '(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)';

Check failure on line 5 in src/web/app/pages-static/request-page/instructor-request-form/instructor-request-form.component.ts

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

Unnecessary escape character: \/

Check failure on line 5 in src/web/app/pages-static/request-page/instructor-request-form/instructor-request-form.component.ts

View workflow job for this annotation

GitHub Actions / lint (windows-latest)

Unnecessary escape character: \/

@Component({
selector: 'tm-instructor-request-form',
templateUrl: './instructor-request-form.component.html',
styleUrls: ['./instructor-request-form.component.scss'],
})
export class InstructorRequestFormComponent {

arf = new FormGroup({
name: new FormControl('', [Validators.required]),
institution: new FormControl('', [Validators.required]),
country: new FormControl('', [Validators.required]),
email: new FormControl('', [Validators.required, Validators.email]),
homePage: new FormControl('', [Validators.pattern(URL_REGEX)]),
comments: new FormControl('')
}, {updateOn: 'submit'});

// Create members for easier access of arf controls
name = this.arf.controls.name;
institution = this.arf.controls.institution;
country = this.arf.controls.country;
email = this.arf.controls.email;
homePage = this.arf.controls.homePage;
comments = this.arf.controls.comments;

hasSubmitAttempt = false;

@Output() requestSubmitted = new EventEmitter<InstructorRequestFormData>();

isFieldRequired(field: FormControl): boolean {
return field.hasValidator(Validators.required);
}

isFieldInvalid(field: FormControl): boolean {
return field.invalid;
}

getFieldValidationClasses(field: FormControl): string {
let str = "";
if (this.hasSubmitAttempt) {
if (field.invalid) {
str = "is-invalid";
} else if (field.value !== "") {
str = "is-valid";
}
}
return str;
}

onSubmit() {
this.hasSubmitAttempt = true;

if (this.arf.invalid) {
// Do not submit form
return;
}

let name = this.name.value!.trim();
let email = this.email.value!.trim();
let country = this.country.value!.trim();
let institution = this.institution.value!.trim();
let combinedInstitution = country + " " + institution;
let homePage = this.homePage.value!;
let comments = this.comments.value!.trim();

let submittedData = {
name: name,
email: email,
institution: combinedInstitution,
homePage: homePage,
comments: comments
}
// TODO: connect to API
console.log(submittedData);

// Pass form input to parent to display confirmation
this.requestSubmitted.emit({
name: name,
institution: institution,
country: country,
email: email,
homePage: homePage,
comments: comments
});
}
}
71 changes: 59 additions & 12 deletions src/web/app/pages-static/request-page/request-page.component.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,61 @@
<h1 class="color-orange">
Request for an Account
Request for an Instructor Account
</h1>
<div *ngIf="accountRequestFormUrl">
<p>
Cannot see the request form below? <a [href]="accountRequestFormUrl" target="_blank" rel="noopener noreferrer">Click here.</a>
</p>
<iframe [src]="accountRequestFormUrl" width="760px" height="880px" frameborder="0" marginheight="0" marginwidth="0">
Loading...
</iframe>
</div>
<div *ngIf="!accountRequestFormUrl">
The URL for the account request form is not set.
</div>
<div class="col-xs-12 col-md-10 col-lg-8 col-xl-7 col-xxl-6">
<div *ngIf="!submittedFormData">
<p>
Request for an instructor account using this form if you are an instructor and want to use TEAMMATES to manage peer evaluations and/or other feedback paths of your students.
</p>
<hr>
<div *ngIf="!isDeclarationDone">
<p>
Note: <b>Students should not use this form to request for TEAMMATES accounts</b>, as students do not need accounts to use TEAMMATES. Instead, TEAMMATES will email students (who have been added to TEAMMATES by a course instructor) an access link when there is a TEAMMATES session available for them to access.
</p>
<a type="button" class="btn btn-secondary" tmRouterLink="/web/front/home">Back to home page</a>
<button type="button" class="btn btn-primary ms-3" (click)="onDeclarationButtonClicked()">I am an instructor</button>
</div>
<div *ngIf="isDeclarationDone">
<tm-instructor-request-form *ngIf="!submittedFormData" (requestSubmitted)="onRequestSubmitted($event)"></tm-instructor-request-form>
</div>
<hr>
</div>
<div *ngIf="submittedFormData">
<p>
Your request has been submitted successfully:
</p>
<table class="table table-bordered my-3">
<tbody>
<tr>
<th scope="row" class="col-3">Full Name</th>
<td>{{submittedFormData.name}}</td>
</tr>
<tr>
<th scope="row">Institution</th>
<td>{{submittedFormData.institution}}</td>
</tr>
<tr>
<th scope="row">Country</th>
<td>{{submittedFormData.country}}</td>
</tr>
<tr>
<th scope="row">Email</th>
<td>{{submittedFormData.email}}</td>
</tr>
<tr>
<th scope="row">Home Page URL</th>
<td>{{submittedFormData.homePage}}</td>
</tr>
<tr>
<th scope="row">Comments</th>
<td>{{submittedFormData.comments}}</td>
</tr>
</tbody>
</table>
<p>
We have sent an acknowledgement email to your email address <b>{{submittedFormData.email}}</b>.
Please check your email inbox or spam folder.<br>
If you do not receive the acknowledgement email within 1 hour, please <a tmRouterLink="/web/front/contact">contact</a> us.
</p>
</div>

</div>
Loading
Loading