diff --git a/frontend/src/app/feature/game/slots/slots.component.css b/frontend/src/app/feature/game/slots/slots.component.css new file mode 100644 index 0000000..0df9046 --- /dev/null +++ b/frontend/src/app/feature/game/slots/slots.component.css @@ -0,0 +1,28 @@ +/* Open button styling - Matches lootbox component style */ +.open-btn { + background: linear-gradient(90deg, #4338ca 0%, #8b5cf6 100%); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); + transition: all 0.2s ease; +} +.open-btn:hover { + background: linear-gradient(90deg, #4f46e5 0%, #a78bfa 100%); + transform: translateY(-2px); + box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3); +} + +/* Symbol colors */ +.symbol-BAR { + color: var(--color-accent-yellow); +} +.symbol-SEVEN { + color: var(--color-accent-red); +} +.symbol-BELL { + color: var(--color-accent-purple); +} +.symbol-CHERRY { + color: #ec4899; +} +.symbol-LEMON { + color: #a3e635; +} diff --git a/frontend/src/app/feature/game/slots/slots.component.html b/frontend/src/app/feature/game/slots/slots.component.html index b6d9318..7b0a850 100644 --- a/frontend/src/app/feature/game/slots/slots.component.html +++ b/frontend/src/app/feature/game/slots/slots.component.html @@ -1,50 +1,178 @@ -
-

Payouts

- @if (slotInfo(); as info) { - - - @for (item of info | keyvalue; track item.key) { - - - - - } - -
{{ item.key }}{{ item.value }}
- } +
+

Spielautomaten

-
-
- @for (row of slotResult().resultMatrix; track $index) { - @for (cell of row; track $index) { -
{{ cell }}
- } - } +
+ +
+
+ +
+
+

Slot Machine

+
+ + {{ + slotResult().status === 'win' + ? 'Gewonnen!' + : slotResult().status === 'lose' + ? 'Verloren' + : 'Bereit' + }} + +
+
+
+ + +
+
+
+ @for (row of slotResult().resultMatrix; track $index) { + @for (cell of row; track $index) { +
+ {{ + cell + }} +
+ } + } +
+
+ + +
+
+ +{{ slotResult().amount | currency: 'EUR' }} +
+
+ + +
+
+ + +
+ + +
+
+
-
-

- Game result: {{ slotResult().status | uppercase }} -

-

- Amount: {{ slotResult().amount }} -

-
+ +
+
+

Spiel Informationen

+
+
+ Kontostand: + + + +
+
+ Einsatz: + + + +
-
- - -
+
+ + + + +
- +

Auszahlungen:

+ + @if (slotInfo(); as info) { +
    + @for (item of info | keyvalue; track item.key) { +
  • +
    + {{ item.key }} +
    + {{ item.value }}x +
  • + } +
+ } @else { +
+
+
+ } + +
+

Spielregeln:

+
    +
  • • Gewinne mit 3 gleichen Symbolen
  • +
  • • Höhere Symbole = höhere Gewinne
  • +
+
+
+
+
diff --git a/frontend/src/app/feature/game/slots/slots.component.ts b/frontend/src/app/feature/game/slots/slots.component.ts index ad73a03..80227f5 100644 --- a/frontend/src/app/feature/game/slots/slots.component.ts +++ b/frontend/src/app/feature/game/slots/slots.component.ts @@ -1,8 +1,18 @@ -import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + inject, + OnInit, + OnDestroy, + signal, +} from '@angular/core'; import { NavbarComponent } from '@shared/components/navbar/navbar.component'; import { HttpClient } from '@angular/common/http'; -import { KeyValuePipe, UpperCasePipe } from '@angular/common'; +import { CommonModule, KeyValuePipe, NgClass, CurrencyPipe } from '@angular/common'; import { FormsModule } from '@angular/forms'; +import { UserService } from '@service/user.service'; +import { Subscription } from 'rxjs'; +import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; interface SlotResult { status: 'win' | 'lose' | 'blank' | 'start'; @@ -13,12 +23,24 @@ interface SlotResult { @Component({ selector: 'app-slots', standalone: true, - imports: [NavbarComponent, KeyValuePipe, UpperCasePipe, FormsModule], + imports: [ + CommonModule, + NavbarComponent, + KeyValuePipe, + NgClass, + FormsModule, + CurrencyPipe, + AnimatedNumberComponent, + ], templateUrl: './slots.component.html', + styleUrl: './slots.component.css', changeDetection: ChangeDetectionStrategy.OnPush, }) -export default class SlotsComponent implements OnInit { +export default class SlotsComponent implements OnInit, OnDestroy { private httpClient: HttpClient = inject(HttpClient); + private userService = inject(UserService); + private userSubscription: Subscription | undefined; + slotInfo = signal | null>(null); slotResult = signal({ status: 'start', @@ -29,21 +51,77 @@ export default class SlotsComponent implements OnInit { ['BELL', 'BELL', 'BELL'], ], }); + + balance = signal(0); betAmount = signal(1); + isSpinning = false; ngOnInit(): void { this.httpClient.get>('/backend/slots/info').subscribe((data) => { this.slotInfo.set(data); }); + + this.userSubscription = this.userService.currentUser$.subscribe((user) => { + this.balance.set(user?.balance ?? 0); + }); + + this.userService.refreshCurrentUser(); + } + + ngOnDestroy(): void { + if (this.userSubscription) { + this.userSubscription.unsubscribe(); + } + } + + getSymbolClass(symbol: string): string { + return `symbol-${symbol}`; + } + + hasEnoughBalance(): boolean { + return this.balance() >= this.betAmount(); + } + + setBetAmount(percentage: number): void { + const calculatedBet = Math.floor(this.balance() * percentage * 100) / 100; + const minimumBet = 0.01; + + const newBet = Math.max(minimumBet, Math.min(calculatedBet, this.balance())); + + this.betAmount.set(newBet); } spin(): void { + if (!this.hasEnoughBalance()) { + return; + } + + this.isSpinning = true; + const betAmount = this.betAmount(); + + this.userService.updateLocalBalance(-betAmount); + const payload = { - betAmount: this.betAmount(), + betAmount: betAmount, }; - this.httpClient.post('/backend/slots/spin', payload).subscribe((result) => { - this.slotResult.set(result); + this.httpClient.post('/backend/slots/spin', payload).subscribe({ + next: (result) => { + setTimeout(() => { + this.slotResult.set(result); + + if (result.status === 'win') { + this.userService.updateLocalBalance(result.amount); + } + + this.isSpinning = false; + }, 1500); + }, + error: (err) => { + console.error('Error spinning slot machine:', err); + this.userService.updateLocalBalance(betAmount); + this.isSpinning = false; + }, }); } }