diff --git a/btc-UI/src/app/components/navbar/navbar.component.html b/btc-UI/src/app/components/navbar/navbar.component.html index 0503fb2..46e392f 100755 --- a/btc-UI/src/app/components/navbar/navbar.component.html +++ b/btc-UI/src/app/components/navbar/navbar.component.html @@ -42,7 +42,7 @@ class="nav-dropdown w-50 text-start ps-3" (click)="openRaceModal()" > - Race No. | {{ selectedRace }} + Race No. | {{ currentLegRaceDisplay ? currentLegRaceDisplay : 'Race ' + selectedRace }}
@@ -95,7 +95,7 @@ class="nav-dropdown w-100 text-end pe-3" (click)="openRaceModal()" > - Race No. | {{ selectedRace }} + Race No. | {{ currentLegRaceDisplay ? currentLegRaceDisplay : 'Race ' + selectedRace }}
@@ -211,7 +211,6 @@
VIEW-LOG
-
@@ -220,40 +219,26 @@
- - - -
- - + \ No newline at end of file diff --git a/btc-UI/src/app/components/navbar/navbar.component.ts b/btc-UI/src/app/components/navbar/navbar.component.ts index 1c6c68e..a5e38fe 100755 --- a/btc-UI/src/app/components/navbar/navbar.component.ts +++ b/btc-UI/src/app/components/navbar/navbar.component.ts @@ -24,7 +24,7 @@ export class NavbarComponent implements OnInit, OnDestroy { showRaceModal = false; selectedVenue = 'Select Venue'; selectedRace: number = 1; - currentLegRaceDisplay: string = ''; // Display current leg's race + currentLegRaceDisplay: string = ''; // Display current leg's race or pool start showWalletModal = false; showResultModal = false; @@ -38,6 +38,7 @@ export class NavbarComponent implements OnInit, OnDestroy { 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, @@ -104,12 +105,97 @@ export class NavbarComponent implements OnInit, OnDestroy { this.sharedStateService.sharedData$.subscribe(data => { if (data.type === 'currentLegRace') { this.selectedRace = data.value; - this.currentLegRaceDisplay = `Race ${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(); @@ -139,6 +225,8 @@ export class NavbarComponent implements OnInit, OnDestroy { const venueIndex = Object.keys(this.raceCardData?.raceVenueRaces?.races || []) .findIndex((_, idx) => idx === this.selectedRaceId); + + if (venueIndex !== -1) { this.raceData = this.raceCardData.raceVenueRaces.races[venueIndex] || []; } @@ -172,7 +260,9 @@ export class NavbarComponent implements OnInit, OnDestroy { selectRace(race: number) { this.selectedRace = race; - this.multiLegBaseRaceIdx = race; + this.currentPool = null; + this.multiLegBaseRaceIdx = 0; + this.currentLegRaceDisplay = ''; this.sharedStateService.updateSharedData({ type: 'selectedRace', @@ -268,4 +358,4 @@ export class NavbarComponent implements OnInit, OnDestroy { this.subscription.unsubscribe(); } } -} +} \ No newline at end of file diff --git a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts index 83a8fc8..fbd4513 100755 --- a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts +++ b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.ts @@ -57,6 +57,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { multiLegGroups: (number | string)[][] = [[], [], [], [], []]; multiLegBaseRaceIdx: number = 0; // Track starting race index currentLegRaceDisplay: string = ''; // Display current leg's race + currentPool: string | null = null; // Track current pool (mjp1, jkp1, trb1, trb2) isBoxed: boolean = false; @@ -87,7 +88,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.runnerCount = count || 12; this.numbers = Array.from({ length: 30 }, (_, i) => i + 1); this.numbersFlat = this.numberRows.flat(); - this.updateLegRaceDisplay(this.selectedLabel || ''); + this.updateLegRaceDisplay(this.currentPool || ''); }); this.labelRowsFlat = this.labelRows.flat(); @@ -96,8 +97,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.maxRowsReached = selections.length >= 5; const totalAmount = selections.reduce((sum, selection) => sum + selection.total, 0); this.totalAmountLimitReached = totalAmount >= 5000; - if (this.totalAmountLimitReached) { - this.showLimitPopup = true; + if (!this.totalAmountLimitReached) { + this.showLimitPopup = false; } }); this.currentRowSubscription = this.selectionService.currentRow$.subscribe(row => { @@ -139,8 +140,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } return this.tanGroupStage >= 2 || this.tanGroups[this.tanGroupStage].length === 0; } else if (this.multiLegLabels.includes(this.selectedLabel || '')) { - const maxLegs = this.getMaxLegs(this.selectedLabel || ''); - return this.multiLegStage >= maxLegs - 1 || this.multiLegGroups[this.multiLegStage].length === 0; + const maxLegs = this.getMaxLegs(this.currentPool || ''); + return this.multiLegStage >= maxLegs || this.multiLegGroups[this.multiLegStage].length === 0; } else if (this.twoGroupLabels.includes(this.selectedLabel || '')) { return this.isFirstGroupComplete || this.firstGroup.length === 0; } @@ -206,10 +207,25 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.canPrint = false; this.isBoxed = false; - // Store base race index for multi-leg pools + // Store base race index and pool name for multi-leg pools if (this.multiLegLabels.includes(label)) { - this.multiLegBaseRaceIdx = this.sharedStateService.getSelectedRace(); - this.updateLegRaceDisplay(label); + const poolName = label === 'MJP' ? 'mjp1' : label === 'JKP' ? 'jkp1' : label === 'TRE' ? 'trb1' : label; + this.currentPool = poolName; + this.multiLegBaseRaceIdx = this.getBaseRaceIndexForPool(poolName); + // Broadcast race and pool info for navbar + this.sharedStateService.updateSharedData({ + type: 'multiLegPoolStart', + value: { label: poolName, baseRaceIdx: this.multiLegBaseRaceIdx } + }); + this.updateLegRaceDisplay(poolName); + } else { + this.currentPool = null; + this.multiLegBaseRaceIdx = 0; + this.currentLegRaceDisplay = ''; + this.sharedStateService.updateSharedData({ + type: 'multiLegPoolEnd', + value: null + }); } // Reset TAN @@ -228,6 +244,34 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.selectionService.updatePartial({ label }); } + private getBaseRaceIndexForPool(poolName: string): number { + const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}'); + const totalRaces = raceCardData?.raceVenueRaces?.races?.length || 10; + const maxLegs = this.getMaxLegs(poolName); + + // Try to get pool-to-race mapping from raceCardData + const poolRaces = raceCardData?.raceVenueRaces?.pools?.[poolName] || []; + let baseRaceIdx = poolRaces.length > 0 ? poolRaces[0] : this.getDefaultBaseRace(poolName); + + // Ensure enough races remain for the pool + if (baseRaceIdx + maxLegs - 1 > totalRaces) { + baseRaceIdx = Math.max(1, totalRaces - maxLegs + 1); + } + + return baseRaceIdx; + } + + private getDefaultBaseRace(poolName: string): number { + // Fallback to hardcoded values if raceCardData.pools is unavailable + const poolRaceMap: { [key: string]: number } = { + 'mjp1': 1, + 'jkp1': 3, + 'trb1': 2, + 'trb2': 5 + }; + return poolRaceMap[poolName] || this.sharedStateService.getSelectedRace(); + } + selectNumber(number: number) { if (!this.selectedLabel || this.totalAmountLimitReached || number > this.runnerCount) return; @@ -310,7 +354,11 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } this.selectedNumbers = combined; this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); - this.updateLegRaceDisplay(this.selectedLabel || ''); + this.updateLegRaceDisplay(this.currentPool || ''); + } + + private calculateMultiLegAmount(poolType: 'TRE' | 'MJP' | 'JKP', horsesPerLeg: number[], units: number, unitBet: number = 10): number { + return horsesPerLeg.reduce((acc, v) => acc * v, 1) * units * unitBet; } onPadEnter() { @@ -325,7 +373,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } if (this.selectedLabel === 'TAN') { - if (this.tanGroupStage < 2) { + if (this.tanGroupStage < 2 && this.tanGroups[this.tanGroupStage].length > 0) { this.tanGroupStage++; const combined: (number | string)[] = [...this.tanGroups[0]]; if (this.tanGroupStage > 0) combined.push('-', ...this.tanGroups[1]); @@ -337,11 +385,11 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } if (this.multiLegLabels.includes(this.selectedLabel || '')) { - const maxLegs = this.getMaxLegs(this.selectedLabel || ''); - if (this.multiLegStage < maxLegs - 1) { + const maxLegs = this.getMaxLegs(this.currentPool || ''); + if (this.multiLegStage < maxLegs - 1 && this.multiLegGroups[this.multiLegStage].length > 0) { this.multiLegStage++; this.updateMultiLegSelection(); - this.updateLegRaceDisplay(this.selectedLabel || ''); + this.updateLegRaceDisplay(this.currentPool || ''); } return; } @@ -380,13 +428,45 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { updateCanPrint() { this.canPrint = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue); + if (this.multiLegLabels.includes(this.selectedLabel || '')) { + const maxLegs = this.getMaxLegs(this.currentPool || ''); + this.canPrint = this.canPrint && this.multiLegStage === maxLegs - 1 && this.multiLegGroups[this.multiLegStage].length > 0; + } } print() { const selectionsTotal = this.currentSelections.reduce((sum, sel) => sum + sel.total, 0); - if (selectionsTotal + this.currentTotal > 5000) { - this.showLimitPopup = true; - return; + let currentRowAmount = 0; + if (this.multiLegLabels.includes(this.selectedLabel || '')) { + const maxLegs = this.getMaxLegs(this.currentPool || ''); + const horsesPerLeg = this.multiLegGroups.map((group, index) => { + if (group.includes('F')) { + return this.getRunnerCountForLeg(this.multiLegBaseRaceIdx, index); + } + return group.length; + }).slice(0, maxLegs); + const units = parseFloat(this.padValue) || 0; + currentRowAmount = this.calculateMultiLegAmount( + this.selectedLabel as 'TRE' | 'MJP' | 'JKP', + horsesPerLeg, + units + ); + if (currentRowAmount > 5000 || selectionsTotal + currentRowAmount > 5000) { + this.totalAmountLimitReached = true; + this.showLimitPopup = true; + return; + } + // Ensure all legs have selections + if (horsesPerLeg.some(count => count === 0)) { + return; + } + } else { + currentRowAmount = this.currentTotal; + if (selectionsTotal + currentRowAmount > 5000) { + this.totalAmountLimitReached = true; + this.showLimitPopup = true; + return; + } } this.selectionService.finalizeCurrentRow(); this.resetSelections(); @@ -403,6 +483,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.padValue = ''; this.canPrint = false; this.isBoxed = false; + this.totalAmountLimitReached = false; + this.showLimitPopup = false; this.tanGroupStage = 0; this.tanGroups = [[], [], []]; @@ -413,10 +495,17 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.multiLegGroups = [[], [], [], [], []]; this.multiLegBaseRaceIdx = 0; this.currentLegRaceDisplay = ''; + this.currentPool = null; this.fieldModalOpen = false; this.fieldInput = ''; this.fieldFEntered = false; + + // Clear multi-leg display in Navbar + this.sharedStateService.updateSharedData({ + type: 'multiLegPoolEnd', + value: null + }); } toggleBoxMode() { @@ -512,21 +601,44 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } - private getMaxLegs(label: string): number { - switch (label) { - case 'TRE': return 3; - case 'MJP': return 4; - case 'JKP': return 5; - default: return 3; + private getMaxLegs(poolName: string): number { + switch (poolName) { + case 'mjp1': + return 4; + case 'jkp1': + return 5; + case 'trb1': + case 'trb2': + case 'TRE': + return 3; + default: + return 5; // Default to 5 for unspecified pools } } - private updateLegRaceDisplay(label: string) { - if (!this.multiLegLabels.includes(label)) { + private getRaceForLeg(poolName: string, leg: number): number { + const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}'); + const poolRaces = raceCardData?.raceVenueRaces?.pools?.[poolName] || []; + if (poolRaces.length > leg) { + return poolRaces[leg]; + } + // Fallback to default race mapping + 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); + } + + private updateLegRaceDisplay(poolName: string) { + if (!['mjp1', 'jkp1', 'trb1', 'trb2'].includes(poolName)) { this.currentLegRaceDisplay = ''; + this.currentPool = null; return; } - const raceIdx = this.multiLegBaseRaceIdx + this.multiLegStage; + const raceIdx = this.getRaceForLeg(poolName, this.multiLegStage); this.currentLegRaceDisplay = `Leg ${this.multiLegStage + 1} (Race ${raceIdx})`; const runnerCount = this.getRunnerCountForLeg(this.multiLegBaseRaceIdx, this.multiLegStage); this.sharedStateService.setRunnerCount(runnerCount); @@ -538,7 +650,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { private getRunnerCountForLeg(baseIdx: number, leg: number): number { const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}'); - const raceIdx = baseIdx - 1 + leg; // 0-based index + const raceIdx = this.getRaceForLeg(this.currentPool || '', leg) - 1; const race = raceCardData?.raceVenueRaces?.races?.[raceIdx] || []; return Array.isArray(race) ? race.length : 12; } @@ -729,10 +841,10 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { treButtonClick(btnNum: number) { this.trePopupVisible = false; - this._selectTreAfterPopup(); + this._selectTreAfterPopup(btnNum); } - private _selectTreAfterPopup() { + private _selectTreAfterPopup(btnNum: number) { this.selectedLabel = 'TRE'; this.selectedNumbers = []; this.padValue = ''; @@ -746,9 +858,24 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.secondGroup = []; this.multiLegStage = 0; this.multiLegGroups = [[], [], [], [], []]; - this.multiLegBaseRaceIdx = this.sharedStateService.getSelectedRace(); - this.updateLegRaceDisplay('TRE'); + // Map TRE button to specific pool name and base race dynamically + const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}'); + const trePoolMap: { [key: number]: { name: string } } = { + 1: { name: 'trb1' }, + 2: { name: 'trb2' } + }; + const poolInfo = trePoolMap[btnNum] || { name: 'trb1' }; + this.currentPool = poolInfo.name; + this.multiLegBaseRaceIdx = this.getBaseRaceIndexForPool(poolInfo.name); + + // Broadcast TRE selection + this.sharedStateService.updateSharedData({ + type: 'multiLegPoolStart', + value: { label: poolInfo.name, baseRaceIdx: this.multiLegBaseRaceIdx } + }); + + this.updateLegRaceDisplay(poolInfo.name); this.selectionService.updatePartial({ label: 'TRE' }); }