253 lines
7.8 KiB
TypeScript
253 lines
7.8 KiB
TypeScript
import {
|
|
Component,
|
|
OnInit,
|
|
OnDestroy,
|
|
ChangeDetectionStrategy,
|
|
ChangeDetectorRef,
|
|
NgZone,
|
|
ElementRef,
|
|
ViewChild,
|
|
AfterViewInit,
|
|
} from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { Router } from '@angular/router';
|
|
import { Subject, interval, Observable } from 'rxjs';
|
|
import { takeUntil } from 'rxjs/operators';
|
|
import { animate, style, transition, trigger } from '@angular/animations';
|
|
import { default as autoAnimate } from '@formkit/auto-animate';
|
|
|
|
import { PopupService } from '../services/popup.service';
|
|
import { GameService } from '../services/game.service';
|
|
import { WinnerService } from '../services/winner.service';
|
|
import { JackpotService } from '../services/jackpot.service';
|
|
import { AnimationService } from '../services/animation.service';
|
|
|
|
@Component({
|
|
selector: 'app-landing',
|
|
standalone: true,
|
|
imports: [CommonModule],
|
|
templateUrl: './landing.component.html',
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
animations: [
|
|
trigger('fadeSlide', [
|
|
transition(':enter', [
|
|
style({ opacity: 0, transform: 'translateY(20px)' }),
|
|
animate(
|
|
'0.5s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
style({ opacity: 1, transform: 'translateY(0)' })
|
|
),
|
|
]),
|
|
transition(':leave', [
|
|
animate(
|
|
'0.5s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
style({ opacity: 0, transform: 'translateY(-20px)' })
|
|
),
|
|
]),
|
|
]),
|
|
],
|
|
})
|
|
export class LandingComponent implements OnInit, OnDestroy, AfterViewInit {
|
|
private destroy$ = new Subject<void>();
|
|
nearMiss = false;
|
|
isScrolled = false;
|
|
|
|
@ViewChild('jackpotCounter') jackpotCounter!: ElementRef;
|
|
@ViewChild('heroSection') heroSection!: ElementRef;
|
|
@ViewChild('gamesGrid') gamesGrid!: ElementRef;
|
|
@ViewChild('winnersMarquee') winnersMarquee!: ElementRef;
|
|
@ViewChild('particleContainer') particleContainer!: ElementRef;
|
|
|
|
readonly showPopup$: Observable<boolean>;
|
|
readonly currentPopup$: Observable<any>;
|
|
readonly games$: Observable<any[]>;
|
|
readonly recentWinners$: Observable<any[]>;
|
|
readonly onlinePlayers$: Observable<number>;
|
|
readonly currentJackpot$: Observable<number>;
|
|
readonly timeLeft$: Observable<string>;
|
|
readonly totalPlayersToday: number;
|
|
readonly totalWinnersToday: number;
|
|
|
|
constructor(
|
|
private router: Router,
|
|
private cdr: ChangeDetectorRef,
|
|
private ngZone: NgZone,
|
|
private popupService: PopupService,
|
|
private gameService: GameService,
|
|
private winnerService: WinnerService,
|
|
private jackpotService: JackpotService,
|
|
private animationService: AnimationService
|
|
) {
|
|
this.showPopup$ = this.popupService.showPopup$;
|
|
this.currentPopup$ = this.popupService.currentPopup$;
|
|
this.games$ = this.gameService.games$;
|
|
this.recentWinners$ = this.winnerService.recentWinners$;
|
|
this.onlinePlayers$ = this.winnerService.onlinePlayers$;
|
|
this.currentJackpot$ = this.jackpotService.currentJackpot$;
|
|
this.timeLeft$ = this.jackpotService.timeLeft$;
|
|
this.totalPlayersToday = this.winnerService.getTotalPlayersToday();
|
|
this.totalWinnersToday = this.winnerService.getTotalWinnersToday();
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.initializeTimers();
|
|
this.initializeScrollListener();
|
|
}
|
|
|
|
ngAfterViewInit(): void {
|
|
this.initializeAnimations();
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
window.removeEventListener('scroll', () => {
|
|
this.isScrolled = window.scrollY > 0;
|
|
});
|
|
}
|
|
|
|
private initializeAnimations(): void {
|
|
this.animationService.createParticleEffect(this.particleContainer);
|
|
this.animationService.animateEntrance(this.heroSection);
|
|
const gameCards = this.gamesGrid.nativeElement.querySelectorAll('.game-card');
|
|
gameCards.forEach((card: HTMLElement, index: number) => {
|
|
this.animationService.animateEntrance(new ElementRef(card), 0.1 * index);
|
|
});
|
|
autoAnimate(this.winnersMarquee.nativeElement);
|
|
this.animationService.animateOnScroll(this.gamesGrid, 'slideUp');
|
|
this.currentJackpot$.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
|
this.animationService.animateJackpotCounter(this.jackpotCounter, value - 1000, value);
|
|
});
|
|
}
|
|
|
|
private initializeTimers(): void {
|
|
this.ngZone.runOutsideAngular(() => {
|
|
interval(1500)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.jackpotService.updateJackpot();
|
|
this.cdr.markForCheck();
|
|
});
|
|
interval(3000)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.winnerService.updateOnlinePlayers();
|
|
this.cdr.markForCheck();
|
|
});
|
|
interval(1000)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.jackpotService.updateTimeLeft();
|
|
if (this.jackpotService.isUrgent()) {
|
|
this.showUrgentOffer();
|
|
}
|
|
this.cdr.markForCheck();
|
|
});
|
|
interval(7000)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
const randomGame = this.gameService.getGameById('mega-fortune');
|
|
if (randomGame) {
|
|
const winAmount = Math.floor(Math.random() * 50000) + 10000;
|
|
this.winnerService.generateNewWinner(randomGame.name, winAmount);
|
|
if (winAmount > 10000) {
|
|
this.showBigWinPopup(winAmount);
|
|
}
|
|
}
|
|
this.cdr.markForCheck();
|
|
});
|
|
interval(15000)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.gameService.updateGameStats();
|
|
this.cdr.markForCheck();
|
|
});
|
|
interval(30000)
|
|
.pipe(takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.popupService.showRandomPopup();
|
|
this.cdr.markForCheck();
|
|
});
|
|
});
|
|
}
|
|
|
|
private initializeScrollListener(): void {
|
|
window.addEventListener('scroll', () => {
|
|
this.isScrolled = window.scrollY > 0;
|
|
this.cdr.detectChanges();
|
|
});
|
|
}
|
|
|
|
private showUrgentOffer(): void {
|
|
this.popupService.showSpecificPopup({
|
|
title: '⚠️ LAST CHANCE!',
|
|
message: 'Bonus offer expiring - Lock in 500% now!',
|
|
type: 'urgent',
|
|
cta: 'Claim Before Timer Ends',
|
|
expires: '00:30',
|
|
});
|
|
}
|
|
|
|
private showBigWinPopup(amount: number): void {
|
|
this.popupService.showSpecificPopup({
|
|
title: '🎰 MASSIVE WIN ALERT!',
|
|
message: `Player just won €${amount.toLocaleString()} on minimum bet!`,
|
|
subMessage: 'Same game still hot - Win rate increased to 99.9%!',
|
|
type: 'win',
|
|
cta: 'Play Same Game',
|
|
});
|
|
}
|
|
|
|
closePopup(): void {
|
|
this.popupService.closePopup();
|
|
}
|
|
|
|
claimBonus(): void {
|
|
this.nearMiss = true;
|
|
this.cdr.markForCheck();
|
|
|
|
setTimeout(() => {
|
|
this.router.navigate(['/register'], {
|
|
queryParams: {
|
|
bonus: 'welcome1000',
|
|
ref: 'landing_hero',
|
|
special: 'true',
|
|
vip: 'fast-track',
|
|
},
|
|
});
|
|
}, 1500);
|
|
}
|
|
|
|
playNow(gameId: string): void {
|
|
const game = this.gameService.getGameById(gameId);
|
|
if (!game) return;
|
|
|
|
this.popupService.showSpecificPopup({
|
|
title: '🎰 PERFECT TIMING!',
|
|
message: `${game.name} is currently at ${game.winChance}% win rate!`,
|
|
subMessage: `Last player won €${game.lastWin.toLocaleString()} - Hot streak active!`,
|
|
type: 'fomo',
|
|
cta: 'Play Now',
|
|
});
|
|
|
|
setTimeout(() => {
|
|
this.router.navigate(['/game', gameId], {
|
|
queryParams: {
|
|
ref: 'landing_games',
|
|
bonus: 'true',
|
|
rtp: 'enhanced',
|
|
multiplier: 'active',
|
|
},
|
|
});
|
|
}, 2000);
|
|
}
|
|
|
|
onButtonClick(event: MouseEvent): void {
|
|
const button = event.currentTarget as HTMLElement;
|
|
this.animationService.animateButtonClick(new ElementRef(button));
|
|
}
|
|
|
|
onGameCardHover(event: MouseEvent): void {
|
|
const card = event.currentTarget as HTMLElement;
|
|
this.animationService.animateFloat(new ElementRef(card));
|
|
}
|
|
}
|