feat(lootboxes): add balance check for opening lootboxes
Some checks failed
CI / Docker backend validation (pull_request) Successful in 11s
CI / Get Changed Files (pull_request) Successful in 36s
CI / Docker frontend validation (pull_request) Successful in 42s
CI / Checkstyle Main (pull_request) Has been skipped
CI / oxlint (pull_request) Successful in 30s
CI / prettier (pull_request) Failing after 30s
CI / eslint (pull_request) Successful in 38s
CI / test-build (pull_request) Successful in 33s
Some checks failed
CI / Docker backend validation (pull_request) Successful in 11s
CI / Get Changed Files (pull_request) Successful in 36s
CI / Docker frontend validation (pull_request) Successful in 42s
CI / Checkstyle Main (pull_request) Has been skipped
CI / oxlint (pull_request) Successful in 30s
CI / prettier (pull_request) Failing after 30s
CI / eslint (pull_request) Successful in 38s
CI / test-build (pull_request) Successful in 33s
This commit is contained in:
parent
bca2649afd
commit
790485decc
4 changed files with 78 additions and 8 deletions
|
@ -31,9 +31,15 @@
|
||||||
<div *ngIf="!isOpening && !isOpen" class="mb-6">
|
<div *ngIf="!isOpening && !isOpen" class="mb-6">
|
||||||
<button
|
<button
|
||||||
(click)="openLootbox()"
|
(click)="openLootbox()"
|
||||||
class="button-primary w-full py-3 text-lg font-semibold rounded"
|
[disabled]="!hasEnoughBalance()"
|
||||||
|
[ngClass]="{
|
||||||
|
'button-primary': hasEnoughBalance(),
|
||||||
|
'bg-gray-500 cursor-not-allowed': !hasEnoughBalance()
|
||||||
|
}"
|
||||||
|
class="w-full py-3 text-lg font-semibold rounded"
|
||||||
>
|
>
|
||||||
Öffnen
|
<span *ngIf="hasEnoughBalance()">Öffnen</span>
|
||||||
|
<span *ngIf="!hasEnoughBalance()">Nicht genug Guthaben</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -87,11 +93,16 @@
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
(click)="openAgain()"
|
(click)="openAgain()"
|
||||||
class="button-primary px-6 py-2 font-semibold rounded"
|
[disabled]="!animationCompleted || !hasEnoughBalance()"
|
||||||
[disabled]="!animationCompleted"
|
[ngClass]="{
|
||||||
|
'button-primary': hasEnoughBalance(),
|
||||||
|
'bg-gray-500 cursor-not-allowed': !hasEnoughBalance()
|
||||||
|
}"
|
||||||
|
class="px-6 py-2 font-semibold rounded"
|
||||||
[attr.aria-hidden]="!animationCompleted"
|
[attr.aria-hidden]="!animationCompleted"
|
||||||
>
|
>
|
||||||
Nochmal Öffnen
|
<span *ngIf="hasEnoughBalance()">Nochmal Öffnen</span>
|
||||||
|
<span *ngIf="!hasEnoughBalance()">Nicht genug Guthaben</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
(click)="goBack()"
|
(click)="goBack()"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { LootboxService } from '../services/lootbox.service';
|
||||||
import { LootBox, Reward } from 'app/model/LootBox';
|
import { LootBox, Reward } from 'app/model/LootBox';
|
||||||
import { NavbarComponent } from '@shared/components/navbar/navbar.component';
|
import { NavbarComponent } from '@shared/components/navbar/navbar.component';
|
||||||
import { UserService } from '@service/user.service';
|
import { UserService } from '@service/user.service';
|
||||||
|
import { User } from 'app/model/User';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-lootbox-opening',
|
selector: 'app-lootbox-opening',
|
||||||
|
@ -22,6 +23,7 @@ export default class LootboxOpeningComponent {
|
||||||
wonReward: Reward | null = null;
|
wonReward: Reward | null = null;
|
||||||
prizeList: Reward[] = [];
|
prizeList: Reward[] = [];
|
||||||
animationCompleted = false;
|
animationCompleted = false;
|
||||||
|
currentUser: User | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
@ -31,6 +33,10 @@ export default class LootboxOpeningComponent {
|
||||||
private cdr: ChangeDetectorRef
|
private cdr: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
this.loadLootbox();
|
this.loadLootbox();
|
||||||
|
this.userService.currentUser$.subscribe(user => {
|
||||||
|
this.currentUser = user;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadLootbox(): void {
|
private loadLootbox(): void {
|
||||||
|
@ -59,6 +65,18 @@ export default class LootboxOpeningComponent {
|
||||||
openLootbox(): void {
|
openLootbox(): void {
|
||||||
if (!this.lootbox || this.isOpening) return;
|
if (!this.lootbox || this.isOpening) return;
|
||||||
|
|
||||||
|
// Check if user has enough balance
|
||||||
|
if (!this.hasEnoughBalance()) {
|
||||||
|
this.error = 'Nicht genug Guthaben, um diese Lootbox zu öffnen.';
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.error = '';
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}, 5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.resetState(true);
|
this.resetState(true);
|
||||||
|
|
||||||
if (this.lootbox.price) {
|
if (this.lootbox.price) {
|
||||||
|
@ -186,4 +204,9 @@ export default class LootboxOpeningComponent {
|
||||||
if (!this.wonReward || !this.lootbox) return '';
|
if (!this.wonReward || !this.lootbox) return '';
|
||||||
return this.wonReward.value > (this.lootbox.price || 0) ? 'text-emerald' : 'text-accent-red';
|
return this.wonReward.value > (this.lootbox.price || 0) ? 'text-emerald' : 'text-accent-red';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasEnoughBalance(): boolean {
|
||||||
|
if (!this.currentUser || !this.lootbox) return false;
|
||||||
|
return this.currentUser.balance >= this.lootbox.price;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,15 @@
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<button
|
<button
|
||||||
(click)="openLootbox(lootbox.id)"
|
(click)="openLootbox(lootbox.id)"
|
||||||
class="button-primary w-full py-2 rounded font-semibold"
|
[disabled]="!hasEnoughBalance(lootbox.price)"
|
||||||
|
[ngClass]="{
|
||||||
|
'button-primary': hasEnoughBalance(lootbox.price),
|
||||||
|
'bg-gray-500 cursor-not-allowed': !hasEnoughBalance(lootbox.price)
|
||||||
|
}"
|
||||||
|
class="w-full py-2 rounded font-semibold"
|
||||||
>
|
>
|
||||||
Öffnen
|
<span *ngIf="hasEnoughBalance(lootbox.price)">Öffnen</span>
|
||||||
|
<span *ngIf="!hasEnoughBalance(lootbox.price)">Nicht genug Guthaben</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { LootboxService } from '../services/lootbox.service';
|
||||||
import { LootBox } from 'app/model/LootBox';
|
import { LootBox } from 'app/model/LootBox';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { timeout } from 'rxjs';
|
import { timeout } from 'rxjs';
|
||||||
|
import { UserService } from '@service/user.service';
|
||||||
|
import { User } from 'app/model/User';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-lootbox-selection',
|
selector: 'app-lootbox-selection',
|
||||||
|
@ -17,6 +19,7 @@ export default class LootboxSelectionComponent implements OnInit {
|
||||||
lootboxes: LootBox[] = [];
|
lootboxes: LootBox[] = [];
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
error = '';
|
error = '';
|
||||||
|
currentUser: User | null = null;
|
||||||
|
|
||||||
// Fallback data in case the API call fails
|
// Fallback data in case the API call fails
|
||||||
fallbackLootboxes: LootBox[] = [
|
fallbackLootboxes: LootBox[] = [
|
||||||
|
@ -86,11 +89,16 @@ export default class LootboxSelectionComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private lootboxService: LootboxService,
|
private lootboxService: LootboxService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private cdr: ChangeDetectorRef
|
private cdr: ChangeDetectorRef,
|
||||||
|
private userService: UserService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadLootboxes();
|
this.loadLootboxes();
|
||||||
|
this.userService.currentUser$.subscribe(user => {
|
||||||
|
this.currentUser = user;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLootboxes(): void {
|
loadLootboxes(): void {
|
||||||
|
@ -120,6 +128,24 @@ export default class LootboxSelectionComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
openLootbox(lootboxId: number): void {
|
openLootbox(lootboxId: number): void {
|
||||||
|
const lootbox = this.lootboxes.find(box => box.id === lootboxId);
|
||||||
|
|
||||||
|
if (!lootbox) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.currentUser || this.currentUser.balance < lootbox.price) {
|
||||||
|
this.error = 'Nicht genug Guthaben, um diese Lootbox zu öffnen.';
|
||||||
|
// Scroll to top to see the error message
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.error = '';
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}, 5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.router.navigate(['/game/lootboxes/open', lootboxId]);
|
this.router.navigate(['/game/lootboxes/open', lootboxId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,4 +162,8 @@ export default class LootboxSelectionComponent implements OnInit {
|
||||||
formatProbability(probability: number): string {
|
formatProbability(probability: number): string {
|
||||||
return (probability * 100).toFixed(0) + '%';
|
return (probability * 100).toFixed(0) + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasEnoughBalance(price: number): boolean {
|
||||||
|
return !!this.currentUser && this.currentUser.balance >= price;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue