Added login UI
- Added empty adminui component - Added authStore
This commit is contained in:
parent
414d152655
commit
95c9b2082a
1
frontend/src/app/adminui/adminui.component.html
Normal file
1
frontend/src/app/adminui/adminui.component.html
Normal file
@ -0,0 +1 @@
|
||||
<p>adminui works!</p>
|
0
frontend/src/app/adminui/adminui.component.scss
Normal file
0
frontend/src/app/adminui/adminui.component.scss
Normal file
23
frontend/src/app/adminui/adminui.component.spec.ts
Normal file
23
frontend/src/app/adminui/adminui.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AdminuiComponent } from './adminui.component';
|
||||
|
||||
describe('AdminuiComponent', () => {
|
||||
let component: AdminuiComponent;
|
||||
let fixture: ComponentFixture<AdminuiComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AdminuiComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AdminuiComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
frontend/src/app/adminui/adminui.component.ts
Normal file
12
frontend/src/app/adminui/adminui.component.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-adminui',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './adminui.component.html',
|
||||
styleUrl: './adminui.component.scss'
|
||||
})
|
||||
export class AdminuiComponent {
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ import {UploadComponent} from "./upload/upload.component";
|
||||
import {DownloadComponent} from "./download/download.component";
|
||||
import {CreditsComponent} from "./credits/credits.component";
|
||||
import {LicensesComponent} from "./credits/licenses/licenses.component";
|
||||
import {LoginComponent} from "./login/login.component";
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
@ -12,6 +13,7 @@ export const routes: Routes = [
|
||||
{ path: 'download', component: DownloadComponent },
|
||||
{ path: 'credits', component: CreditsComponent },
|
||||
{ path: 'licenses', component: LicensesComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
// { path: 'download/:id', component: DownloadComponent }
|
||||
{ path: '**', redirectTo: 'home' }
|
||||
];
|
||||
|
@ -8,7 +8,7 @@
|
||||
<img class="w-56 mt-6 mb-6" src="./assets/cloud-arrow-down-solid.svg">
|
||||
<input type="text" class="input input-bordered text-center w-full max-w-md mb-6" placeholder="Enter download code/link"
|
||||
[(ngModel)]="inputFileId"
|
||||
(keydown.enter)="requestDownload()"/>
|
||||
(keydown.enter)="requestDownload()"/>
|
||||
|
||||
<div class="mb-6 w-full flex flex-col items-center justify-center">
|
||||
<input
|
||||
|
46
frontend/src/app/login/login.component.html
Normal file
46
frontend/src/app/login/login.component.html
Normal file
@ -0,0 +1,46 @@
|
||||
<div class="container mx-auto p-4 mt-20">
|
||||
<div class="bg-white shadow-lg rounded-lg p-10 w-full max-w-xl mx-auto">
|
||||
<h2 class="text-3xl font-bold text-gray-800 mb-6 text-center">Login to SharePulse</h2>
|
||||
<form>
|
||||
<div class="mb-5">
|
||||
<label class="block text-gray-700 text-sm font-bold mb-2 text-center" for="username">
|
||||
Username
|
||||
</label>
|
||||
<input class="input w-full shadow text-center" id="username" type="text" placeholder="Username"
|
||||
[(ngModel)]="inputUsername" name="username"
|
||||
[ngClass]="{'input-error': loginFailed}">
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<label class="block text-gray-700 text-sm font-bold mb-2 text-center" for="password">
|
||||
Password
|
||||
</label>
|
||||
<input class="input w-full shadow text-center" id="password" type="password" placeholder="********"
|
||||
[(ngModel)]="inputPassword" name="password"
|
||||
[ngClass]="{'input-error': loginFailed}"
|
||||
(keydown.enter)="tryToLogin()" >
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<label class="flex items-center justify-center">
|
||||
<input type="checkbox" class="toggle" checked name="keepSignedIn"/>
|
||||
<span class="ml-2 text-gray-700">Keep me signed in</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<button *ngIf="!loginSuccessful" class="btn btn-primary w-full hover:scale-105 transition-transform duration-100" type="button" (click)="tryToLogin()">
|
||||
Login
|
||||
</button>
|
||||
<button *ngIf="loginSuccessful" class="btn btn-success w-full hover:scale-105 transition-transform duration-100" type="button">
|
||||
<span class="loading loading-ring loading-xs bg-white"></span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="white" class="bi bi-check-lg" viewBox="0 0 16 16">
|
||||
<path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425z"/>
|
||||
</svg>
|
||||
<span class="loading loading-ring loading-xs bg-white"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-gray-600 text-center">
|
||||
Login to SharePulse to access the administrative dashboard and manage uploaded files. Please note that registration is disabled.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
0
frontend/src/app/login/login.component.scss
Normal file
0
frontend/src/app/login/login.component.scss
Normal file
23
frontend/src/app/login/login.component.spec.ts
Normal file
23
frontend/src/app/login/login.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [LoginComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
60
frontend/src/app/login/login.component.ts
Normal file
60
frontend/src/app/login/login.component.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {DevelopmentStore} from "../../store/DevelopmentStore";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import axios from "axios";
|
||||
import {NgClass, NgIf} from "@angular/common";
|
||||
import {AuthStore} from "../../store/authStore";
|
||||
import {firstValueFrom} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
standalone: true,
|
||||
imports: [
|
||||
FormsModule,
|
||||
NgClass,
|
||||
NgIf
|
||||
],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.scss'
|
||||
})
|
||||
export class LoginComponent {
|
||||
inputUsername: string = "";
|
||||
inputPassword: string = "";
|
||||
loginFailed: boolean = false;
|
||||
loginSuccessful: boolean = false;
|
||||
|
||||
constructor(private developmentStore: DevelopmentStore, private authStore: AuthStore) {
|
||||
}
|
||||
|
||||
tryToLogin() {
|
||||
console.log("Trying to login with username: " + this.inputUsername + " and password: " + this.inputPassword);
|
||||
|
||||
axios({
|
||||
method: 'post',
|
||||
url: this.developmentStore.getBaseUrl() + 'api/v1/auth/login',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: {
|
||||
username: this.inputUsername,
|
||||
password: this.inputPassword
|
||||
}
|
||||
})
|
||||
.then(async response => {
|
||||
console.log(response);
|
||||
console.log(response.data);
|
||||
if(response.data.token) {
|
||||
this.loginSuccessful = true;
|
||||
this.authStore.setToken(response.data.token);
|
||||
this.authStore.setUsername(this.inputUsername);
|
||||
|
||||
console.log("Login successful");
|
||||
console.log("Token: " + await firstValueFrom(this.authStore.token$));
|
||||
console.log("Username: " + await firstValueFrom(this.authStore.username$));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.loginFailed = true;
|
||||
});
|
||||
}
|
||||
}
|
40
frontend/src/store/authStore.ts
Normal file
40
frontend/src/store/authStore.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
interface AuthStoreState {
|
||||
username: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthStore {
|
||||
private state: BehaviorSubject<AuthStoreState> = new BehaviorSubject<AuthStoreState>({
|
||||
username: "",
|
||||
token: "",
|
||||
});
|
||||
|
||||
// Getter for username
|
||||
get username$() {
|
||||
return this.state.asObservable().pipe(map(state => state.username));
|
||||
}
|
||||
|
||||
// Getter for token
|
||||
get token$() {
|
||||
return this.state.asObservable().pipe(map(state => state.token));
|
||||
}
|
||||
|
||||
// Mutation for username
|
||||
setUsername(username: string) {
|
||||
const currentState = this.state.getValue();
|
||||
this.state.next({ ...currentState, username });
|
||||
}
|
||||
|
||||
// Mutation for token
|
||||
setToken(token: string) {
|
||||
const currentState = this.state.getValue();
|
||||
this.state.next({ ...currentState, token });
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user