From 3c9d3ea8c0c2e13804af85c3a1fe912b21e7c2f8 Mon Sep 17 00:00:00 2001 From: Jan-Marlon Leibl Date: Wed, 23 Apr 2025 09:47:32 +0200 Subject: [PATCH] feat(lootboxes): add lootbox selection feature and routes --- frontend/src/app/app.routes.ts | 5 + frontend/src/app/feature/lootboxes/README.md | 40 ++++ .../lootbox-selection.component.html | 55 +++++ .../lootbox-selection.component.scss | 188 ++++++++++++++++++ .../lootbox-selection.component.ts | 71 +++++++ .../assets/images/lootboxes/common-box.png | 1 + .../assets/images/lootboxes/legendary-box.png | 1 + .../src/assets/images/lootboxes/rare-box.png | 1 + 8 files changed, 362 insertions(+) create mode 100644 frontend/src/app/feature/lootboxes/README.md create mode 100644 frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html create mode 100644 frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.scss create mode 100644 frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts create mode 100644 frontend/src/assets/images/lootboxes/common-box.png create mode 100644 frontend/src/assets/images/lootboxes/legendary-box.png create mode 100644 frontend/src/assets/images/lootboxes/rare-box.png diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index c536f8f..bba628f 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -21,4 +21,9 @@ export const routes: Routes = [ loadComponent: () => import('./feature/game/blackjack/blackjack.component'), canActivate: [authGuard], }, + { + path: 'game/lootboxes', + loadComponent: () => import('./feature/lootboxes/lootbox-selection/lootbox-selection.component'), + canActivate: [authGuard], + }, ]; diff --git a/frontend/src/app/feature/lootboxes/README.md b/frontend/src/app/feature/lootboxes/README.md new file mode 100644 index 0000000..2aecc6b --- /dev/null +++ b/frontend/src/app/feature/lootboxes/README.md @@ -0,0 +1,40 @@ +# Lootboxes Feature + +Diese Funktion ermöglicht es Spielern, Lootboxen zu kaufen und zu öffnen. + +## Komponenten + +- **LootboxSelection**: Zeigt alle verfügbaren Lootboxen an und ermöglicht Filterung nach Kategorien. +- (Weitere Komponenten werden implementiert) + +## Implementierung + +### Lootbox-Kategorien +- Gewöhnlich (Common): Niedrigere Preise, höhere Gewinnchance +- Selten (Rare): Mittlere Preise, mittlere Gewinnchance +- Legendär (Legendary): Hohe Preise, niedrige Gewinnchance + +### Routen +- `/lootboxes`: Hauptseite mit Lootbox-Auswahl +- `/lootboxes/open/:id`: Öffnen einer bestimmten Lootbox +- `/lootboxes/fairness`: Informationen zur Fairness-Garantie + +## Hinweise zur Implementierung + +1. **Bilder**: Stelle sicher, dass die korrekten Bilder unter `/assets/images/lootboxes/` vorhanden sind. +2. **Styling**: Das Styling ist an Counter-Strike-Lootboxen angelehnt. +3. **Authentifizierung**: Alle Lootbox-Routen sind durch den Auth-Guard geschützt. + +## Lootbox-Objekt-Interface + +```typescript +interface Lootbox { + id: string; + name: string; + category: 'common' | 'rare' | 'legendary'; + price: number; + image: string; + chance: number; + maxPrize: number; +} +``` \ No newline at end of file diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html new file mode 100644 index 0000000..3b6d80c --- /dev/null +++ b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.html @@ -0,0 +1,55 @@ +
+
+

Lootboxen

+
+ + +
+
+ +
+

Alle unsere Lootboxen unterliegen einem verifizierbaren Fairness-System. + Die Gewinnchancen sind transparent und werden von unabhängigen Prüfern bestätigt.

+ Mehr zur Fairness-Garantie +
+ +
+
+
+
+ +
{{ lootbox.category | titlecase }}
+
+
+

{{ lootbox.name }}

+
+
+ Preis: + {{ lootbox.price }}€ +
+
+ Wahrscheinlichkeit: + {{ lootbox.chance }}% +
+
+ Höchster Preis: + {{ lootbox.maxPrize }}€ +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.scss b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.scss new file mode 100644 index 0000000..879dccc --- /dev/null +++ b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.scss @@ -0,0 +1,188 @@ + +.lootbox-container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; + background-color: #1a1a1a; + color: #fff; + font-family: 'Inter', sans-serif; +} + +.lootbox-header { + text-align: center; + margin-bottom: 2rem; + + h1 { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1rem; + color: #f8f8f8; + text-transform: uppercase; + letter-spacing: 2px; + } +} + +.category-filters { + display: flex; + justify-content: center; + gap: 1rem; + margin: 1.5rem 0; + + .category-btn { + background-color: #2a2a2a; + border: none; + color: #aaa; + padding: 0.5rem 1.5rem; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; + font-weight: 500; + + &:hover { + background-color: #3a3a3a; + color: #fff; + } + + &.active { + background-color: #4a4a4a; + color: #fff; + box-shadow: 0 0 0 2px rgba(#ffcc00, 0.5); + } + } +} + +.fairness-info { + background-color: rgba(#ffcc00, 0.1); + border-left: 4px solid #ffcc00; + padding: 1rem; + margin-bottom: 2rem; + border-radius: 4px; + + p { + margin: 0 0 0.5rem 0; + color: #ddd; + font-size: 0.9rem; + } + + .info-link { + color: #ffcc00; + text-decoration: none; + font-size: 0.9rem; + font-weight: 500; + + &:hover { + text-decoration: underline; + } + } +} + +.lootbox-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 2rem; +} + +.lootbox-card { + background: linear-gradient(135deg, #2a2a2a 0%, #1c1c1c 100%); + border-radius: 8px; + overflow: hidden; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); + transition: transform 0.3s ease, box-shadow 0.3s ease; + + &:hover { + transform: translateY(-5px); + box-shadow: 0 15px 30px rgba(0, 0, 0, 0.4); + } +} + +.lootbox-image-container { + position: relative; + padding-bottom: 75%; + overflow: hidden; + + .lootbox-image { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; + } + + .lootbox-category { + position: absolute; + top: 10px; + right: 10px; + padding: 5px 10px; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + + &.common { + background-color: #6b6b6b; + color: #fff; + } + + &.rare { + background-color: #4b69ff; + color: #fff; + } + + &.legendary { + background-color: #d32ce6; + color: #fff; + } + } + + &:hover .lootbox-image { + transform: scale(1.05); + } +} + +.lootbox-info { + padding: 1.5rem; +} + +.lootbox-name { + font-size: 1.25rem; + margin: 0 0 1rem 0; + font-weight: 600; +} + +.lootbox-details { + margin-bottom: 1.5rem; + + .detail-item { + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; + + .label { + color: #aaa; + font-size: 0.9rem; + } + + .value { + font-weight: 600; + font-size: 0.9rem; + } + } +} + +.kaufen-btn { + width: 100%; + background-color: #ffcc00; + color: #000; + border: none; + border-radius: 4px; + padding: 0.75rem 0; + font-weight: 600; + cursor: pointer; + transition: background-color 0.2s ease; + text-transform: uppercase; + letter-spacing: 1px; + + &:hover { + background-color: #ffd633; + } +} \ No newline at end of file diff --git a/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts new file mode 100644 index 0000000..43fe751 --- /dev/null +++ b/frontend/src/app/feature/lootboxes/lootbox-selection/lootbox-selection.component.ts @@ -0,0 +1,71 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; + +interface Lootbox { + id: string; + name: string; + category: 'common' | 'rare' | 'legendary'; + price: number; + image: string; + chance: number; + maxPrize: number; +} + +@Component({ + selector: 'app-lootbox-selection', + standalone: true, + imports: [CommonModule, RouterModule], + templateUrl: './lootbox-selection.component.html', + styleUrl: './lootbox-selection.component.scss' +}) +export default class LootboxSelectionComponent { + lootboxes: Lootbox[] = [ + { + id: 'common-box', + name: 'Gewöhnliche Box', + category: 'common', + price: 5, + image: '/assets/images/lootboxes/common-box.png', + chance: 7, + maxPrize: 50 + }, + { + id: 'rare-box', + name: 'Seltene Box', + category: 'rare', + price: 20, + image: '/assets/images/lootboxes/rare-box.png', + chance: 3.5, + maxPrize: 200 + }, + { + id: 'legendary-box', + name: 'Legendäre Box', + category: 'legendary', + price: 50, + image: '/assets/images/lootboxes/legendary-box.png', + chance: 1, + maxPrize: 1000 + } + ]; + + categories = [ + { id: 'common', name: 'Gewöhnlich' }, + { id: 'rare', name: 'Selten' }, + { id: 'legendary', name: 'Legendär' } + ]; + + selectedCategory: string | null = null; + + filterByCategory(category: string | null): void { + this.selectedCategory = category; + } + + get filteredLootboxes(): Lootbox[] { + if (!this.selectedCategory) { + return this.lootboxes; + } + return this.lootboxes.filter(box => box.category === this.selectedCategory); + } +} \ No newline at end of file diff --git a/frontend/src/assets/images/lootboxes/common-box.png b/frontend/src/assets/images/lootboxes/common-box.png new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/frontend/src/assets/images/lootboxes/common-box.png @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/images/lootboxes/legendary-box.png b/frontend/src/assets/images/lootboxes/legendary-box.png new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/frontend/src/assets/images/lootboxes/legendary-box.png @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/images/lootboxes/rare-box.png b/frontend/src/assets/images/lootboxes/rare-box.png new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/frontend/src/assets/images/lootboxes/rare-box.png @@ -0,0 +1 @@ + \ No newline at end of file