Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1300776
Merge pull request #309 from SELab-2/development
thomasdejaeghere Mar 13, 2025
1dfcc93
chore(deps): bump @babel/runtime and @angular-devkit/build-angular
dependabot[bot] Mar 13, 2025
fde684b
Merge pull request #311 from SELab-2/dependabot/npm_and_yarn/frontend…
thomasdejaeghere Mar 19, 2025
69fd169
chore: initialized component
brentjan Mar 21, 2025
9464be9
feat: basic landing page
brentjan Mar 21, 2025
e957c61
feat: basic landing page
brentjan Mar 21, 2025
c885d32
chore: added some basic tests for landing page
brentjan Mar 21, 2025
db8b974
chore: fixed tests and linter
brentjan Mar 21, 2025
433bcfc
feat: favicon
brentjan Mar 21, 2025
c39fdec
i18n starters
lennertdr Mar 23, 2025
241ba74
feat: implemented simple header
bramcomyn Mar 23, 2025
17e4d8d
merge: 324-landing-page into 325-login-page
bramcomyn Mar 23, 2025
5ff891d
chore: made translations consistent
bramcomyn Mar 23, 2025
98af635
feat: generated login and register components and updated very simple…
bramcomyn Mar 23, 2025
cb4b463
feat: added basic styling to increase my developer experience
bramcomyn Mar 23, 2025
38ccc51
feat: implemented forms for login and register
bramcomyn Mar 23, 2025
9fd55c4
feat: implemented very basic styling and made the correct links butto…
bramcomyn Mar 23, 2025
f17ee91
test: fixed all tests, made basic testing for the creation of each of…
bramcomyn Mar 23, 2025
9cc3f4f
test: structural tests for login, register and landing pages and rela…
bramcomyn Mar 23, 2025
cb827f7
feat: added i18n tags
bramcomyn Mar 23, 2025
11e99ba
feat: i18n updates
bramcomyn Mar 24, 2025
28fb6f7
Merge remote-tracking branch 'origin' into 325-login-page
bramcomyn Mar 24, 2025
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
19 changes: 17 additions & 2 deletions frontend/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
"newProjectRoot": "projects",
"projects": {
"frontend": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"nl": "src/locale/messages.nl.json"
}
},
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
Expand All @@ -17,6 +23,9 @@
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"localize": [
"en-US"
],
"outputPath": "dist/frontend",
"index": "src/index.html",
"browser": "src/main.ts",
Expand Down Expand Up @@ -100,10 +109,16 @@
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"cli": {
"analytics": false
}
}
}
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@angular/cli": "^17.3.0",
"@angular/compiler-cli": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/localize": "^17.3.12",
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "^8.25.0",
"@typescript-eslint/parser": "^8.25.0",
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<p>Hello World!</p>
<main>
<router-outlet></router-outlet>
</main>
3 changes: 3 additions & 0 deletions frontend/src/app/app.component.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main {
height: 100%;
}
43 changes: 20 additions & 23 deletions frontend/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { TestBed } from "@angular/core/testing";
import { provideRouter } from "@angular/router";
import { RouterTestingHarness } from "@angular/router/testing";
import { AppComponent } from "./app.component";

describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent],
}).compileComponents();
});
let component: AppComponent;
let harness: RouterTestingHarness;

it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [AppComponent],
providers: [
provideRouter([{ path: "**", component: AppComponent }])
]
});

it(`should have the 'frontend' title`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('frontend');
});
harness = await RouterTestingHarness.create();
component = await harness.navigateByUrl('/', AppComponent);
harness.detectChanges();
});

it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('p')?.textContent).toContain('Hello World!');
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
5 changes: 3 additions & 2 deletions frontend/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
imports: [
RouterOutlet
],
templateUrl: './app.component.html',
styleUrl: './app.component.less'
})
export class AppComponent {
title = 'frontend';
}
13 changes: 12 additions & 1 deletion frontend/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import { Routes } from '@angular/router';
import { LandingPageComponent } from './pages/landing-page/landing-page.component';
import { LoginPageComponent } from './pages/login-page/login-page.component';
import { RegisterPageComponent } from './pages/register-page/register-page.component';

export const routes: Routes = [];
/**
* Routing of our frontend.
* Based on https://angular.dev/guide/routing/common-router-tasks
*/
export const routes: Routes = [
{ path: '', component: LandingPageComponent },
{ path: 'login', component: LoginPageComponent },
{ path: 'register', component: RegisterPageComponent },
];
1 change: 0 additions & 1 deletion frontend/src/app/components/README.md

This file was deleted.

15 changes: 15 additions & 0 deletions frontend/src/app/components/login/login.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<form [formGroup]="loginForm" (ngSubmit)="login()">
<div class="login-email">
<label for="email">Email:</label>
<input type="email" id="email" formControlName="email" required>
</div>

<div class="login-password">
<label for="password">Password:</label>
<input type="password" id="password" formControlName="password" required>
</div>

<div class="login-submit">
<button type="submit" [disabled]="loginForm.invalid">Login</button>
</div>
</form>
7 changes: 7 additions & 0 deletions frontend/src/app/components/login/login.component.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
div {
width: 96%;
margin: 2%;
display: flex;
flex-direction: column;
justify-content: center;
}
41 changes: 41 additions & 0 deletions frontend/src/app/components/login/login.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { TestBed } from "@angular/core/testing";
import { provideRouter } from "@angular/router";
import { RouterTestingHarness } from "@angular/router/testing";
import { LoginComponent } from "./login.component";

describe('LoginComponent', () => {
let component: LoginComponent;
let harness: RouterTestingHarness;

beforeEach(async () => {
TestBed.configureTestingModule({
imports: [LoginComponent],
providers: [
provideRouter([{ path: "**", component: LoginComponent }])
]
});

harness = await RouterTestingHarness.create();
component = await harness.navigateByUrl('/', LoginComponent);
harness.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should have a login form', () => {
const loginForm = harness.fixture.nativeElement.querySelector('form');
expect(loginForm).toBeTruthy();
});

it('should have an email input', () => {
const emailInput = harness.fixture.nativeElement.querySelector('input[type="email"]');
expect(emailInput).toBeTruthy();
});

it('should have a password input', () => {
const passwordInput = harness.fixture.nativeElement.querySelector('input[type="password"]');
expect(passwordInput).toBeTruthy();
});
});
29 changes: 29 additions & 0 deletions frontend/src/app/components/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Component } from '@angular/core';
import { FormGroup, ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';

@Component({
selector: 'app-login',
standalone: true,
imports: [ReactiveFormsModule],
templateUrl: './login.component.html',
styleUrl: './login.component.less'
})
export class LoginComponent {
loginForm: FormGroup;

constructor(private formBuilder: FormBuilder) {
this.loginForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required]
});
}

login() {
// TODO: include logic
if(this.loginForm.valid) {
window.alert(`Login successful!\n${this.loginForm.value.email}`);
} else {
console.error('Invalid login form');
}
}
}
30 changes: 30 additions & 0 deletions frontend/src/app/components/register/register.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<form [formGroup]="registrationForm" (ngSubmit)="register()">
<div class="register-email">
<label for="email">Email:</label>
<input type="email" id="email" formControlName="email" required>
</div>

<div class="register-password">
<label for="password">Password:</label>
<input name="password" type="password" id="password" formControlName="password" required>
</div>

<div class="register-password">
<label for="confirmPassword">Confirm Password:</label>
<input
name="confirm-password"
type="password"
id="confirmPassword"
formControlName="confirmPassword"
required>
</div>

<div class="register-teacher">
<input type="checkbox" id="teacher" formControlName="teacher">
<label for="teacher">Teacher</label>
</div>

<div class="register-submit">
<button type="submit" [disabled]="registrationForm.invalid">Register</button>
</div>
</form>
10 changes: 10 additions & 0 deletions frontend/src/app/components/register/register.component.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
div {
width: 96%;
margin: 2%;
display: flex;
justify-content: center;
}

div:not(.register-teacher) {
flex-direction: column;
}
52 changes: 52 additions & 0 deletions frontend/src/app/components/register/register.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { TestBed } from "@angular/core/testing";
import { provideRouter } from "@angular/router";
import { RouterTestingHarness } from "@angular/router/testing";
import { RegisterComponent } from "./register.component";
import { By } from "@angular/platform-browser";

describe('RegisterComponent', () => {
let component: RegisterComponent;
let harness: RouterTestingHarness;

beforeEach(async () => {
TestBed.configureTestingModule({
imports: [RegisterComponent],
providers: [
provideRouter([{ path: "**", component: RegisterComponent }])
]
});

harness = await RouterTestingHarness.create();
component = await harness.navigateByUrl('/', RegisterComponent);
harness.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should have a register form', () => {
const registerForm = harness.fixture.nativeElement.querySelector('form');
expect(registerForm).toBeTruthy();
});

it('should have an email input', () => {
const emailInput = harness.fixture.nativeElement.querySelector('input[type="email"]');
expect(emailInput).toBeTruthy();
});

it('should have a password input', () => {
const passwordInput = harness.fixture.debugElement.query(By.css('input[name="password"]'));
expect(passwordInput).toBeTruthy();
});

it('should have a confirm password input', () => {
const confirmPasswordInput = harness.fixture.debugElement.query(By.css('input[name="confirm-password"]'));
expect(confirmPasswordInput).toBeTruthy();
});

it('should have a register button', () => {
const registerButton = harness.fixture.nativeElement.querySelector('button');
expect(registerButton).toBeTruthy();
});
});
31 changes: 31 additions & 0 deletions frontend/src/app/components/register/register.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';

@Component({
selector: 'app-register',
standalone: true,
imports: [ReactiveFormsModule],
templateUrl: './register.component.html',
styleUrl: './register.component.less'
})
export class RegisterComponent {
registrationForm: FormGroup;

constructor(private formBuilder: FormBuilder) {
this.registrationForm = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
confirmPassword: ['', Validators.required],
teacher: [false]
});
}

register() {
// TODO: include logic
if(this.registrationForm.valid) {
window.alert(`Registration successful!\n${this.registrationForm.value.email}`);
} else {
console.error('Invalid register form');
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<header>
<span class="logo">
<img i18n-alt routerLink="/" src="assets/images/logo.svg" alt="Dwengo logo">
</span>

<span class="links">
<button i18n class="home-button" routerLink="/">Home</button>
<button i18n class="login-button" routerLink="/login">Login</button>
<button i18n class="register-button" routerLink="/register">Register</button>
</span>
</header>
Loading