Added login UI

- Added empty adminui component
- Added authStore
This commit is contained in:
Max W. 2024-05-30 13:44:38 +02:00
parent 414d152655
commit 95c9b2082a
11 changed files with 208 additions and 1 deletions

View File

@ -0,0 +1 @@
<p>adminui works!</p>

View 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();
});
});

View 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 {
}

View File

@ -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' }
];

View File

@ -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

View 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>

View 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();
});
});

View 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;
});
}
}

View 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 });
}
}