361 lines
10 KiB
TypeScript
Executable File
361 lines
10 KiB
TypeScript
Executable File
import { Component, OnInit, HostListener, OnDestroy } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { BtcService } from '../../service/btc.service';
|
|
import { Router } from '@angular/router';
|
|
import { catchError, interval, of, Subscription, switchMap } from 'rxjs';
|
|
import { SharedStateService } from '../../service/shared-state.service';
|
|
|
|
@Component({
|
|
selector: 'app-navbar',
|
|
templateUrl: './navbar.component.html',
|
|
styleUrls: ['./navbar.component.css'],
|
|
standalone: true,
|
|
imports: [CommonModule],
|
|
})
|
|
export class NavbarComponent implements OnInit, OnDestroy {
|
|
dateTime: string = '';
|
|
isMenuOpen: boolean = false;
|
|
screenWidth: number = window.innerWidth;
|
|
private subscription!: Subscription;
|
|
|
|
liveStatusOk: boolean = true;
|
|
|
|
showVenueModal = false;
|
|
showRaceModal = false;
|
|
selectedVenue = 'Select Venue';
|
|
selectedRace: number = 1;
|
|
currentLegRaceDisplay: string = ''; // Display current leg's race or pool start
|
|
|
|
showWalletModal = false;
|
|
showResultModal = false;
|
|
showMessagesModal = false;
|
|
showLogModal = false;
|
|
|
|
raceCardData: any = {};
|
|
raceData: any[] = [];
|
|
objectKeys = Object.keys;
|
|
|
|
selectedRaceId: number = 0;
|
|
enabledHorseNumbers: number[] = [];
|
|
multiLegBaseRaceIdx: number = 0; // Track base race index for multi-leg pools
|
|
currentPool: string | null = null; // Track current multi-leg pool
|
|
|
|
wallet = {
|
|
withdraw: 0,
|
|
deposit: 0,
|
|
payout: 0,
|
|
cancel: 0,
|
|
ticketing: 0,
|
|
balance: 0,
|
|
};
|
|
|
|
logs = [{
|
|
description: '',
|
|
venue: '',
|
|
ticketNumber: '',
|
|
poolName: '',
|
|
totalAmount: '',
|
|
}];
|
|
|
|
messages: string[] = [
|
|
'System ready.',
|
|
'Please select a venue.',
|
|
'Races updated.',
|
|
'Live status stable.',
|
|
];
|
|
|
|
constructor(
|
|
private btcService: BtcService,
|
|
private router: Router,
|
|
private sharedStateService: SharedStateService
|
|
) {}
|
|
|
|
ngOnInit() {
|
|
this.updateDateTime();
|
|
setInterval(() => this.updateDateTime(), 1000);
|
|
|
|
this.subscription = interval(5000)
|
|
.pipe(
|
|
switchMap(() =>
|
|
this.btcService.pingLiveStatus().pipe(
|
|
catchError((error) => {
|
|
console.error('[LIVE STATUS] Ping failed:', error);
|
|
this.liveStatusOk = false;
|
|
return of(null);
|
|
})
|
|
))
|
|
).subscribe((response) => {
|
|
if (response !== null) {
|
|
console.log('[LIVE STATUS] OK');
|
|
this.liveStatusOk = true;
|
|
}
|
|
});
|
|
|
|
const cachedData = localStorage.getItem('raceCardData');
|
|
if (cachedData) {
|
|
this.raceCardData = JSON.parse(cachedData);
|
|
console.log('📦 Loaded race card from localStorage:', this.raceCardData);
|
|
this.selectedVenue = this.raceCardData?.Venue || 'Select Venue';
|
|
this.updateEnabledHorseNumbers();
|
|
} else {
|
|
this.raceCardData = { raceVenueRaces: { races: [] }, pools: {} };
|
|
console.warn('⚠️ No race card data found in localStorage.');
|
|
}
|
|
|
|
this.sharedStateService.sharedData$.subscribe(data => {
|
|
if (data.type === 'currentLegRace') {
|
|
this.selectedRace = data.value;
|
|
if (this.currentPool) {
|
|
const leg = this.getLegIndexForRace(this.currentPool, data.value);
|
|
this.currentLegRaceDisplay = `Leg ${leg + 1} (Race ${data.value}) for ${this.currentPool}`;
|
|
this.updateEnabledHorseNumbersForMultiLeg(this.multiLegBaseRaceIdx);
|
|
} else {
|
|
this.currentLegRaceDisplay = '';
|
|
this.updateEnabledHorseNumbers();
|
|
}
|
|
}
|
|
if (data.type === 'multiLegPoolStart') {
|
|
const { label, baseRaceIdx } = data.value;
|
|
this.currentPool = label;
|
|
this.multiLegBaseRaceIdx = baseRaceIdx;
|
|
this.currentLegRaceDisplay = `Starting at Race ${baseRaceIdx} for ${label}`;
|
|
this.updateEnabledHorseNumbersForMultiLeg(baseRaceIdx);
|
|
console.log(`[Multi-leg Pool] Selected: ${label}, Base Race: ${baseRaceIdx}`);
|
|
}
|
|
if (data.type === 'multiLegPoolEnd') {
|
|
this.currentPool = null;
|
|
this.multiLegBaseRaceIdx = 0;
|
|
this.currentLegRaceDisplay = '';
|
|
this.updateEnabledHorseNumbers();
|
|
}
|
|
if (data.type === 'selectedRace') {
|
|
this.currentPool = null;
|
|
this.multiLegBaseRaceIdx = 0;
|
|
this.currentLegRaceDisplay = '';
|
|
this.selectedRace = data.value;
|
|
this.updateEnabledHorseNumbers();
|
|
}
|
|
});
|
|
}
|
|
|
|
private getLegIndexForRace(poolName: string, race: number): number {
|
|
const raceMap: { [key: string]: number[] } = {
|
|
'mjp1': [1, 2, 3, 4],
|
|
'jkp1': [3, 4, 5, 6, 7],
|
|
'trb1': [2, 3, 4],
|
|
'trb2': [5, 6, 7]
|
|
};
|
|
return raceMap[poolName]?.indexOf(race) ?? 0;
|
|
}
|
|
|
|
private updateEnabledHorseNumbersForMultiLeg(baseRaceIdx: number) {
|
|
const raceCardData = this.raceCardData?.raceVenueRaces?.races || [];
|
|
let combinedHorseNumbers: number[] = [];
|
|
const legCount = this.getLegCountForLabel();
|
|
|
|
for (let i = 0; i < legCount; i++) {
|
|
const raceIdx = this.getRaceForLeg(this.currentPool || '', i) - 1;
|
|
const race = raceCardData[raceIdx] || [];
|
|
if (Array.isArray(race)) {
|
|
const horses = race
|
|
.map((runner: any) => runner?.horseNumber)
|
|
.filter((n: number) => typeof n === 'number' && n >= 1 && n <= 30);
|
|
combinedHorseNumbers = combinedHorseNumbers.concat(horses);
|
|
}
|
|
}
|
|
|
|
combinedHorseNumbers = Array.from(new Set(combinedHorseNumbers));
|
|
this.enabledHorseNumbers = combinedHorseNumbers;
|
|
|
|
this.sharedStateService.updateSharedData({
|
|
type: 'enabledHorseNumbers',
|
|
value: this.enabledHorseNumbers,
|
|
});
|
|
|
|
console.log('[Multi-leg Pool] Updated enabled horse numbers:', this.enabledHorseNumbers);
|
|
}
|
|
|
|
private getLegCountForLabel(): number {
|
|
if (!this.currentPool) return 3;
|
|
switch (this.currentPool) {
|
|
case 'mjp1': return 4;
|
|
case 'jkp1': return 5;
|
|
case 'trb1':
|
|
case 'trb2': return 3;
|
|
default: return 3;
|
|
}
|
|
}
|
|
|
|
private getRaceForLeg(poolName: string, leg: number): number {
|
|
const raceMap: { [key: string]: number[] } = {
|
|
'mjp1': [1, 2, 3, 4],
|
|
'jkp1': [3, 4, 5, 6, 7],
|
|
'trb1': [2, 3, 4],
|
|
'trb2': [5, 6, 7]
|
|
};
|
|
return raceMap[poolName]?.[leg] || (this.multiLegBaseRaceIdx + leg);
|
|
}
|
|
|
|
updateDateTime() {
|
|
const now = new Date();
|
|
this.dateTime = now.toLocaleString();
|
|
}
|
|
|
|
@HostListener('window:resize', ['$event'])
|
|
onResize(event: any) {
|
|
this.screenWidth = event.target.innerWidth;
|
|
if (this.screenWidth > 800) {
|
|
this.isMenuOpen = false;
|
|
}
|
|
}
|
|
|
|
toggleMenu() {
|
|
this.isMenuOpen = !this.isMenuOpen;
|
|
}
|
|
|
|
openVenueModal() {
|
|
console.log('[MODAL] Opening venue modal');
|
|
this.showVenueModal = true;
|
|
}
|
|
|
|
openRaceModal() {
|
|
console.log('[MODAL] Opening race modal');
|
|
this.showRaceModal = true;
|
|
|
|
const venueIndex = Object.keys(this.raceCardData?.raceVenueRaces?.races || [])
|
|
.findIndex((_, idx) => idx === this.selectedRaceId);
|
|
|
|
|
|
|
|
if (venueIndex !== -1) {
|
|
this.raceData = this.raceCardData.raceVenueRaces.races[venueIndex] || [];
|
|
}
|
|
}
|
|
|
|
closeModals() {
|
|
console.log('[MODAL] Closing all modals');
|
|
this.showVenueModal = false;
|
|
this.showRaceModal = false;
|
|
this.showWalletModal = false;
|
|
this.showResultModal = false;
|
|
this.showMessagesModal = false;
|
|
this.showLogModal = false;
|
|
}
|
|
|
|
selectVenue(index: number) {
|
|
const venue = this.raceCardData?.Venue || 'Unknown Venue';
|
|
this.selectedVenue = venue;
|
|
this.selectedRaceId = index;
|
|
|
|
this.sharedStateService.updateSharedData({
|
|
type: 'selectedVenue',
|
|
value: this.selectedVenue,
|
|
});
|
|
|
|
console.log('[VENUE] Venue resolved to:', this.selectedVenue);
|
|
console.log('[VENUE] Venue sent to sharedStateService');
|
|
|
|
this.closeModals();
|
|
}
|
|
|
|
selectRace(race: number) {
|
|
this.selectedRace = race;
|
|
this.currentPool = null;
|
|
this.multiLegBaseRaceIdx = 0;
|
|
this.currentLegRaceDisplay = '';
|
|
|
|
this.sharedStateService.updateSharedData({
|
|
type: 'selectedRace',
|
|
value: this.selectedRace,
|
|
});
|
|
|
|
const raceCard = JSON.parse(localStorage.getItem('raceCardData') || '{}');
|
|
const raceList = raceCard?.raceVenueRaces?.races || [];
|
|
const selectedRaceData = raceList[race - 1] || [];
|
|
const runnerCount = selectedRaceData.length || 12;
|
|
|
|
this.sharedStateService.setRunnerCount(runnerCount);
|
|
this.updateEnabledHorseNumbers();
|
|
|
|
console.log('[RACE] Race selected:', this.selectedRace, '| Runner count:', runnerCount);
|
|
this.closeModals();
|
|
}
|
|
|
|
updateEnabledHorseNumbers() {
|
|
const raceIndex = this.selectedRace - 1;
|
|
const race = this.raceCardData?.raceVenueRaces?.races?.[raceIndex];
|
|
|
|
if (Array.isArray(race)) {
|
|
this.enabledHorseNumbers = race
|
|
.map((runner: any) => runner?.horseNumber)
|
|
.filter((n: any) => typeof n === 'number' && n >= 1 && n <= 30);
|
|
} else {
|
|
this.enabledHorseNumbers = [];
|
|
}
|
|
|
|
console.log('[HORSE NUMBERS] Enabled horse numbers:', this.enabledHorseNumbers);
|
|
|
|
this.sharedStateService.updateSharedData({
|
|
type: 'enabledHorseNumbers',
|
|
value: this.enabledHorseNumbers,
|
|
});
|
|
}
|
|
|
|
selectHorseNumber(number: number) {
|
|
console.log('[HORSE] Selected horse number:', number);
|
|
}
|
|
|
|
openWalletModal() {
|
|
console.log('[MODAL] Opening wallet modal');
|
|
this.showWalletModal = true;
|
|
}
|
|
|
|
openResultModal() {
|
|
console.log('[MODAL] Opening result modal');
|
|
this.showResultModal = true;
|
|
}
|
|
|
|
openMessagesModal() {
|
|
console.log('[MODAL] Opening messages modal');
|
|
this.showMessagesModal = true;
|
|
}
|
|
|
|
openLogModal() {
|
|
console.log('[MODAL] Opening log modal');
|
|
this.showLogModal = true;
|
|
}
|
|
|
|
logout(): void {
|
|
const name = localStorage.getItem('userName') || 'Unknown User';
|
|
const employeeId = localStorage.getItem('employeeId') || '000000';
|
|
|
|
const printData = { name, employeeId, action: 'logout' };
|
|
|
|
console.log('[LOGOUT] Initiating logout with printData:', printData);
|
|
|
|
fetch('http://localhost:9100/print', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(printData),
|
|
})
|
|
.then((res) => {
|
|
if (!res.ok) throw new Error('Logout print failed');
|
|
console.log('[LOGOUT] Print successful');
|
|
(window as any).electronAPI?.closeSecondScreen?.();
|
|
localStorage.clear();
|
|
this.router.navigate(['/logout']);
|
|
})
|
|
.catch((err) => {
|
|
console.error('[LOGOUT] Error printing:', err);
|
|
(window as any).electronAPI?.closeSecondScreen?.();
|
|
localStorage.clear();
|
|
this.router.navigate(['/logout']);
|
|
});
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
if (this.subscription) {
|
|
this.subscription.unsubscribe();
|
|
}
|
|
}
|
|
} |