Skip to content

Commit 93ed9d2

Browse files
authored
Merge pull request #14 from sentemon/add-form-for-registration-and-login
Add form for registration and login, service logic for registration and login
2 parents b270fa0 + c5c2f35 commit 93ed9d2

34 files changed

+501
-124
lines changed

frontend/package-lock.json

Lines changed: 0 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727
"apollo-angular": "^8.0.0",
2828
"express": "^4.21.2",
2929
"graphql": "^16.9.0",
30-
"keycloak-angular": "^16.1.0",
31-
"keycloak-js": "^26.0.7",
3230
"rxjs": "~7.8.0",
3331
"tslib": "^2.3.0",
3432
"zone.js": "~0.14.10"

frontend/src/app/app.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<router-outlet />
2-
<div class="layout">
3-
<app-sidebar></app-sidebar>
4-
<app-main></app-main>
5-
</div>
2+
<!--<div class="layout">-->
3+
<!-- <app-sidebar></app-sidebar>-->
4+
<!-- <app-main></app-main>-->
5+
<!--</div>-->

frontend/src/app/app.config.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ import {HTTP_INTERCEPTORS, provideHttpClient} from '@angular/common/http';
77
import { provideApollo } from 'apollo-angular';
88
import { HttpLink } from 'apollo-angular/http';
99
import { InMemoryCache } from '@apollo/client/core';
10-
import { KeycloakService } from 'keycloak-angular';
11-
import {initKeycloak} from "./init-keycloak";
1210
import {AuthInterceptor} from "./core/services/auth-interceptor.service";
11+
import {environment} from "../environments/environment";
1312

1413
export const appConfig: ApplicationConfig = {
1514
providers: [
@@ -22,18 +21,11 @@ export const appConfig: ApplicationConfig = {
2221

2322
return {
2423
link: httpLink.create({
25-
uri: '<%= endpoint %>',
24+
uri: environment.auth_service,
2625
}),
2726
cache: new InMemoryCache(),
2827
};
2928
}),
30-
KeycloakService,
31-
{
32-
provide: APP_INITIALIZER,
33-
useFactory: initKeycloak,
34-
deps: [KeycloakService],
35-
multi: true
36-
},
3729
{
3830
provide: HTTP_INTERCEPTORS,
3931
useClass: AuthInterceptor,

frontend/src/app/app.routes.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { Routes } from '@angular/router';
2-
import {AuthGuard} from "./core/services/auth-guard.service";
32
import {AppComponent} from "./app.component";
3+
import {LoginComponent} from "./features/auth/componets/login/login.component";
4+
import {RegisterComponent} from "./features/auth/componets/register/register.component";
5+
import {ProfileComponent} from "./features/auth/componets/profile/profile.component";
46

57
export const routes: Routes = [
68
// { path: '', component: AppComponent, canActivate: [AuthGuard] },
9+
{ path: 'sentemon', component: ProfileComponent },
10+
{ path: 'login', component: LoginComponent },
11+
{ path: 'register', component: RegisterComponent },
712
{ path: '**', redirectTo: '', pathMatch: 'full' }
813
];
Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,9 @@
1-
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
2-
import { KeycloakAuthGuard, KeycloakService } from "keycloak-angular";
3-
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from "@angular/router";
1+
import { Injectable } from '@angular/core';
42

53
@Injectable({
64
providedIn: 'root'
75
})
8-
export class AuthGuard extends KeycloakAuthGuard {
6+
export class AuthGuard {
97

10-
constructor(
11-
protected override router: Router,
12-
protected override keycloakAngular: KeycloakService,
13-
@Inject(PLATFORM_ID) private platformId: Object
14-
) {
15-
super(router, keycloakAngular);
16-
}
17-
18-
public override async isAccessAllowed(
19-
route: ActivatedRouteSnapshot,
20-
state: RouterStateSnapshot): Promise<boolean> {
21-
if (!this.keycloakAngular.isLoggedIn()) {
22-
await this.keycloakAngular.login({
23-
redirectUri: window.location.origin + state.url
24-
});
25-
26-
return false;
27-
}
28-
29-
return true;
30-
}
8+
constructor() {}
319
}
Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,16 @@
11
import { Injectable } from '@angular/core';
22
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "@angular/common/http";
33
import {Observable} from 'rxjs';
4-
import {KeycloakService} from "keycloak-angular";
54

65
@Injectable({
76
providedIn: 'root'
87
})
98
export class AuthInterceptor implements HttpInterceptor {
109

11-
constructor(private keycloakService: KeycloakService) { }
10+
constructor() { }
1211

1312
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
14-
return new Observable(observer => {
15-
this.keycloakService.updateToken(5).then(() => {
16-
const token = this.keycloakService.getKeycloakInstance().token;
17-
18-
if (token) {
19-
req = req.clone({
20-
setHeaders: {
21-
Authorization: `Bearer ${token}`,
22-
},
23-
});
24-
}
25-
26-
next.handle(req).subscribe(
27-
event => observer.next(event),
28-
err => observer.error(err),
29-
() => observer.complete()
30-
);
31-
}).catch(err => {
32-
console.error('Failed to refresh token', err);
33-
observer.error(err);
34-
});
35-
});
13+
return new Observable()
3614
}
3715

3816
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
.form {
2+
display: flex;
3+
justify-content: center;
4+
align-items: center;
5+
height: 100vh;
6+
7+
form {
8+
display: flex;
9+
flex-direction: column;
10+
11+
h1 {
12+
margin-bottom: 1.5rem;
13+
text-align: center;
14+
}
15+
16+
.fields {
17+
display: flex;
18+
flex-direction: column;
19+
gap: 1rem;
20+
21+
input {
22+
padding: 0.8rem;
23+
font-size: 1rem;
24+
border: 1px solid #ccc;
25+
border-radius: 4px;
26+
outline: none;
27+
transition: border-color 0.3s;
28+
29+
&:focus {
30+
border-color: #007bff;
31+
}
32+
}
33+
}
34+
35+
button {
36+
margin-top: 1rem;
37+
padding: 0.8rem;
38+
font-size: 1rem;
39+
color: white;
40+
background-color: black;
41+
border: none;
42+
border-radius: 4px;
43+
cursor: pointer;
44+
transition: background-color 0.3s;
45+
46+
&:hover {
47+
background-color: #333;
48+
}
49+
}
50+
51+
p {
52+
margin-top: 10px;
53+
54+
a {
55+
text-decoration: none;
56+
}
57+
}
58+
}
59+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div class="form">
2+
<form [formGroup]="loginForm" (ngSubmit)="onLogin()">
3+
<h1>Login to Fitness App</h1>
4+
<div class="fields">
5+
<input id="email" type="email" formControlName="email" placeholder="Email / Username" name="email" autocomplete="username" autocapitalize="off">
6+
<input id="password" type="password" formControlName="password" placeholder="Password">
7+
</div>
8+
<button type="submit">Login</button>
9+
<p>Don't have an account? <a routerLink="/register">Register</a></p>
10+
</form>
11+
</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { LoginComponent } from './login.component';
4+
5+
describe('LoginComponent', () => {
6+
let component: LoginComponent;
7+
let fixture: ComponentFixture<LoginComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [LoginComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(LoginComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Component } from '@angular/core';
2+
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
3+
import {NgIf} from "@angular/common";
4+
import {RouterLink} from "@angular/router";
5+
import {AuthGuardService} from "../../services/auth-guard.service";
6+
7+
@Component({
8+
selector: 'app-login',
9+
standalone: true,
10+
imports: [
11+
ReactiveFormsModule,
12+
NgIf,
13+
RouterLink
14+
],
15+
templateUrl: './login.component.html',
16+
styleUrl: './../auth.scss'
17+
})
18+
export class LoginComponent {
19+
loginForm: FormGroup;
20+
21+
constructor(private authGuardService: AuthGuardService, private formBuilder: FormBuilder) {
22+
this.loginForm = this.formBuilder.group({
23+
email: ['', [Validators.required]],
24+
password: ['', [Validators.required, Validators.minLength(6)]]
25+
})
26+
}
27+
onLogin() {
28+
if (this.loginForm.valid) {
29+
// ToDo: save to cookie
30+
this.authGuardService.login(this.loginForm.value.email, this.loginForm.value.password).subscribe(result => {
31+
console.log(result);
32+
});
33+
} else {
34+
// ToDo
35+
console.log('Form is invalid', this.loginForm.errors);
36+
}
37+
}
38+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>logout works!</p>

frontend/src/app/features/auth/componets/logout/logout.component.scss

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { LogoutComponent } from './logout.component';
4+
5+
describe('LogoutComponent', () => {
6+
let component: LogoutComponent;
7+
let fixture: ComponentFixture<LogoutComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [LogoutComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(LogoutComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'app-logout',
5+
standalone: true,
6+
imports: [],
7+
templateUrl: './logout.component.html',
8+
styleUrl: './logout.component.scss'
9+
})
10+
export class LogoutComponent {
11+
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<p>profile works!</p>
2+
<p>{{ user?.firstName }}</p>
3+
<p>{{ user?.lastName }}</p>
4+
<p>{{ user?.username }}</p>
5+
<button (click)="getSentemon()" >Get Sentemon</button>

frontend/src/app/features/auth/componets/profile/profile.component.scss

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ProfileComponent } from './profile.component';
4+
5+
describe('ProfileComponent', () => {
6+
let component: ProfileComponent;
7+
let fixture: ComponentFixture<ProfileComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [ProfileComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(ProfileComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});

0 commit comments

Comments
 (0)