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