fix : added restriction for the multileg pools (row)

This commit is contained in:
karthik 2025-09-21 14:38:59 +05:30
parent 148de807f7
commit 102b6d57df
2 changed files with 150 additions and 92 deletions

View File

@ -1,4 +1,3 @@
// label-restriction.service.ts
import { Injectable } from '@angular/core';
import { SelectionData } from '../selection.service/selection.service';
@ -22,15 +21,16 @@ export class LabelRestrictionService {
// accept optional currentLabel
getBlockedLabels(selections: SelectionData[], currentLabel?: string | null): Set<string> {
const selectedGroups = new Set<string>();
const multiLegLabels = ['TBP', 'MJP', 'JPP'];
// existing finalized selections
// Existing finalized selections
for (const row of selections) {
if (row.label && LABEL_TO_GROUP[row.label]) {
selectedGroups.add(LABEL_TO_GROUP[row.label]);
}
}
// also consider in-progress/current label (if provided)
// Also consider in-progress/current label (if provided)
if (currentLabel && LABEL_TO_GROUP[currentLabel]) {
selectedGroups.add(LABEL_TO_GROUP[currentLabel]);
}
@ -52,6 +52,12 @@ export class LabelRestrictionService {
}
});
}
// New rule: if any multi-leg label is finalized, block all other multi-leg labels
const hasMultiLeg = selections.some(sel => multiLegLabels.includes(sel.label));
if (hasMultiLeg) {
multiLegLabels.forEach(label => blockLabels.add(label));
}
}
return blockLabels;
@ -71,14 +77,14 @@ export class LabelRestrictionService {
): boolean {
const boxedLabels = new Set(['FRP', 'QNP', 'TNP']);
// check finalized selections
// Check finalized selections
for (const s of selections) {
if (s && s.label && boxedLabels.has(s.label) && !!s.isBoxed) {
return true;
}
}
// check the in-progress/current row if provided
// Check the in-progress/current row if provided
if (current && current.label && boxedLabels.has(String(current.label)) && !!current.isBoxed) {
return true;
}

View File

@ -53,7 +53,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
maxRowsReached: boolean = false;
totalAmountLimitReached: boolean = false;
showLimitPopup: boolean = false;
disabledLabels: string[] = ['SHW', 'SJP', '.','EXA'];
disabledLabels: string[] = ['SHW', 'SJP', '.', 'EXA'];
private hasFinalizedMultiLeg: boolean = false; // Tracks if a multi-leg pool is finalized
// TNP logic
tanGroupStage = 0;
@ -113,7 +114,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
) {}
ngOnInit() {
// Always prefer rpinfo.structuredRaceCard if present, else fall back to raceCardData key (but still use only structuredRaceCard content)
// Always prefer rpinfo.structuredRaceCard if present, else fall back to raceCardData key
const rpinfo = this.safeGetJSON('rpinfo');
if (rpinfo && rpinfo.structuredRaceCard) {
this.structuredRaceCard = rpinfo.structuredRaceCard;
@ -145,7 +146,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
this.selectionsSubscription = this.selectionService.selections$.subscribe((selections: SelectionData[]) => {
this.currentSelections = selections;
this.maxRowsReached = selections.length >= 5;
// Update maxRowsReached to account for multi-leg finalization
this.maxRowsReached = this.hasFinalizedMultiLeg || selections.length >= 5;
const totalAmount = selections.reduce((sum: number, selection: SelectionData) => sum + (selection.total || 0), 0);
this.totalAmountLimitReached = totalAmount >= 5000;
this.refreshBlockedLabels(this.selectedLabel);
@ -175,7 +177,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
this.cdr.markForCheck();
});
// Keep raw storage copy if present (but all logic below uses structuredRaceCard)
// Keep raw storage copy if present
const data = localStorage.getItem('raceCardData');
if (data) {
try { this.raceCardData = JSON.parse(data); } catch { this.raceCardData = this.raceCardData || {}; }
@ -442,6 +444,12 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
return;
}
// Prevent selecting multi-leg labels if one is already finalized
if (this.hasFinalizedMultiLeg && this.multiLegLabels.includes(label)) {
console.log('[DEBUG] Cannot select another multi-leg pool until selections are cleared');
return;
}
this.selectedLabel = label;
this.selectedNumbers = [];
this.padValue = '';
@ -497,7 +505,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
this.selectionService.finalizeCurrentRow();
const currentSelections = this.selectionService.getSelections();
const existingWSP = currentSelections.filter(sel => wspLabels.includes(sel.label));
if (existingWSP.length === 0) {
if (existingWSP.length === 0 && !this.hasFinalizedMultiLeg) {
const blankRows = wspLabels.map(lbl => ({
label: lbl,
numbers: [],
@ -704,7 +712,17 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
}
onPadEnter() {
if (this.maxRowsReached) return;
if (this.maxRowsReached || this.hasFinalizedMultiLeg) return;
// Prevent ENTER action for multi-leg pools if current row already has a value.
// This ensures "Enter" won't re-run and cause race/leg selection clashes once the value is set.
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
const currentRow = this.selectionService.getCurrentRow();
if (currentRow && typeof currentRow.value === 'number' && currentRow.value > 0) {
// do nothing (ENTER is disabled for multi-leg after entering one value)
return;
}
}
if (!this.canPrint) {
this.print();
@ -716,7 +734,6 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
const targetLabel = labels[this.wspTicketStage];
const selections = this.selectionService.getSelections();
// Find the current WSP row to ensure numbers are synchronized
const currentWSPRow = selections.find(sel => sel.label === targetLabel);
if (currentWSPRow) {
this.selectedNumbers = [...currentWSPRow.numbers];
@ -734,7 +751,6 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
// Call after setSelections
this.refreshBlockedLabels(this.selectedLabel);
// Only increment stage if not at the last stage (PLP)
if (this.wspTicketStage < 2) {
this.wspTicketStage++;
// Update selectedNumbers for the next stage
@ -981,7 +997,10 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
}
updateCanPrint() {
if (this.maxRowsReached) { this.canPrint = false; return; }
if (this.maxRowsReached || this.hasFinalizedMultiLeg) {
this.canPrint = false;
return;
}
this.canPrint = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue);
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
const maxLegs = this.getMaxLegs(this.currentPool || '');
@ -991,19 +1010,17 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
// Add this getter for print button enable logic
get canPrintTicket(): boolean {
// At least one valid row in finalized selections or current row
const selections = this.selectionService.getSelections();
const currentRow = this.selectionService.getCurrentRow();
if (this.selectedLabel === 'WSP') {
// For WSP, require all three rows (WNP, SHP, PLP) to have valid numbers and values >= 1
const wspLabels = ['WNP', 'SHP', 'PLP'];
const wspSelections = selections.filter(sel => wspLabels.includes(sel.label));
const wspSelections = this.selectionService.getSelections().filter(sel => wspLabels.includes(sel.label));
const allWSPRowsValid = wspSelections.length === 3 && wspSelections.every(row =>
row.label && row.numbers && row.numbers.length > 0 && row.value >= 1 && row.total > 0
);
return this.wspTicketStage === 2 && allWSPRowsValid;
}
// For non-WSP, keep existing logic: any valid row enables printing
const selections = this.selectionService.getSelections();
const currentRow = this.selectionService.getCurrentRow();
const hasValidRow = selections.some(
row => !!row.label && !!row.numbers && row.numbers.length > 0 && row.value > 0 && row.total > 0
) || (
@ -1012,9 +1029,49 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
return Boolean(hasValidRow);
}
// ---------- Updated canEnterRow getter ----------
get canEnterRow(): boolean {
if (this.maxRowsReached) return false;
// If multi-leg pool (TBP/MJP/JPP): disable "Enter" once a value is already recorded
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
const currentRow = this.selectionService.getCurrentRow();
// If a value already entered (>0) then Enter should be disabled; only PRINT allowed.
if (currentRow && typeof currentRow.value === 'number' && currentRow.value > 0) {
return false;
}
// Otherwise allow Enter only when value is valid (1..100) and numbers exist
return !!currentRow.label &&
!!currentRow.numbers &&
currentRow.numbers.length > 0 &&
typeof currentRow.value === 'number' &&
currentRow.value >= 1 &&
currentRow.value <= 100 &&
currentRow.total > 0;
}
// WSP special-case (existing behavior)
if (this.selectedLabel === 'WSP') {
const isValidPadValue = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue);
const hasNumbers = this.selectedNumbers.length > 0;
return isValidPadValue && hasNumbers;
}
// Default logic for non-multi, non-WSP labels
const currentRow = this.selectionService.getCurrentRow();
return !!currentRow.label &&
!!currentRow.numbers &&
currentRow.numbers.length > 0 &&
typeof currentRow.value === 'number' &&
currentRow.value >= 1 &&
currentRow.value <= 100 &&
currentRow.total > 0;
}
print() {
const selectionsTotal = this.currentSelections.reduce((sum, sel) => sum + (sel.total || 0), 0);
let currentRowAmount = 0;
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
const maxLegs = this.getMaxLegs(this.currentPool || '');
const horsesPerLeg = this.multiLegGroups.map((group, index) => {
@ -1032,6 +1089,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
}
// Ensure all legs have selections
if (horsesPerLeg.some(count => count === 0)) return;
this.hasFinalizedMultiLeg = true; // Mark multi-leg pool as finalized
} else {
currentRowAmount = this.currentTotal;
if (selectionsTotal + currentRowAmount > 5000) {
@ -1098,7 +1156,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
if (allRows.length === 0) {
console.warn("No valid rows to print.");
this.cdr.markForCheck(); // <-- Ensure UI updates
this.cdr.markForCheck();
return;
}
@ -1184,7 +1242,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
}
let numbersStr = '';
if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
if (row.isBoxed) {
// Keep only numeric tokens; stringify when comparing to '#' to avoid number vs string compare.
const actualNumbers = displayNumbers
@ -1206,11 +1264,10 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
// case: TNP but not boxed (falls through here). Use string comparisons consistently.
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
}
} else {
} else {
// Default: non-FRP/QNP/TNP labels
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
}
}
const label = displayLabel.padEnd(10);
const numbers = numbersStr.padEnd(15);
@ -1231,7 +1288,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
return legs.join('/');
}
// helper to pad ticket count to 3 digits (001..999)
// helper to pad ticket count to 3 digits (001..999)
function padTicketCountToThree(n: number) {
const num = Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
return String(num).padStart(3, '0');
@ -1458,15 +1515,28 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
console.log('Printer payload:', payload);
fetch('http://localhost:9100/print', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
// ---------------------sending data to backend ---------------------------------
.then(response => {
if (!response.ok) {
throw new Error(`Printer error: ${response.status}`);
}
return response.text();
})
.then(result => {
console.log("✅ Print successful:", result);
this.erase();
})
.catch(error => {
console.error("❌ Print failed:", error);
this.erase();
});
try {
const existingTicketsStr = localStorage.getItem('localTickets');
const existingTickets = existingTicketsStr ? JSON.parse(existingTicketsStr) : [];
@ -1542,6 +1612,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
erase() {
this.selectionService.clearSelections();
this.resetSelections();
this.hasFinalizedMultiLeg = false; // Reset multi-leg finalization flag
this.refreshBlockedLabels(null);
this.cdr.markForCheck();
}
@ -1568,7 +1639,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
this.fieldInput = '';
this.fieldFEntered = false;
this.wspTicketStage = 0;
// Explicitly reset blocked labels (no current label)
this.hasFinalizedMultiLeg = false; // Reset multi-leg finalization flag
this.refreshBlockedLabels(null);
this.updateCanPrint();
this.sharedStateService.updateSharedData({ type: 'multiLegPoolEnd', value: null });
@ -2002,25 +2073,6 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
get dedupedEnabledHorseNumbers(): number[] {
return _.uniq(this.enabledHorseNumbers);
}
// Update canEnterRow to require value between 1 and 100
get canEnterRow(): boolean {
if (this.maxRowsReached) return false;
if (this.selectedLabel === 'WSP') {
const isValidPadValue = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue);
const hasNumbers = this.selectedNumbers.length > 0;
return isValidPadValue && hasNumbers;
}
// Default logic for non-WSP
const currentRow = this.selectionService.getCurrentRow();
return !!currentRow.label &&
!!currentRow.numbers &&
currentRow.numbers.length > 0 &&
typeof currentRow.value === 'number' &&
currentRow.value >= 1 &&
currentRow.value <= 100 &&
currentRow.total > 0;
}
// add this in the component class (near other helpers)
private refreshBlockedLabels(currentLabel?: string | null) {
// Pass finalized selections and optionally the in-progress/current label