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
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:
parent
0d9b0ad987
commit
8b6e026e0a
5 changed files with 79 additions and 17 deletions
BIN
frontend/public/coinflip.png
Normal file
BIN
frontend/public/coinflip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
Binary file not shown.
Before Width: | Height: | Size: 60 KiB |
|
@ -102,15 +102,25 @@
|
|||
|
||||
<!-- Custom bet input -->
|
||||
<div class="space-y-1">
|
||||
<label for="bet" class="text-sm text-text-secondary">Bet Amount</label>
|
||||
<div class="flex justify-between">
|
||||
<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
|
||||
type="number"
|
||||
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"
|
||||
[max]="balance()"
|
||||
[ngModel]="betInputValue()"
|
||||
(input)="updateBet($event)"
|
||||
(keydown)="validateBetInput($event)"
|
||||
step="1"
|
||||
[disabled]="gameInProgress()"
|
||||
[placeholder]="balance() | currency: 'EUR'"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { CurrencyPipe } from '@angular/common';
|
||||
import { NgClass, NgIf, CurrencyPipe, CommonModule } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import {
|
||||
|
@ -20,7 +20,14 @@ import { CoinflipGame, CoinflipRequest } from './models/coinflip.model';
|
|||
@Component({
|
||||
selector: 'app-coinflip',
|
||||
standalone: true,
|
||||
imports: [AnimatedNumberComponent, CurrencyPipe, FormsModule],
|
||||
imports: [
|
||||
AnimatedNumberComponent,
|
||||
CurrencyPipe,
|
||||
FormsModule,
|
||||
CommonModule,
|
||||
NgIf,
|
||||
NgClass
|
||||
],
|
||||
templateUrl: './coinflip.component.html',
|
||||
styleUrl: './coinflip.component.css',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
|
@ -33,6 +40,7 @@ export default class CoinflipComponent implements OnInit {
|
|||
gameResult = signal<CoinflipGame | null>(null);
|
||||
betInputValue = signal(10);
|
||||
errorMessage = signal('');
|
||||
isInvalidBet = signal(false);
|
||||
|
||||
@ViewChild('coinElement') coinElement?: ElementRef;
|
||||
|
||||
|
@ -62,18 +70,30 @@ export default class CoinflipComponent implements OnInit {
|
|||
|
||||
updateBet(event: Event) {
|
||||
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) {
|
||||
this.betInputValue.set(1);
|
||||
this.currentBet.set(1);
|
||||
} else if (value > this.balance()) {
|
||||
this.betInputValue.set(this.balance());
|
||||
this.currentBet.set(this.balance());
|
||||
} else {
|
||||
this.betInputValue.set(value);
|
||||
this.currentBet.set(value);
|
||||
value = 1;
|
||||
}
|
||||
|
||||
// Cap bet at available balance and show feedback
|
||||
if (value > this.balance()) {
|
||||
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.currentBet.set(value);
|
||||
}
|
||||
|
||||
betHeads() {
|
||||
|
@ -191,6 +211,38 @@ export default class CoinflipComponent implements OnInit {
|
|||
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() {
|
||||
if (!this.gameResult()) return '';
|
||||
const result = this.gameResult();
|
||||
|
|
|
@ -48,9 +48,9 @@ export default class HomeComponent implements OnInit {
|
|||
featuredGames: Game[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Poker',
|
||||
image: '/poker.webp',
|
||||
route: '/game/poker',
|
||||
name: 'Coinflip',
|
||||
image: '/coinflip.png',
|
||||
route: '/game/coinflip',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
|
|
Reference in a new issue