feat(blackjack): refresh user balance on game state change
This commit is contained in:
parent
08b12d238e
commit
e983b21e07
7 changed files with 48 additions and 19 deletions
|
@ -82,8 +82,7 @@ export default class BlackjackComponent {
|
||||||
|
|
||||||
if (isGameOver) {
|
if (isGameOver) {
|
||||||
console.log('Game is over, state:', game.state);
|
console.log('Game is over, state:', game.state);
|
||||||
this.refreshUserBalance();
|
this.userService.refreshCurrentUser();
|
||||||
|
|
||||||
this.showGameResult.set(true);
|
this.showGameResult.set(true);
|
||||||
console.log('Game result dialog should be shown now');
|
console.log('Game result dialog should be shown now');
|
||||||
}
|
}
|
||||||
|
@ -96,7 +95,7 @@ export default class BlackjackComponent {
|
||||||
this.blackjackService.startGame(bet).subscribe({
|
this.blackjackService.startGame(bet).subscribe({
|
||||||
next: (game) => {
|
next: (game) => {
|
||||||
this.updateGameState(game);
|
this.updateGameState(game);
|
||||||
this.refreshUserBalance();
|
this.userService.refreshCurrentUser();
|
||||||
this.isActionInProgress.set(false);
|
this.isActionInProgress.set(false);
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
|
@ -115,6 +114,9 @@ export default class BlackjackComponent {
|
||||||
this.blackjackService.hit(this.currentGameId()!).subscribe({
|
this.blackjackService.hit(this.currentGameId()!).subscribe({
|
||||||
next: (game) => {
|
next: (game) => {
|
||||||
this.updateGameState(game);
|
this.updateGameState(game);
|
||||||
|
if (game.state !== 'IN_PROGRESS') {
|
||||||
|
this.userService.refreshCurrentUser();
|
||||||
|
}
|
||||||
this.isActionInProgress.set(false);
|
this.isActionInProgress.set(false);
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
|
@ -139,6 +141,7 @@ export default class BlackjackComponent {
|
||||||
this.blackjackService.stand(this.currentGameId()!).subscribe({
|
this.blackjackService.stand(this.currentGameId()!).subscribe({
|
||||||
next: (game) => {
|
next: (game) => {
|
||||||
this.updateGameState(game);
|
this.updateGameState(game);
|
||||||
|
this.userService.refreshCurrentUser();
|
||||||
this.isActionInProgress.set(false);
|
this.isActionInProgress.set(false);
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
|
@ -163,6 +166,7 @@ export default class BlackjackComponent {
|
||||||
this.blackjackService.doubleDown(this.currentGameId()!).subscribe({
|
this.blackjackService.doubleDown(this.currentGameId()!).subscribe({
|
||||||
next: (game) => {
|
next: (game) => {
|
||||||
this.updateGameState(game);
|
this.updateGameState(game);
|
||||||
|
this.userService.refreshCurrentUser();
|
||||||
this.isActionInProgress.set(false);
|
this.isActionInProgress.set(false);
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
|
|
|
@ -18,10 +18,6 @@ import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angula
|
||||||
<div class="card p-4">
|
<div class="card p-4">
|
||||||
<h3 class="section-heading text-xl mb-4">Spiel Informationen</h3>
|
<h3 class="section-heading text-xl mb-4">Spiel Informationen</h3>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="flex justify-between items-center">
|
|
||||||
<span class="text-text-secondary">Guthaben:</span>
|
|
||||||
<span class="text-emerald">{{ balance | currency: 'EUR' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-text-secondary">Aktuelle Wette:</span>
|
<span class="text-text-secondary">Aktuelle Wette:</span>
|
||||||
<span [class]="currentBet > 0 ? 'text-accent-red' : 'text-text-secondary'">
|
<span [class]="currentBet > 0 ? 'text-accent-red' : 'text-text-secondary'">
|
||||||
|
|
|
@ -86,7 +86,7 @@ export class GameResultComponent {
|
||||||
visible = false;
|
visible = false;
|
||||||
|
|
||||||
get isWin(): boolean {
|
get isWin(): boolean {
|
||||||
return this.gameState === GameState.PLAYER_WON;
|
return this.gameState === GameState.PLAYER_WON || this.gameState === GameState.PLAYER_BLACKJACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLoss(): boolean {
|
get isLoss(): boolean {
|
||||||
|
@ -98,6 +98,7 @@ export class GameResultComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getResultTitle(): string {
|
getResultTitle(): string {
|
||||||
|
if (this.gameState === GameState.PLAYER_BLACKJACK) return 'Blackjack!';
|
||||||
if (this.isWin) return 'Gewonnen!';
|
if (this.isWin) return 'Gewonnen!';
|
||||||
if (this.isLoss) return 'Verloren!';
|
if (this.isLoss) return 'Verloren!';
|
||||||
if (this.isDraw) return 'Unentschieden!';
|
if (this.isDraw) return 'Unentschieden!';
|
||||||
|
@ -105,6 +106,7 @@ export class GameResultComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getResultMessage(): string {
|
getResultMessage(): string {
|
||||||
|
if (this.gameState === GameState.PLAYER_BLACKJACK) return 'Glückwunsch! Du hast mit einem Blackjack gewonnen!';
|
||||||
if (this.isWin) return 'Glückwunsch! Du hast diese Runde gewonnen.';
|
if (this.isWin) return 'Glückwunsch! Du hast diese Runde gewonnen.';
|
||||||
if (this.isLoss) return 'Schade! Du hast diese Runde verloren.';
|
if (this.isLoss) return 'Schade! Du hast diese Runde verloren.';
|
||||||
if (this.isDraw) return 'Diese Runde endet unentschieden. Dein Einsatz wurde zurückgegeben.';
|
if (this.isDraw) return 'Diese Runde endet unentschieden. Dein Einsatz wurde zurückgegeben.';
|
||||||
|
@ -112,6 +114,7 @@ export class GameResultComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getResultClass(): string {
|
getResultClass(): string {
|
||||||
|
if (this.gameState === GameState.PLAYER_BLACKJACK) return 'text-emerald font-bold';
|
||||||
if (this.isWin) return 'text-emerald';
|
if (this.isWin) return 'text-emerald';
|
||||||
if (this.isLoss) return 'text-accent-red';
|
if (this.isLoss) return 'text-accent-red';
|
||||||
if (this.isDraw) return 'text-yellow-400';
|
if (this.isDraw) return 'text-yellow-400';
|
||||||
|
|
|
@ -3,4 +3,5 @@ export enum GameState {
|
||||||
IN_PROGRESS = 'IN_PROGRESS',
|
IN_PROGRESS = 'IN_PROGRESS',
|
||||||
PLAYER_LOST = 'PLAYER_LOST',
|
PLAYER_LOST = 'PLAYER_LOST',
|
||||||
DRAW = 'DRAW',
|
DRAW = 'DRAW',
|
||||||
|
PLAYER_BLACKJACK = 'PLAYER_BLACKJACK',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { KeycloakProfile } from 'keycloak-js';
|
import { KeycloakProfile } from 'keycloak-js';
|
||||||
import { catchError, EMPTY, Observable } from 'rxjs';
|
import { BehaviorSubject, catchError, EMPTY, Observable, tap } from 'rxjs';
|
||||||
import { User } from '../model/User';
|
import { User } from '../model/User';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -9,20 +9,39 @@ import { User } from '../model/User';
|
||||||
})
|
})
|
||||||
export class UserService {
|
export class UserService {
|
||||||
private http: HttpClient = inject(HttpClient);
|
private http: HttpClient = inject(HttpClient);
|
||||||
|
private currentUserSubject = new BehaviorSubject<User | null>(null);
|
||||||
|
public currentUser$ = this.currentUserSubject.asObservable();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Initialize with current user data
|
||||||
|
this.getCurrentUser().subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
public getUser(id: string): Observable<User | null> {
|
public getUser(id: string): Observable<User | null> {
|
||||||
return this.http.get<User | null>(`/backend/user/${id}`).pipe(catchError(() => EMPTY));
|
return this.http.get<User | null>(`/backend/user/${id}`).pipe(
|
||||||
|
catchError(() => EMPTY),
|
||||||
|
tap(user => this.currentUserSubject.next(user))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCurrentUser(): Observable<User | null> {
|
public getCurrentUser(): Observable<User | null> {
|
||||||
return this.http.get<User | null>('/backend/user').pipe(catchError(() => EMPTY));
|
return this.http.get<User | null>('/backend/user').pipe(
|
||||||
|
catchError(() => EMPTY),
|
||||||
|
tap(user => this.currentUserSubject.next(user))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public refreshCurrentUser(): void {
|
||||||
|
this.getCurrentUser().subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public createUser(id: string, username: string): Observable<User> {
|
public createUser(id: string, username: string): Observable<User> {
|
||||||
return this.http.post<User>('/backend/user', {
|
return this.http.post<User>('/backend/user', {
|
||||||
keycloakId: id,
|
keycloakId: id,
|
||||||
username: username,
|
username: username,
|
||||||
});
|
}).pipe(
|
||||||
|
tap(user => this.currentUserSubject.next(user))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getOrCreateUser(userProfile: KeycloakProfile) {
|
public async getOrCreateUser(userProfile: KeycloakProfile) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<div
|
<div
|
||||||
class="text-white font-bold bg-deep-blue-contrast rounded-full px-4 py-2 text-sm hover:bg-deep-blue-contrast/80 hover:cursor-pointer hover:scale-105 transition-all active:scale-95 select-none duration-300"
|
class="text-white font-bold bg-deep-blue-contrast rounded-full px-4 py-2 text-sm hover:bg-deep-blue-contrast/80 hover:cursor-pointer hover:scale-105 transition-all active:scale-95 select-none duration-300"
|
||||||
>
|
>
|
||||||
<span>Guthaben: {{ balance() | currency: 'EUR' : 'symbol' : '1.2-2' }}</span>
|
<span>{{ balance() | currency: 'EUR' : 'symbol' : '1.2-2' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="logout()" class="button-primary px-4 py-1.5">Abmelden</button>
|
<button (click)="logout()" class="button-primary px-4 py-1.5">Abmelden</button>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, inject, OnInit, OnDestroy, signal } from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { KeycloakService } from 'keycloak-angular';
|
import { KeycloakService } from 'keycloak-angular';
|
||||||
|
|
||||||
import { CurrencyPipe } from '@angular/common';
|
import { CurrencyPipe } from '@angular/common';
|
||||||
import { UserService } from '@service/user.service';
|
import { UserService } from '@service/user.service';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-navbar',
|
selector: 'app-navbar',
|
||||||
templateUrl: './navbar.component.html',
|
templateUrl: './navbar.component.html',
|
||||||
|
@ -11,22 +12,27 @@ import { UserService } from '@service/user.service';
|
||||||
imports: [RouterModule, CurrencyPipe],
|
imports: [RouterModule, CurrencyPipe],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class NavbarComponent implements OnInit {
|
export class NavbarComponent implements OnInit, OnDestroy {
|
||||||
isMenuOpen = false;
|
isMenuOpen = false;
|
||||||
private keycloakService: KeycloakService = inject(KeycloakService);
|
private keycloakService: KeycloakService = inject(KeycloakService);
|
||||||
isLoggedIn = this.keycloakService.isLoggedIn();
|
isLoggedIn = this.keycloakService.isLoggedIn();
|
||||||
|
|
||||||
private userService = inject(UserService);
|
private userService = inject(UserService);
|
||||||
private user = this.userService.getCurrentUser();
|
private userSubscription: Subscription | undefined;
|
||||||
|
|
||||||
public balance = signal(0);
|
public balance = signal(0);
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.user.subscribe((user) => {
|
this.userSubscription = this.userService.currentUser$.subscribe((user) => {
|
||||||
this.balance.set(user?.balance ?? 0);
|
this.balance.set(user?.balance ?? 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.userSubscription) {
|
||||||
|
this.userSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
login() {
|
login() {
|
||||||
try {
|
try {
|
||||||
const baseUrl = window.location.origin;
|
const baseUrl = window.location.origin;
|
||||||
|
|
Reference in a new issue