btc_horse/btc-UI/src/app/components/navbar/navbar.component.ts

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();
}
}
}