fix: delayed displaying of messages, transactions using signals

This commit is contained in:
eneller
2026-07-23 15:17:29 +02:00
parent 0f4474d29b
commit c282e275ef
6 changed files with 23 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, signal } from '@angular/core'; import { Component, inject, OnInit, signal } from '@angular/core';
import { RouterOutlet, RouterLinkWithHref, Router, NavigationEnd } from '@angular/router'; import { RouterOutlet, RouterLinkWithHref, Router, NavigationEnd } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { import {
@@ -8,6 +8,7 @@ import {
NgbNavLinkBase, NgbNavLinkBase,
} from '@ng-bootstrap/ng-bootstrap/nav'; } from '@ng-bootstrap/ng-bootstrap/nav';
import { filter } from 'rxjs'; import { filter } from 'rxjs';
import { APIService } from './services/api';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@@ -17,6 +18,7 @@ import { filter } from 'rxjs';
}) })
export class App implements OnInit{ export class App implements OnInit{
protected readonly title = signal('client'); protected readonly title = signal('client');
protected api = inject(APIService);
active = '/'; active = '/';
constructor( constructor(
@@ -24,6 +26,7 @@ export class App implements OnInit{
){} ){}
ngOnInit(): void { ngOnInit(): void {
this.api.checkAuthStatus().subscribe();
this.router.events this.router.events
.pipe(filter(event => event instanceof NavigationEnd)) .pipe(filter(event => event instanceof NavigationEnd))
.subscribe(() =>{ .subscribe(() =>{

View File

@@ -48,7 +48,7 @@
type="submit" type="submit"
class="btn btn-primary w-100 mb-3" class="btn btn-primary w-100 mb-3"
> >
@if (loading) { @if (loading()) {
<span> Signing In... </span> <span> Signing In... </span>
}@else { }@else {
<span>Sign In</span> <span>Sign In</span>
@@ -57,13 +57,13 @@
<!-- Error Alert --> <!-- Error Alert -->
@if (error) { @if (error()) {
<ngb-alert <ngb-alert
type="danger" type="danger"
(closed)="error = null" (closed)="error.set(null)"
[dismissible]="true" [dismissible]="true"
> >
{{ error }} {{ error() }}
</ngb-alert> </ngb-alert>
} }
</form> </form>

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component } from '@angular/core'; import { Component, signal } from '@angular/core';
import { Validators, FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Form } from '@angular/forms'; import { Validators, FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Form } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@@ -15,9 +15,9 @@ import { GenericMessage } from '@message/Message';
export class ScreenLogin { export class ScreenLogin {
loginForm: FormGroup; loginForm: FormGroup;
submitted = false; submitted = false;
loading = false; loading = signal(false);
showPassword = false; showPassword = false;
error: string | null = null; error = signal<string|null>(null);
constructor( constructor(
private api: APIService, private api: APIService,
@@ -33,8 +33,8 @@ export class ScreenLogin {
onSubmit() { onSubmit() {
this.submitted = true; this.submitted = true;
this.error = null; this.error.set(null);
this.loading = true; this.loading.set(true)
this.api.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({ this.api.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({
next: () => { next: () => {
@@ -42,10 +42,9 @@ export class ScreenLogin {
this.router.navigateByUrl(returnUrl); this.router.navigateByUrl(returnUrl);
}, },
error: (resp) => { error: (resp) => {
//FIXME error message displaying delayed, display message from server response
let msg: GenericMessage = resp.error; let msg: GenericMessage = resp.error;
this.error = msg.message || 'Login failed. Please try again.'; this.error.set(msg.message || 'Login failed. Please try again.');
this.loading = false; this.loading.set(false);
} }
}); });
} }

View File

@@ -23,7 +23,7 @@
<div class="card-body p-0"> <div class="card-body p-0">
<div class="list-group list-group-flush"> <div class="list-group list-group-flush">
<!-- Transaction Item --> <!-- Transaction Item -->
@for (transaction of transactions; track $index) { @for (transaction of transactions(); track $index) {
<div class="list-group-item"> <div class="list-group-item">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
@@ -53,6 +53,7 @@
</div> </div>
</div> </div>
} }
@empty {<p class="text-muted">No transactions yet</p>}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common'; import { CommonModule, CurrencyPipe, DatePipe } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit, signal } from '@angular/core';
import { APIService } from '../../services/api'; import { APIService } from '../../services/api';
import Transaction from '@model/transaction'; import Transaction from '@model/transaction';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@@ -14,7 +14,7 @@ export class ScreenProfile implements OnInit{
// TODO display real data // TODO display real data
username = 'John Doe'; username = 'John Doe';
balance = 200; balance = 200;
transactions!: Transaction[]; transactions = signal<Transaction[]>([])
constructor( constructor(
protected api: APIService, protected api: APIService,
@@ -22,10 +22,9 @@ export class ScreenProfile implements OnInit{
){} ){}
ngOnInit(): void { ngOnInit(): void {
// FIXME transactions displaying delayed (only on second nav click)
this.api.getTransactions().subscribe({ this.api.getTransactions().subscribe({
next: (transactions) => { next: (transactions) => {
this.transactions = transactions; this.transactions.set(transactions);
}, },
error: (err) => { error: (err) => {
console.error('Error fetching transactions:', err); console.error('Error fetching transactions:', err);

View File

@@ -1,13 +1,14 @@
import { inject } from '@angular/core'; import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router'; import { CanActivateFn, Router } from '@angular/router';
import { APIService } from './api'; import { APIService } from './api';
import { map } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
export const authGuard: CanActivateFn = (route, state) => { export const authGuard: CanActivateFn = (route, state) => {
const api = inject(APIService); const api = inject(APIService);
const router = inject(Router); const router = inject(Router);
return api.checkAuthStatus().pipe( return api.isAuthenticated$.pipe(
take(1),
map((isAuthenticated) => { map((isAuthenticated) => {
if (isAuthenticated) { if (isAuthenticated) {
return true; return true;