fix: Make user not able to enter too much money
Some checks failed
CI / Get Changed Files (pull_request) Successful in 8s
CI / Checkstyle Main (pull_request) Has been skipped
CI / Docker backend validation (pull_request) Has been skipped
CI / oxlint (pull_request) Successful in 21s
CI / eslint (pull_request) Successful in 27s
CI / prettier (pull_request) Failing after 31s
CI / Docker frontend validation (pull_request) Successful in 54s
CI / test-build (pull_request) Successful in 50s

This commit is contained in:
Jan K9f 2025-05-21 10:58:35 +02:00
commit 8b6e026e0a
5 changed files with 79 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

View file

@ -102,15 +102,25 @@
<!-- Custom bet input --> <!-- Custom bet input -->
<div class="space-y-1"> <div class="space-y-1">
<div class="flex justify-between">
<label for="bet" class="text-sm text-text-secondary">Bet Amount</label> <label for="bet" class="text-sm text-text-secondary">Bet Amount</label>
<span *ngIf="isInvalidBet()" class="text-xs text-accent-red animate-pulse"
>Cannot exceed balance</span
>
</div>
<input <input
type="number" type="number"
id="bet" id="bet"
class="w-full px-3 py-2 bg-deep-blue-light text-white rounded focus:outline-none focus:ring-2 focus:ring-emerald disabled:opacity-50" class="w-full px-3 py-2 bg-deep-blue-light text-white rounded focus:outline-none focus:ring-2 disabled:opacity-50"
[ngClass]="{
'ring-accent-red': isInvalidBet(),
'ring-emerald': !isInvalidBet(),
}"
[min]="1" [min]="1"
[max]="balance()" [max]="balance()"
[ngModel]="betInputValue()" [ngModel]="betInputValue()"
(input)="updateBet($event)" (input)="updateBet($event)"
(keydown)="validateBetInput($event)"
step="1" step="1"
[disabled]="gameInProgress()" [disabled]="gameInProgress()"
[placeholder]="balance() | currency: 'EUR'" [placeholder]="balance() | currency: 'EUR'"

View file

@ -1,4 +1,4 @@
import { CurrencyPipe } from '@angular/common'; import { NgClass, NgIf, CurrencyPipe, CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { import {
@ -20,7 +20,14 @@ import { CoinflipGame, CoinflipRequest } from './models/coinflip.model';
@Component({ @Component({
selector: 'app-coinflip', selector: 'app-coinflip',
standalone: true, standalone: true,
imports: [AnimatedNumberComponent, CurrencyPipe, FormsModule], imports: [
AnimatedNumberComponent,
CurrencyPipe,
FormsModule,
CommonModule,
NgIf,
NgClass
],
templateUrl: './coinflip.component.html', templateUrl: './coinflip.component.html',
styleUrl: './coinflip.component.css', styleUrl: './coinflip.component.css',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -33,6 +40,7 @@ export default class CoinflipComponent implements OnInit {
gameResult = signal<CoinflipGame | null>(null); gameResult = signal<CoinflipGame | null>(null);
betInputValue = signal(10); betInputValue = signal(10);
errorMessage = signal(''); errorMessage = signal('');
isInvalidBet = signal(false);
@ViewChild('coinElement') coinElement?: ElementRef; @ViewChild('coinElement') coinElement?: ElementRef;
@ -62,19 +70,31 @@ export default class CoinflipComponent implements OnInit {
updateBet(event: Event) { updateBet(event: Event) {
const inputElement = event.target as HTMLInputElement; const inputElement = event.target as HTMLInputElement;
const value = Number(inputElement.value); let value = Number(inputElement.value);
// Reset invalid bet state
this.isInvalidBet.set(false);
// Enforce minimum bet of 1
if (value <= 0) { if (value <= 0) {
this.betInputValue.set(1); value = 1;
this.currentBet.set(1); }
} else if (value > this.balance()) {
this.betInputValue.set(this.balance()); // Cap bet at available balance and show feedback
this.currentBet.set(this.balance()); if (value > this.balance()) {
} else { value = this.balance();
// Show visual feedback
this.isInvalidBet.set(true);
// Indicate the error briefly
setTimeout(() => this.isInvalidBet.set(false), 800);
// Update the input field directly to show the user the max value
inputElement.value = String(value);
}
// Update signals
this.betInputValue.set(value); this.betInputValue.set(value);
this.currentBet.set(value); this.currentBet.set(value);
} }
}
betHeads() { betHeads() {
this.placeBet('HEAD'); this.placeBet('HEAD');
@ -191,6 +211,38 @@ export default class CoinflipComponent implements OnInit {
console.log(`Animation applied for result: ${result}`); console.log(`Animation applied for result: ${result}`);
} }
/**
* Validates input as the user types to prevent invalid values
*/
validateBetInput(event: KeyboardEvent) {
// Allow navigation keys (arrows, delete, backspace, tab)
const navigationKeys = ['ArrowLeft', 'ArrowRight', 'Delete', 'Backspace', 'Tab'];
if (navigationKeys.includes(event.key)) {
return;
}
// Only allow numbers
if (!/^\d$/.test(event.key)) {
event.preventDefault();
return;
}
// Get the value that would result after the keypress
const input = event.target as HTMLInputElement;
const currentValue = input.value;
const cursorPosition = input.selectionStart || 0;
const newValue = currentValue.substring(0, cursorPosition) + event.key + currentValue.substring(input.selectionEnd || cursorPosition);
const numValue = Number(newValue);
// Prevent values greater than balance
if (numValue > this.balance()) {
event.preventDefault();
}
}
// We removed the paste handler for simplicity since the updateBet method
// will handle any value that gets into the input field
getResultClass() { getResultClass() {
if (!this.gameResult()) return ''; if (!this.gameResult()) return '';
const result = this.gameResult(); const result = this.gameResult();

View file

@ -48,9 +48,9 @@ export default class HomeComponent implements OnInit {
featuredGames: Game[] = [ featuredGames: Game[] = [
{ {
id: '1', id: '1',
name: 'Poker', name: 'Coinflip',
image: '/poker.webp', image: '/coinflip.png',
route: '/game/poker', route: '/game/coinflip',
}, },
{ {
id: '2', id: '2',