Compare commits

...

21 Commits

Author SHA1 Message Date
bebdbcaacc update package lock
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-23 15:53:08 +01:00
e124b8b62c Merge remote-tracking branch 'origin/renovate/jasmine-core-5.x'
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-23 15:37:26 +01:00
96c1bc3c46 Merge branch 'renovate/typescript-eslint-parser-7.x'
Some checks failed
continuous-integration/drone/push Build was killed
2025-03-23 15:37:09 +01:00
9cb3467b2a Merge pull request 'Update dependency @typescript-eslint/eslint-plugin to v7.18.0' (!2) from renovate/typescript-eslint-eslint-plugin-7.x into main
Some checks failed
continuous-integration/drone/push Build was killed
Reviewed-on: #2
2025-03-23 15:34:20 +01:00
cd74e79efd Update dependency jasmine-core to ~5.6.0 2025-03-23 13:28:24 +00:00
5663048b79 Update dependency @typescript-eslint/parser to v7.18.0
Some checks failed
continuous-integration/drone/pr Build is failing
2025-03-23 12:27:34 +00:00
f188a34e7d Update dependency @typescript-eslint/eslint-plugin to v7.18.0
Some checks failed
continuous-integration/drone/pr Build is failing
2025-03-23 11:29:59 +00:00
25e998041c Merge pull request 'Configure Renovate' (!1) from renovate/configure into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #1
2025-03-23 11:58:38 +01:00
a91b06213c Add renovate.json
Some checks failed
continuous-integration/drone/pr Build is failing
2025-03-22 23:13:13 +00:00
1c82e15d28 use node 20
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-09 01:31:22 +01:00
12a0b2b1a3 fix code scan
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-09 01:29:59 +01:00
86cd25435e workaround for aarch64
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-09 01:25:59 +01:00
64b8d3e32a use official sonar image
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-09 01:21:15 +01:00
b28915a3a6 fix sonar-scanner
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-09 01:18:35 +01:00
0e16025d56 disable tests
Some checks failed
continuous-integration/drone/push Build is failing
2025-03-09 01:16:24 +01:00
7e4fee5a05 implement drone
Some checks failed
continuous-integration/drone/push Build was killed
2025-03-09 01:14:22 +01:00
1bb4d1d134 RLH-12 | Implement username changing 2024-11-04 11:25:19 +01:00
c4e8e7483a RLH-18 | Implement Account rename APIs 2024-11-04 11:24:14 +01:00
5e5b81743a RLH-12 - Implement account page basic func with sidebar 2024-11-04 09:33:35 +01:00
ddfe5e7f02 RLH-15 - Implement Input component 2024-11-04 09:32:11 +01:00
ec27ad7ee2 RLH-14 - Implement Button component 2024-11-04 09:31:29 +01:00
31 changed files with 2014 additions and 69 deletions

61
.drone.yml Normal file
View File

@@ -0,0 +1,61 @@
kind: pipeline
type: docker
name: build
platform:
os: linux
arch: arm64
trigger:
branch:
- main
event:
- push
- pull_request
steps:
# Install project dependencies
- name: install
image: node:20-alpine
commands:
- npm ci
# Build the Angular project
- name: build
image: node:20-alpine
commands:
- npm run build --if-present
# Run unit tests (e.g. using Karma, Jest or your configured test runner)
# - name: test
# image: node:20-alpine
# commands:
# - npm test
# Run SonarQube code analysis
- name: code-analysis
image: openjdk:11-jre-slim
commands:
# Update package lists and install dependencies for Node.js
- apt-get update && apt-get install -y curl gnupg wget unzip
# Install Node.js (e.g., version 18) using Nodesource setup script
- curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
- apt-get install -y nodejs
# Verify Node.js is installed
- node -v
- npm -v
# Download the SonarScanner CLI zip (adjust the version as needed)
- wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-7.0.2.4839-linux-aarch64.zip -O sonar-scanner.zip
# Unzip it to /opt
- unzip sonar-scanner.zip -d /opt/
- rm sonar-scanner.zip
# Add sonar-scanner to the PATH (the folder name may vary with version)
- export PATH=/opt/sonar-scanner-7.0.2.4839-linux-aarch64/bin:$PATH
# Run the scanner
- sonar-scanner -Dsonar.projectKey=$SONAR_PROJECT_KEY -Dsonar.sources=. -Dsonar.host.url=$SONAR_INSTANCE_URL -Dsonar.token=$SONAR_LOGIN_KEY
environment:
SONAR_PROJECT_KEY:
from_secret: sonar_project_key
SONAR_INSTANCE_URL:
from_secret: sonar_instance_url
SONAR_LOGIN_KEY:
from_secret: sonar_login_key

48
.eslintrc.json Normal file
View File

@@ -0,0 +1,48 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:@angular-eslint/template/accessibility"
],
"rules": {}
}
]
}

3
.gitignore vendored
View File

@@ -40,3 +40,6 @@ testem.log
# System files # System files
.DS_Store .DS_Store
Thumbs.db Thumbs.db
.nx/cache
.nx/workspace-data

View File

@@ -102,8 +102,22 @@
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js" "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
] ]
} }
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
} }
} }
} }
},
"cli": {
"schematicCollections": [
"@angular-eslint/schematics"
]
} }
} }

1521
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,8 @@
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test",
"lint": "ng lint"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
@@ -24,17 +25,26 @@
"bootstrap-icons": "^1.11.3", "bootstrap-icons": "^1.11.3",
"mdb-ui-kit": "^8.0.0", "mdb-ui-kit": "^8.0.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"nanoid": "^5.0.8",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.14.3" "zone.js": "~0.14.3"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^17.3.11", "@angular-devkit/build-angular": "^17.3.11",
"@angular-eslint/builder": "17.5.3",
"@angular-eslint/eslint-plugin": "17.5.3",
"@angular-eslint/eslint-plugin-template": "17.5.3",
"@angular-eslint/schematics": "17.5.3",
"@angular-eslint/template-parser": "17.5.3",
"@angular/cli": "^17.3.11", "@angular/cli": "^17.3.11",
"@angular/compiler-cli": "^17.3.0", "@angular/compiler-cli": "^17.3.0",
"@angular/localize": "^17.3.0", "@angular/localize": "^17.3.0",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0", "@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"eslint": "^8.57.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
@@ -42,4 +52,4 @@
"karma-jasmine-html-reporter": "~2.1.0", "karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.4.2" "typescript": "~5.4.2"
} }
} }

3
renovate.json Normal file
View File

@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@@ -1,6 +1,6 @@
import {HTTP_INTERCEPTORS} from "@angular/common/http"; import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {AuthInterceptorService} from "./services/auth-interceptor.service"; import {AuthInterceptorService} from "./services/auth-interceptor.service";
import {AfterViewChecked, AfterViewInit, Component, OnInit} from "@angular/core"; import {Component} from "@angular/core";
import {RouterOutlet} from "@angular/router"; import {RouterOutlet} from "@angular/router";
import {LoginComponent} from "./views/login/login.component"; import {LoginComponent} from "./views/login/login.component";
import {ApiService} from "./services/api.service"; import {ApiService} from "./services/api.service";

View File

@@ -1,8 +1,8 @@
import {ApplicationConfig} from '@angular/core'; import {ApplicationConfig} from '@angular/core';
import {provideRouter, provideRoutes, withComponentInputBinding} from '@angular/router'; import {provideRouter} from '@angular/router';
import {routes} from './app.routes'; import {routes} from './app.routes';
import {provideHttpClient, withInterceptors, withInterceptorsFromDi} from "@angular/common/http"; import {provideHttpClient, withInterceptorsFromDi} from "@angular/common/http";
import {httpInterceptorProviders} from "./app.component"; import {httpInterceptorProviders} from "./app.component";
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {

View File

@@ -1,7 +1,10 @@
<button <ng-container *ngIf="!!button.visible && button.visible()">
type="button" <button
class="btn btn-link" type="button"
[disabled]="buttonDisabled()" class="m-1 {{classes}}"
(click)="button.click()"> [disabled]="isDisabled()"
{{button.text}} (click)="button.click()">
</button> {{ button.text }}
</button>
</ng-container>

View File

@@ -1,10 +1,13 @@
import {booleanAttribute, Component, Input, OnInit} from '@angular/core'; import {Component, Input, OnInit} from '@angular/core';
import {ButtonModel} from "./models/button.model"; import {ButtonModel, ButtonType} from "./models/button.model";
import {NgIf} from "@angular/common";
@Component({ @Component({
selector: 'rlh-button', selector: 'rlh-button',
standalone: true, standalone: true,
imports: [], imports: [
NgIf
],
templateUrl: './button.component.html', templateUrl: './button.component.html',
styleUrl: './button.component.scss' styleUrl: './button.component.scss'
}) })
@@ -14,26 +17,38 @@ export class ButtonComponent implements OnInit
@Input() button: ButtonModel = { @Input() button: ButtonModel = {
text: 'text', text: 'text',
disabled: () => false, disabled: () => false,
click: () => {} visible: () => true,
click: () => {},
type: ButtonType.PRIMARY
}; };
buttonDisabled: () => boolean = () => { isDisabled: () => boolean = () => {
return false; return false;
// tslint:disable-next-line: semicolon
}; };
ngOnInit() { ngOnInit() {
this.button.disabled = this.button.disabled this.button.disabled = this.button.disabled
? this.button.disabled ? this.button.disabled
: () => false; : () => false;
//
setTimeout(() => { setTimeout(() => {
this.buttonDisabled = () => { this.isDisabled = () => {
return this.button.disabled(); return this.button.disabled();
}; };
}); });
this.button.visible =
this.button.visible ?
this.button.visible : () => true;
} }
get classes(): string {
let classes = 'btn';
classes += ' ' + (this.button.type ? this.button.type : ButtonType.PRIMARY);
return classes;
}

View File

@@ -1,5 +1,19 @@
export class ButtonModel { export class ButtonModel {
text: string = "text"; text: string = "text";
type: ButtonType;
disabled: () => boolean; disabled: () => boolean;
click: () => void; click: () => void;
visible?: () => boolean;
}
export enum ButtonType {
LINK = "btn-link",
PRIMARY = "btn-primary",
SECONDARY = "btn-secondary",
SUCCESS = "btn-success",
DANGER = "btn-danger",
WARNING = "btn-warning",
INFO = "btn-info",
LIGHT = "btn-light",
DARK = "btn-dark"
} }

View File

@@ -0,0 +1,10 @@
<input
[name]="input.id"
[id]="'input-' + input.id"
[disabled]="isDisabled()"
[type]="input.type"
(ngModelChange)="input.modelChange()"
class="form-control m-1"
[(ngModel)]="model"
/>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { InputComponent } from './input.component';
describe('InputComponent', () => {
let component: InputComponent;
let fixture: ComponentFixture<InputComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [InputComponent]
})
.compileComponents();
fixture = TestBed.createComponent(InputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,61 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {InputModel, InputType} from "./input.model";
import {FormsModule} from "@angular/forms";
import {nanoid} from "nanoid";
@Component({
selector: 'rlh-input',
standalone: true,
imports: [
FormsModule
],
templateUrl: './input.component.html',
styleUrl: './input.component.scss'
})
export class InputComponent implements OnInit {
renderModel: any
@Input() input: InputModel = {
type: InputType.TEXT,
disabled: () => false,
modelChange: () => {}
};
@Input()
get model() {
return this.renderModel;
}
set model(val: any) {
if (val !== this.renderModel) {
this.renderModel = val;
this.modelChange.emit(val);
}
}
@Output() modelChange = new EventEmitter<any>();
isDisabled: () => boolean = () => {
return false;
};
ngOnInit() {
this.input.disabled = this.input.disabled
? this.input.disabled
: () => false;
setTimeout(() => {
this.isDisabled = () => {
return this.input.disabled();
};
});
if(!this.input.id || this.input.id.length < 1) {
this.input.id = nanoid(12);
}
}
}

View File

@@ -0,0 +1,7 @@
import { InputModel } from './input.model';
describe('InputModel', () => {
it('should create an instance', () => {
expect(new InputModel()).toBeTruthy();
});
});

View File

@@ -0,0 +1,13 @@
export class InputModel {
id?: string;
type: InputType;
disabled: () => boolean;
modelChange: () => void;
}
export enum InputType {
TEXT = 'text',
NUMBER = 'number',
EMAIL = 'email',
PASSWORD = 'password'
}

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { AccountService } from './account.service';
describe('AccountService', () => {
let service: AccountService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AccountService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {UserData} from "../interface/user";
import {Observable} from "rxjs";
@Injectable({
providedIn: 'root'
})
export class AccountService {
private apiUrl = 'http://localhost:8080/api/';
constructor(
private http: HttpClient
) {}
// v1 ACCOUNT
changeUsername(uuid: string, username: string): Observable<string> {
const body = {
uuid: uuid,
username: username
}
return this.http.post<string>(this.apiUrl + 'v1/account/edit', body);
}
}

View File

@@ -11,9 +11,7 @@ export class ApiService {
constructor( constructor(
private http: HttpClient private http: HttpClient
) { ) {}
}
// v1 USERS // v1 USERS

View File

@@ -11,7 +11,7 @@ export class AuthInterceptorService implements HttpInterceptor {
const tokenId = localStorage.getItem('tokenId'); const tokenId = localStorage.getItem('tokenId');
if (!!tokenId) { if (tokenId) {
const cloned = req.clone({ const cloned = req.clone({
headers: req.headers.set("Authorization", headers: req.headers.set("Authorization",
"Bearer " + tokenId) "Bearer " + tokenId)

View File

@@ -1,15 +1,17 @@
<div class="row border p-4"> <div class="row border p-4">
<b>Profile Management</b> <div class="row-3">
<div class="nav flex-column nav-pills"> <b>Profile Management</b>
<div> <div class="nav flex-column nav-pills">
<rlh-button <div>
[button]="accountManagementButton" <rlh-button
></rlh-button> [button]="accountManagementButton"
</div> ></rlh-button>
<div> </div>
<rlh-button <div>
[button]="publicProfileButton" <rlh-button
></rlh-button> [button]="publicProfileButton"
></rlh-button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,6 @@
import {Component, EventEmitter, Output} from '@angular/core'; import {Component, EventEmitter, Output} from '@angular/core';
import {ButtonComponent} from "../../../libraries/components/button/button.component"; import {ButtonComponent} from "../../../libraries/components/button/button.component";
import {ButtonModel} from "../../../libraries/components/button/models/button.model"; import {ButtonModel, ButtonType} from "../../../libraries/components/button/models/button.model";
@Component({ @Component({
selector: 'app-account-navigation', selector: 'app-account-navigation',
@@ -13,7 +13,7 @@ import {ButtonModel} from "../../../libraries/components/button/models/button.mo
}) })
export class AccountNavigationComponent { export class AccountNavigationComponent {
@Output() onNavChange = new EventEmitter<string>(); @Output() navChange = new EventEmitter<string>();
selectedMenu = "ACC"; selectedMenu = "ACC";
@@ -22,17 +22,19 @@ export class AccountNavigationComponent {
click: () => click: () =>
{ {
this.selectedMenu = 'ACC'; this.selectedMenu = 'ACC';
this.onNavChange.emit(this.selectedMenu); this.navChange.emit(this.selectedMenu);
}, },
text: 'Account Management' text: 'Account Management',
type: ButtonType.LINK
} }
publicProfileButton: ButtonModel = { publicProfileButton: ButtonModel = {
disabled: () => this.selectedMenu === 'PPF', disabled: () => this.selectedMenu === 'PPF',
click: () => { click: () => {
this.selectedMenu = 'PPF'; this.selectedMenu = 'PPF';
this.onNavChange.emit(this.selectedMenu); this.navChange.emit(this.selectedMenu);
}, },
text: 'Public Profile' text: 'Public Profile',
type: ButtonType.LINK
} }
} }

View File

@@ -2,7 +2,7 @@
<div class="row"> <div class="row">
<div class="col-3"> <div class="col-3">
<app-account-navigation <app-account-navigation
(onNavChange)="navChanged($event)" (navChange)="navChanged($event)"
> >
</app-account-navigation> </app-account-navigation>
</div> </div>

View File

@@ -1,6 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {ButtonComponent} from "../../libraries/components/button/button.component"; import {ButtonComponent} from "../../libraries/components/button/button.component";
import {ButtonModel} from "../../libraries/components/button/models/button.model";
import {DashboardComponent} from "../dashboard/dashboard.component"; import {DashboardComponent} from "../dashboard/dashboard.component";
import {NgIf} from "@angular/common"; import {NgIf} from "@angular/common";
import {LoginComponent} from "../login/login.component"; import {LoginComponent} from "../login/login.component";

View File

@@ -1,4 +1,4 @@
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import {LoginComponent} from "../../login/login.component"; import {LoginComponent} from "../../login/login.component";
import {NgIf} from "@angular/common"; import {NgIf} from "@angular/common";
import {RegisterComponent} from "../../register/register.component"; import {RegisterComponent} from "../../register/register.component";
@@ -15,7 +15,7 @@ import {AuthService} from "../../../services/auth.service";
templateUrl: './auth-form.component.html', templateUrl: './auth-form.component.html',
styleUrl: './auth-form.component.scss' styleUrl: './auth-form.component.scss'
}) })
export class AuthFormComponent { export class AuthFormComponent implements OnInit {
constructor(private authService: AuthService) { constructor(private authService: AuthService) {
} }

View File

@@ -1,8 +1,52 @@
<div *ngIf="isLoggedIn"> <div *ngIf="isLoggedIn">
<p class="border"> <h2 class="p-3">Account Management</h2>
<b>Username: </b>{{userData.username}} | <div class="p-4">
<b>eMail: </b>{{userData.email}} | <div class="row">
<b>UUID: </b>{{userData.uuid}} | <div class="col-4">
<b>Created At: </b>{{userData.createdAt}} <b>Username</b>
</p> <div>
<rlh-input
[input]="usernameInput"
[(model)]="userData.username">
</rlh-input>
</div>
</div>
<div class="col-2">
Actions
<div>
<rlh-button *ngIf="!isEditingUsername"
[button]="editUsernameButton">
</rlh-button>
<rlh-button *ngIf="isEditingUsername"
[button]="saveUsernameButton">
</rlh-button>
</div>
</div>
</div>
<div class="row">
<div class="col-4">
<b>Email</b>
<rlh-input
[input]="emailInput"
[(model)]="userData.email">
</rlh-input>
</div>
</div>
<div class="row">
<div class="col-4">
<b>UUID</b>
<rlh-input
[input]="uuidInput"
[(model)]="userData.uuid">
</rlh-input>
</div>
<div class="col-4">
<b>Created At</b>
<rlh-input
[input]="createdAtInput"
[(model)]="userData.createdAt">
</rlh-input>
</div>
</div>
</div>
</div> </div>

View File

@@ -2,10 +2,15 @@ import {Component, OnInit} from '@angular/core';
import {UserData} from "../../interface/user"; import {UserData} from "../../interface/user";
import {AuthService} from "../../services/auth.service"; import {AuthService} from "../../services/auth.service";
import {ApiService} from "../../services/api.service"; import {ApiService} from "../../services/api.service";
import {NgbDatepicker, NgbDateStruct} from "@ng-bootstrap/ng-bootstrap"; import {NgbDatepicker} from "@ng-bootstrap/ng-bootstrap";
import {FormsModule} from "@angular/forms"; import {FormsModule} from "@angular/forms";
import {NgIf} from "@angular/common"; import {NgIf} from "@angular/common";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {InputComponent} from "../../libraries/components/input/input.component";
import {InputModel, InputType} from "../../libraries/components/input/input.model";
import {ButtonComponent} from "../../libraries/components/button/button.component";
import {ButtonModel, ButtonType} from "../../libraries/components/button/models/button.model";
import {AccountService} from "../../services/account.service";
@Component({ @Component({
selector: 'app-dashboard', selector: 'app-dashboard',
@@ -13,7 +18,9 @@ import {Router} from "@angular/router";
imports: [ imports: [
NgbDatepicker, NgbDatepicker,
FormsModule, FormsModule,
NgIf NgIf,
InputComponent,
ButtonComponent
], ],
templateUrl: './dashboard.component.html', templateUrl: './dashboard.component.html',
styleUrl: './dashboard.component.scss' styleUrl: './dashboard.component.scss'
@@ -22,6 +29,50 @@ export class DashboardComponent implements OnInit {
isLoggedIn = false; isLoggedIn = false;
usernameInput: InputModel = {
type: InputType.TEXT,
disabled: () => !this.isEditingUsername,
modelChange: () => {}
}
emailInput: InputModel = {
type: InputType.EMAIL,
disabled: () => true,
modelChange: () => {}
}
uuidInput: InputModel = {
type: InputType.TEXT,
disabled: () => true,
modelChange: () => {}
}
createdAtInput: InputModel = {
type: InputType.TEXT,
disabled: () => true,
modelChange: () => {}
}
editUsernameButton: ButtonModel = {
disabled: () => this.isEditingUsername,
visible: () => !this.isEditingUsername,
click: () => {
this.isEditingUsername = true;
},
text: 'Edit',
type: ButtonType.SECONDARY
}
saveUsernameButton: ButtonModel = {
disabled: () => !this.isEditingUsername,
visible: () => this.isEditingUsername,
click: () => {
this.saveUsername();
},
text: 'Save',
type: ButtonType.PRIMARY
}
userData: UserData = { userData: UserData = {
uuid: null, uuid: null,
username: null, username: null,
@@ -29,7 +80,12 @@ export class DashboardComponent implements OnInit {
createdAt: null createdAt: null
} }
constructor(private authService: AuthService, private apiService: ApiService, private router: Router) { isEditingUsername = false;
constructor(private authService: AuthService,
private apiService: ApiService,
private accountService: AccountService,
private router: Router) {
} }
ngOnInit(): void { ngOnInit(): void {
@@ -43,4 +99,19 @@ export class DashboardComponent implements OnInit {
} }
} }
saveUsername(): void {
this.isEditingUsername = false;
this.apiService.getCurrentUser().subscribe(res => {
if(!res) return;
let uuid = res.uuid;
if(!!uuid) {
this.accountService.changeUsername(uuid, this.userData.username)
.subscribe(res => {
this.userData.username = res;
});
}
});
}
} }

View File

@@ -10,7 +10,7 @@
*ngIf="!!loggedUser && !!loggedUser.username"> *ngIf="!!loggedUser && !!loggedUser.username">
<div class="col-4"> <div class="col-4">
<div class="form-group" data-mdb-input-init> <div class="form-group" data-mdb-input-init>
<label class="form-label">Username</label> <p class="form-label">Username</p>
<input type="text" <input type="text"
class="form-control" class="form-control"
name="loggedUser.username" name="loggedUser.username"
@@ -22,7 +22,7 @@
<div class="row justify-content-center mb-2"> <div class="row justify-content-center mb-2">
<div class="col-4"> <div class="col-4">
<div class="form-group" data-mdb-input-init> <div class="form-group" data-mdb-input-init>
<label class="form-label">Email address</label> <p class="form-label">Email address</p>
<input type="text" <input type="text"
name="email" name="email"
[disabled]="isLoggedIn" [disabled]="isLoggedIn"
@@ -34,7 +34,7 @@
<div class="row justify-content-center mb-4"> <div class="row justify-content-center mb-4">
<div class="col-4"> <div class="col-4">
<div class="form-group" data-mdb-input-init> <div class="form-group" data-mdb-input-init>
<label class="form-label">Password</label> <p class="form-label">Password</p>
<input type="password" <input type="password"
name="password" name="password"
[disabled]="isLoggedIn" [disabled]="isLoggedIn"

View File

@@ -36,7 +36,7 @@ export class LoginComponent implements OnInit {
public attemptLogin() { public attemptLogin() {
this.authService.authenticate(this.email, this.password) this.authService.authenticate(this.email, this.password)
.subscribe(token => { .subscribe(() => {
this.router.navigate(['/']).then(); this.router.navigate(['/']).then();
}); });
} }