diff --git a/frontend/public/coinflip.png b/frontend/public/coinflip.png new file mode 100644 index 0000000..0f39ca8 Binary files /dev/null and b/frontend/public/coinflip.png differ diff --git a/frontend/public/poker.webp b/frontend/public/poker.webp deleted file mode 100644 index 329f4da..0000000 Binary files a/frontend/public/poker.webp and /dev/null differ diff --git a/frontend/src/app/feature/game/coinflip/coinflip.component.html b/frontend/src/app/feature/game/coinflip/coinflip.component.html index 4501de1..671bc31 100644 --- a/frontend/src/app/feature/game/coinflip/coinflip.component.html +++ b/frontend/src/app/feature/game/coinflip/coinflip.component.html @@ -102,15 +102,25 @@
- +
+ + Cannot exceed balance +
(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(); diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts index 07b5f9f..9ca6d39 100644 --- a/frontend/src/app/feature/home/home.component.ts +++ b/frontend/src/app/feature/home/home.component.ts @@ -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',