Merge pull request 'feat: add bare slots frontend, remove bun start warnings (CAS-61)' (!164) from slots-frontend into main
All checks were successful
Release / Release (push) Successful in 59s
Release / Build Backend Image (push) Successful in 22s
Release / Build Frontend Image (push) Successful in 26s

Reviewed-on: #164
Reviewed-by: Constantin Simonis <constantin@simonis.lol>
This commit is contained in:
Phan Huy Tran 2025-05-07 12:32:52 +00:00
commit 1a42057962
No known key found for this signature in database
GPG key ID: 944223E4D46B7412
8 changed files with 111 additions and 11 deletions

View file

@ -21,4 +21,9 @@ export const routes: Routes = [
loadComponent: () => import('./feature/game/blackjack/blackjack.component'), loadComponent: () => import('./feature/game/blackjack/blackjack.component'),
canActivate: [authGuard], canActivate: [authGuard],
}, },
{
path: 'game/slots',
loadComponent: () => import('./feature/game/slots/slots.component'),
canActivate: [authGuard],
},
]; ];

View file

@ -1,7 +1,6 @@
import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { PlayingCardComponent } from './components/playing-card/playing-card.component';
import { DealerHandComponent } from './components/dealer-hand/dealer-hand.component'; import { DealerHandComponent } from './components/dealer-hand/dealer-hand.component';
import { PlayerHandComponent } from './components/player-hand/player-hand.component'; import { PlayerHandComponent } from './components/player-hand/player-hand.component';
import { GameControlsComponent } from './components/game-controls/game-controls.component'; import { GameControlsComponent } from './components/game-controls/game-controls.component';
@ -22,7 +21,6 @@ import { DebtDialogComponent } from '@shared/components/debt-dialog/debt-dialog.
imports: [ imports: [
CommonModule, CommonModule,
NavbarComponent, NavbarComponent,
PlayingCardComponent,
DealerHandComponent, DealerHandComponent,
PlayerHandComponent, PlayerHandComponent,
GameControlsComponent, GameControlsComponent,

View file

@ -8,13 +8,13 @@ import {
SimpleChanges, SimpleChanges,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { CommonModule, CurrencyPipe } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CountUp } from 'countup.js'; import { CountUp } from 'countup.js';
@Component({ @Component({
selector: 'app-animated-number', selector: 'app-animated-number',
standalone: true, standalone: true,
imports: [CommonModule, CurrencyPipe], imports: [CommonModule],
template: ` <span #numberElement>{{ formattedValue }}</span> `, template: ` <span #numberElement>{{ formattedValue }}</span> `,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })

View file

@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule, CurrencyPipe } from '@angular/common'; import { CommonModule } from '@angular/common';
import { animate, style, transition, trigger } from '@angular/animations'; import { animate, style, transition, trigger } from '@angular/animations';
import { GameState } from '../../enum/gameState'; import { GameState } from '../../enum/gameState';
import { AnimatedNumberComponent } from '../animated-number/animated-number.component'; import { AnimatedNumberComponent } from '../animated-number/animated-number.component';
@ -7,7 +7,7 @@ import { AnimatedNumberComponent } from '../animated-number/animated-number.comp
@Component({ @Component({
selector: 'app-game-result', selector: 'app-game-result',
standalone: true, standalone: true,
imports: [CommonModule, CurrencyPipe, AnimatedNumberComponent], imports: [CommonModule, AnimatedNumberComponent],
template: ` template: `
<div *ngIf="visible" [@fadeInOut] class="modal-bg" style="z-index: 1000; position: fixed;"> <div *ngIf="visible" [@fadeInOut] class="modal-bg" style="z-index: 1000; position: fixed;">
<div class="modal-card" [@cardAnimation]> <div class="modal-card" [@cardAnimation]>

View file

@ -0,0 +1,50 @@
<app-navbar></app-navbar>
<div>
<h2>Payouts</h2>
@if (slotInfo(); as info) {
<table>
<tbody>
@for (item of info | keyvalue; track item.key) {
<tr>
<td>{{ item.key }}</td>
<td>{{ item.value }}</td>
</tr>
}
</tbody>
</table>
}
<div>
<div class="grid grid-cols-3 gap-1">
@for (row of slotResult().resultMatrix; track $index) {
@for (cell of row; track $index) {
<div class="text-center">{{ cell }}</div>
}
}
</div>
<div>
<p>
Game result: <strong>{{ slotResult().status | uppercase }}</strong>
</p>
<p>
Amount: <strong>{{ slotResult().amount }}</strong>
</p>
</div>
<div>
<label for="betAmount">Bet Amount: </label>
<input
id="betAmount"
type="number"
[ngModel]="betAmount()"
(ngModelChange)="betAmount.set($event)"
step="0.01"
min="0.01"
/>
</div>
<button (click)="spin()">SPIN</button>
</div>
</div>

View file

@ -0,0 +1,49 @@
import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';
import { NavbarComponent } from '@shared/components/navbar/navbar.component';
import { HttpClient } from '@angular/common/http';
import { KeyValuePipe, NgClass, UpperCasePipe } from '@angular/common';
import { FormsModule } from '@angular/forms';
interface SlotResult {
status: 'win' | 'lose' | 'blank' | 'start';
amount: number;
resultMatrix: string[][];
}
@Component({
selector: 'app-slots',
standalone: true,
imports: [NavbarComponent, KeyValuePipe, UpperCasePipe, NgClass, FormsModule],
templateUrl: './slots.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class SlotsComponent implements OnInit {
private httpClient: HttpClient = inject(HttpClient);
slotInfo = signal<Record<string, number> | null>(null);
slotResult = signal<SlotResult>({
status: 'start',
amount: 0,
resultMatrix: [
['BAR', 'BAR', 'BAR'],
['SEVEN', 'SEVEN', 'SEVEN'],
['BELL', 'BELL', 'BELL'],
],
});
betAmount = signal<number>(1);
ngOnInit(): void {
this.httpClient.get<Record<string, number>>('/backend/slots/info').subscribe((data) => {
this.slotInfo.set(data);
});
}
spin(): void {
const payload = {
betAmount: this.betAmount(),
};
this.httpClient.post<SlotResult>('/backend/slots/spin', payload).subscribe((result) => {
this.slotResult.set(result);
});
}
}

View file

@ -8,8 +8,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { TransactionService } from '@service/transaction.service'; import { TransactionService } from '@service/transaction.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AsyncPipe, CurrencyPipe, DatePipe, NgForOf, NgIf } from '@angular/common'; import { AsyncPipe, CurrencyPipe, DatePipe, NgIf } from '@angular/common';
import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component';
import { TransactionData } from '../../model/TransactionData'; import { TransactionData } from '../../model/TransactionData';
const PER_PAGE = 5; const PER_PAGE = 5;
@ -17,7 +16,7 @@ const PER_PAGE = 5;
@Component({ @Component({
standalone: true, standalone: true,
selector: 'app-transaction-history', selector: 'app-transaction-history',
imports: [NgForOf, AsyncPipe, CurrencyPipe, DatePipe, AnimatedNumberComponent, NgIf], imports: [AsyncPipe, CurrencyPipe, DatePipe, NgIf],
templateUrl: './transaction-history.component.html', templateUrl: './transaction-history.component.html',
styleUrl: './transaction-history.component.css', styleUrl: './transaction-history.component.css',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,

View file

@ -8,7 +8,6 @@ import {
} from '@angular/core'; } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { AuthService } from '../../../service/auth.service'; import { AuthService } from '../../../service/auth.service';
import { CurrencyPipe } from '@angular/common';
import { UserService } from '@service/user.service'; import { UserService } from '@service/user.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component';
@ -17,7 +16,7 @@ import { AnimatedNumberComponent } from '@blackjack/components/animated-number/a
selector: 'app-navbar', selector: 'app-navbar',
templateUrl: './navbar.component.html', templateUrl: './navbar.component.html',
standalone: true, standalone: true,
imports: [RouterModule, CurrencyPipe, AnimatedNumberComponent], imports: [RouterModule, AnimatedNumberComponent],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class NavbarComponent implements OnInit, OnDestroy { export class NavbarComponent implements OnInit, OnDestroy {