From f6b8dba35262d7ccd854ee7e20b3892ad1451e1b Mon Sep 17 00:00:00 2001 From: karthik Date: Sat, 2 Aug 2025 22:46:13 +0530 Subject: [PATCH] fix : field fetches data from the backend --- .../selection.service/selection.service.ts | 82 +++++++++-- .../touch-pad-menu.component.html | 64 +++------ .../touch-pad-menu.component.ts | 55 ++++---- btc-UI/src/app/home/home.component.ts | 130 +++--------------- .../src/app/service/shared-state.service.ts | 21 ++- 5 files changed, 156 insertions(+), 196 deletions(-) diff --git a/btc-UI/src/app/components/selection.service/selection.service.ts b/btc-UI/src/app/components/selection.service/selection.service.ts index 7266a6f..9885622 100644 --- a/btc-UI/src/app/components/selection.service/selection.service.ts +++ b/btc-UI/src/app/components/selection.service/selection.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; +import { SharedStateService } from '../../service/shared-state.service'; // Corrected path export interface SelectionData { label: string; @@ -23,6 +24,14 @@ export class SelectionService { }); currentRow$ = this.currentRow.asObservable(); + private runnerCount: number = 12; // Fallback + + constructor(private sharedStateService: SharedStateService) { + this.sharedStateService.runnerCount$.subscribe(count => { + this.runnerCount = count || 12; // Update runner count dynamically + }); + } + updatePartial(update: Partial) { const current = this.currentRow.value; const updated: SelectionData = { ...current, ...update }; @@ -47,7 +56,7 @@ export class SelectionService { case 'PLC': case 'SHW': { if (numbers.includes('F')) { - updated.total = 12 * value * 10; + updated.total = this.runnerCount * value * 10; } else { updated.total = numbers.filter(n => typeof n === 'number').length * value * 10; } @@ -58,23 +67,23 @@ export class SelectionService { const dashIndex = numbers.indexOf('-'); const group1 = dashIndex === -1 ? numbers : numbers.slice(0, dashIndex); const group2 = dashIndex === -1 ? [] : numbers.slice(dashIndex + 1); - const group1Count = group1.includes('F') ? 12 : group1.filter(n => typeof n === 'number').length; - const group2Count = group2.includes('F') ? 12 : group2.filter(n => typeof n === 'number').length; + const group1Count = group1.includes('F') ? this.runnerCount : group1.filter(n => typeof n === 'number').length; + const group2Count = group2.includes('F') ? this.runnerCount : group2.filter(n => typeof n === 'number').length; let combinations = 0; if (isBoxed) { const allNums = [...group1, ...group2].filter(n => typeof n === 'number') as number[]; - const uniqueCount = new Set(allNums).size + (group1.includes('F') || group2.includes('F') ? 12 : 0); + const uniqueCount = new Set(allNums).size + (group1.includes('F') || group2.includes('F') ? this.runnerCount : 0); combinations = uniqueCount >= 2 ? this.calculatePermutations(uniqueCount) : 0; updated.numbers = [...group1, '-', ...group2]; } else { if (group1.includes('F') && group2.includes('F')) { - combinations = 12 * 11; // nP2 for 12 runners + combinations = this.runnerCount * (this.runnerCount - 1); // nP2 for dynamic runners } else if (group1.includes('F') || group2.includes('F')) { const nonFieldGroup = group1.includes('F') ? group2 : group1; const nonFieldNumbers = nonFieldGroup.filter(n => typeof n === 'number') as number[]; - combinations = 12 * nonFieldNumbers.length; + combinations = this.runnerCount * nonFieldNumbers.length; if (nonFieldNumbers.length > 0) { combinations -= nonFieldNumbers.length; // Subtract overlapping runners } @@ -107,15 +116,15 @@ export class SelectionService { if (isBoxed) { const allNums = [...group1, ...group2].filter(n => typeof n === 'number') as number[]; - const uniqueCount = new Set(allNums).size + (group1_is_field || group2_is_field ? 12 : 0); + const uniqueCount = new Set(allNums).size + (group1_is_field || group2_is_field ? this.runnerCount : 0); combinations = uniqueCount >= 2 ? (uniqueCount * (uniqueCount - 1)) / 2 : 0; } else if (group1_is_field && group2_is_field) { - combinations = (12 * 11) / 2; // C(12,2) + combinations = (this.runnerCount * (this.runnerCount - 1)) / 2; // C(n,2) } else if (group1_is_field || group2_is_field) { const fieldSide = group1_is_field ? group1Numbers : group2Numbers; const nonFieldNumbers = (group1_is_field ? group2 : group1).filter(n => typeof n === 'number') as number[]; const pairSet = new Set(); - const fieldNumbers = fieldSide.length > 0 ? fieldSide : Array.from({ length: 12 }, (_, i) => i + 1); + const fieldNumbers = fieldSide.length > 0 ? fieldSide : Array.from({ length: this.runnerCount }, (_, i) => i + 1); for (let j of nonFieldNumbers) { for (let i of fieldNumbers) { if (i !== j) { @@ -158,14 +167,13 @@ export class SelectionService { if (isBoxed) { if (numbers.includes('F')) { - combinations = this.calculatePermutationsN(12, 3); + combinations = this.calculatePermutationsN(this.runnerCount, 3); } else { const allNums = [...group1, ...group2, ...group3].filter(n => typeof n === 'number') as number[]; combinations = allNums.length >= 3 ? this.calculatePermutationsN(allNums.length, 3) : 0; } } else { - // Define possible values for each group: 'F' means all runners (1 to 12), else only selected numbers - const runners = Array.from({ length: 12 }, (_, i) => i + 1); + const runners = Array.from({ length: this.runnerCount }, (_, i) => i + 1); const group1Vals = group1.includes('F') ? runners : group1.filter(n => typeof n === 'number') as number[]; const group2Vals = group2.includes('F') ? runners : group2.filter(n => typeof n === 'number') as number[]; const group3Vals = group3.includes('F') ? runners : group3.filter(n => typeof n === 'number') as number[]; @@ -187,13 +195,61 @@ export class SelectionService { break; } + case 'EXA': { + const dashIndex = numbers.indexOf('-'); + const group1 = dashIndex === -1 ? numbers : numbers.slice(0, dashIndex); + const group2 = dashIndex === -1 ? [] : numbers.slice(dashIndex + 1); + const group1Count = group1.includes('F') ? this.runnerCount : group1.filter(n => typeof n === 'number').length; + const group2Count = group2.includes('F') ? this.runnerCount : group2.filter(n => typeof n === 'number').length; + + let combinations = 0; + + if (isBoxed) { + const allNums = [...group1, ...group2].filter(n => typeof n === 'number') as number[]; + const uniqueCount = new Set(allNums).size + (group1.includes('F') || group2.includes('F') ? this.runnerCount : 0); + combinations = uniqueCount >= 2 ? this.calculatePermutations(uniqueCount) : 0; + } else { + if (group1.includes('F') && group2.includes('F')) { + combinations = this.runnerCount * (this.runnerCount - 1); + } else if (group1.includes('F') || group2.includes('F')) { + const nonFieldGroup = group1.includes('F') ? group2 : group1; + const nonFieldNumbers = nonFieldGroup.filter(n => typeof n === 'number') as number[]; + combinations = this.runnerCount * nonFieldNumbers.length; + if (nonFieldNumbers.length > 0) { + combinations -= nonFieldNumbers.length; + } + } else { + const numGroup1 = group1.filter(n => typeof n === 'number') as number[]; + const numGroup2 = group2.filter(n => typeof n === 'number') as number[]; + for (const a of numGroup1) { + for (const b of numGroup2) { + if (a !== b) combinations++; + } + } + } + } + + updated.numbers = [...group1, '-', ...group2]; + updated.total = combinations * value * 10; + break; + } + + case 'WSP': { + if (numbers.includes('F')) { + updated.total = this.runnerCount * value * 10; + } else { + updated.total = numbers.filter(n => typeof n === 'number').length * value * 10; + } + break; + } + case 'TRE': case 'MJP': case 'JKP': { const legs = this.splitToLegs(numbers, this.getLegCount(label)); const requiredLegs = this.getLegCount(label); - const legCounts = legs.map(leg => leg.includes('F') ? 12 : leg.filter(n => typeof n === 'number').length); + const legCounts = legs.map(leg => leg.includes('F') ? this.runnerCount : leg.filter(n => typeof n === 'number').length); const filledLegs = legs.filter(leg => leg.length > 0).length; if (filledLegs >= requiredLegs - 1) { diff --git a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html index d916233..ef61dc5 100755 --- a/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html +++ b/btc-UI/src/app/components/touch-pad-menu/touch-pad-menu.component.html @@ -1,10 +1,8 @@
-
-
@@ -16,11 +14,8 @@ > BOX - -
-
- - -
-
-
- - +
@@ -83,7 +72,6 @@
-
@@ -94,7 +82,6 @@
-
-
@@ -114,7 +100,6 @@
-
@@ -128,28 +113,23 @@ - - - -
-
@@ -157,12 +137,9 @@ ×
FIELD
- - -

Total Runners
1,2,3,4,5,6,7,8,9,10,11,12

- +

Total Runners
{{ numbers.join(',') }}

-
-
TRB3
-
-
-
- Limit Reached +
+
+ Limit Reached +
+

+ Total amount limit of 5000 rupees has been reached. No further selections can be made. +

+
-

- Total amount limit of 5000 rupees has been reached. No further selections can be made. -

-
-
-
\ 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 cea60ca..0ff8f3d 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 @@ -1,8 +1,9 @@ import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { SelectionService } from '../selection.service/selection.service'; import { Subscription } from 'rxjs'; +import { SelectionService } from '../selection.service/selection.service'; import { SelectionData } from '../selection.service/selection.service'; +import { SharedStateService } from '../../service/shared-state.service'; @Component({ selector: 'app-touch-pad-menu', @@ -26,6 +27,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { ]; numbers: number[] = Array.from({ length: 30 }, (_, i) => i + 1); + runnerCount: number = 12; // Fallback labelRowsFlat: string[] = []; numbersFlat: number[] = []; @@ -69,14 +71,23 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { private currentRowSubscription: Subscription | null = null; private selectionsSubscription: Subscription | null = null; + private runnerCountSubscription: Subscription | null = null; private currentTotal: number = 0; private currentSelections: SelectionData[] = []; - constructor(private selectionService: SelectionService) {} + constructor( + private selectionService: SelectionService, + private sharedStateService: SharedStateService + ) {} ngOnInit() { + this.runnerCountSubscription = this.sharedStateService.runnerCount$.subscribe(count => { + this.runnerCount = count || 12; + this.numbers = Array.from({ length: 30 }, (_, i) => i + 1); // Always 1 to 30 + this.numbersFlat = this.numberRows.flat(); + }); + this.labelRowsFlat = this.labelRows.flat(); - this.numbersFlat = this.numberRows.flat(); this.selectionsSubscription = this.selectionService.selections$.subscribe(selections => { this.currentSelections = selections; this.maxRowsReached = selections.length >= 5; @@ -92,12 +103,9 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } ngOnDestroy() { - if (this.currentRowSubscription) { - this.currentRowSubscription.unsubscribe(); - } - if (this.selectionsSubscription) { - this.selectionsSubscription.unsubscribe(); - } + this.currentRowSubscription?.unsubscribe(); + this.selectionsSubscription?.unsubscribe(); + this.runnerCountSubscription?.unsubscribe(); } get labelRows() { @@ -170,6 +178,20 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { return this.disabledLabels.includes(label) || this.totalAmountLimitReached; } + isNumberDisabled(number: number): boolean { + // Only numbers up to runnerCount are enabled, others are disabled + if (number > this.runnerCount) { + return true; + } + if (this.selectedLabel === 'TAN' && this.isBoxed) { + return false; + } + if (this.selectedLabel === 'TAN' || this.multiLegLabels.includes(this.selectedLabel || '') || this.twoGroupLabels.includes(this.selectedLabel || '')) { + return false; + } + return this.selectedNumbers.includes(number) || this.totalAmountLimitReached; + } + selectLabel(label: string) { if (this.totalAmountLimitReached) { this.showLimitPopup = true; @@ -202,7 +224,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { } selectNumber(number: number) { - if (!this.selectedLabel || this.totalAmountLimitReached) return; + if (!this.selectedLabel || this.totalAmountLimitReached || number > this.runnerCount) return; // TAN Box mode: freestyle selection with dash-separated format if (this.selectedLabel === 'TAN' && this.isBoxed) { @@ -287,17 +309,6 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.selectionService.updatePartial({ numbers: [...this.selectedNumbers] }); } - isNumberDisabled(number: number): boolean { - // For TAN Box mode, allow all numbers to be selectable - if (this.selectedLabel === 'TAN' && this.isBoxed) { - return false; - } - if (this.selectedLabel === 'TAN' || this.multiLegLabels.includes(this.selectedLabel || '') || this.twoGroupLabels.includes(this.selectedLabel || '')) { - return false; - } - return this.selectedNumbers.includes(number) || this.totalAmountLimitReached; - } - onPadEnter() { if (this.canPrint) { this.print(); @@ -392,11 +403,9 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy { this.tanGroupStage = 0; this.tanGroups = [[], [], []]; - this.isFirstGroupComplete = false; this.firstGroup = []; this.secondGroup = []; - this.multiLegStage = 0; this.multiLegGroups = [[], [], [], [], []]; diff --git a/btc-UI/src/app/home/home.component.ts b/btc-UI/src/app/home/home.component.ts index e6bc444..f6a9b30 100755 --- a/btc-UI/src/app/home/home.component.ts +++ b/btc-UI/src/app/home/home.component.ts @@ -1,109 +1,4 @@ - -// import { -// Component, -// ChangeDetectorRef, -// OnInit, -// OnDestroy, -// } from '@angular/core'; -// import { SidebarComponent } from '../components/sidebar/sidebar.component'; -// import { NavbarComponent } from '../components/navbar/navbar.component'; -// import { MiddleSectionComponent } from '../components/middle-section/middle-section.component'; -// import { TouchPadMenuComponent } from '../components/touch-pad-menu/touch-pad-menu.component'; -// import { CommonModule } from '@angular/common'; -// import { BtcService } from '../service/btc.service'; -// import { HttpResponse } from '@angular/common/http'; -// import { HorseService } from '../service/horseData.service'; -// import { HorseRaceModel } from '../model/horseRaceData'; -// import { SharedStateService } from '../service/shared-state.service'; - -// @Component({ -// selector: 'app-home', -// standalone: true, -// imports: [ -// CommonModule, -// SidebarComponent, -// NavbarComponent, -// MiddleSectionComponent, -// TouchPadMenuComponent, -// ], -// templateUrl: './home.component.html', -// styleUrls: ['./home.component.css'], -// }) -// export class HomeComponent implements OnInit, OnDestroy { -// isTabletView = false; -// isTicketingActive = false; -// private resizeObserver!: () => void; - -// constructor( -// private cdr: ChangeDetectorRef, -// private btcService: BtcService, -// private horseService: HorseService, -// private sharedStateService: SharedStateService, -// ) {} - -// ngOnInit() { -// this.updateView(); - -// this.resizeObserver = () => { -// this.updateView(); -// this.cdr.detectChanges(); -// }; -// window.addEventListener('resize', this.resizeObserver); - -// console.log('Hit hitttt'); - -// // Fetch race data and push to shared screen -// this.btcService.getAllRaceEventsToday().subscribe({ -// next: (response: HttpResponse) => { -// const horseRaceData = response.body; -// this.horseService.HorseData.next(horseRaceData); - -// // ๐Ÿ” Push to shared screen -// this.sharedStateService.updateSharedData({ -// type: 'horseData', -// value: horseRaceData, -// }); -// }, -// error: (error) => { -// console.log('Error fetching race data'); -// }, -// }); -// } - -// ngOnDestroy() { -// window.removeEventListener('resize', this.resizeObserver); -// } - -// private updateView() { -// this.isTabletView = window.innerWidth <= 800; -// } - -// onTicketingClicked() { -// this.isTicketingActive = true; - -// // ๐Ÿ” Push ticketing state to shared screen -// this.sharedStateService.updateSharedData({ -// type: 'ticketing', -// value: true, -// }); -// } - -// onOtherActionClicked() { -// this.isTicketingActive = false; - -// // ๐Ÿ” Push ticketing state to shared screen -// this.sharedStateService.updateSharedData({ -// type: 'ticketing', -// value: false, -// }); -// } -// } -import { - Component, - ChangeDetectorRef, - OnInit, - OnDestroy, -} from '@angular/core'; +import { Component, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core'; import { SidebarComponent } from '../components/sidebar/sidebar.component'; import { NavbarComponent } from '../components/navbar/navbar.component'; import { MiddleSectionComponent } from '../components/middle-section/middle-section.component'; @@ -132,6 +27,8 @@ export class HomeComponent implements OnInit, OnDestroy { isTabletView = false; isTicketingActive = false; private resizeObserver!: () => void; + private currentRaceIdx: number = 0; // Track current race + races: any[] = []; // Store race data constructor( private cdr: ChangeDetectorRef, @@ -156,8 +53,7 @@ export class HomeComponent implements OnInit, OnDestroy { next: (response: HttpResponse) => { const horseRaceData = response.body; this.horseService.HorseData.next(horseRaceData); - - // ๐Ÿ” Push to shared screen + this.races = horseRaceData || []; // Populate races for selection this.sharedStateService.updateSharedData({ type: 'horseData', value: horseRaceData, @@ -176,6 +72,7 @@ export class HomeComponent implements OnInit, OnDestroy { const raceCardData = res.body; console.log('๐Ÿ“ฆ Race card preloaded:', raceCardData); localStorage.setItem('raceCardData', JSON.stringify(raceCardData)); + this.updateRunnerCount(0); // Initialize with first race }, error: (err) => { console.error('โŒ Failed to preload race card:', err); @@ -183,6 +80,7 @@ export class HomeComponent implements OnInit, OnDestroy { }); } else { console.log('๐Ÿ“ฆ Race card already cached'); + this.updateRunnerCount(0); // Initialize with first race } } @@ -213,4 +111,18 @@ export class HomeComponent implements OnInit, OnDestroy { value: false, }); } -} + + onRaceSelected(raceIdx: number) { + this.currentRaceIdx = raceIdx; + this.updateRunnerCount(raceIdx); + } + + private updateRunnerCount(raceIdx: number) { + const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}'); + const runnerCount = raceCardData?.raceVenueRaces?.races?.[raceIdx]?.length || 12; + if (!raceCardData?.raceVenueRaces?.races?.[raceIdx]) { + console.warn('โš ๏ธ Race data not found for index:', raceIdx); + } + this.sharedStateService.setRunnerCount(runnerCount); + } +} \ No newline at end of file diff --git a/btc-UI/src/app/service/shared-state.service.ts b/btc-UI/src/app/service/shared-state.service.ts index 59dc1d4..579707d 100644 --- a/btc-UI/src/app/service/shared-state.service.ts +++ b/btc-UI/src/app/service/shared-state.service.ts @@ -1,9 +1,11 @@ - import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SharedStateService { + private runnerCountSubject = new BehaviorSubject(12); // Default runner count + runnerCount$ = this.runnerCountSubject.asObservable(); + private sharedDataSubject = new BehaviorSubject(null); sharedData$ = this.sharedDataSubject.asObservable(); @@ -13,13 +15,22 @@ export class SharedStateService { // Listen to messages from other windows this.channel.onmessage = (event) => { console.log('[BroadcastChannel] Received data:', event.data); - this.sharedDataSubject.next(event.data); // sync incoming data + if (event.data?.runnerCount !== undefined) { + this.runnerCountSubject.next(event.data.runnerCount); // Sync runner count + } + this.sharedDataSubject.next(event.data); // Sync other shared data }; } + setRunnerCount(count: number) { + console.log('[SharedStateService] Broadcasting runner count:', count); + this.channel.postMessage({ runnerCount: count }); // Broadcast runner count + this.runnerCountSubject.next(count); // Update local runner count + } + updateSharedData(data: any) { console.log('[SharedStateService] Broadcasting data:', data); - this.channel.postMessage(data); // send to other windows - this.sharedDataSubject.next(data); // update local BehaviorSubject + this.channel.postMessage(data); // Send to other windows + this.sharedDataSubject.next(data); // Update local BehaviorSubject } -} +} \ No newline at end of file