fix : added restriction for the multileg pools (row)
This commit is contained in:
parent
148de807f7
commit
102b6d57df
@ -1,4 +1,3 @@
|
|||||||
// label-restriction.service.ts
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { SelectionData } from '../selection.service/selection.service';
|
import { SelectionData } from '../selection.service/selection.service';
|
||||||
|
|
||||||
@ -22,15 +21,16 @@ export class LabelRestrictionService {
|
|||||||
// accept optional currentLabel
|
// accept optional currentLabel
|
||||||
getBlockedLabels(selections: SelectionData[], currentLabel?: string | null): Set<string> {
|
getBlockedLabels(selections: SelectionData[], currentLabel?: string | null): Set<string> {
|
||||||
const selectedGroups = new Set<string>();
|
const selectedGroups = new Set<string>();
|
||||||
|
const multiLegLabels = ['TBP', 'MJP', 'JPP'];
|
||||||
|
|
||||||
// existing finalized selections
|
// Existing finalized selections
|
||||||
for (const row of selections) {
|
for (const row of selections) {
|
||||||
if (row.label && LABEL_TO_GROUP[row.label]) {
|
if (row.label && LABEL_TO_GROUP[row.label]) {
|
||||||
selectedGroups.add(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]) {
|
if (currentLabel && LABEL_TO_GROUP[currentLabel]) {
|
||||||
selectedGroups.add(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;
|
return blockLabels;
|
||||||
@ -71,14 +77,14 @@ export class LabelRestrictionService {
|
|||||||
): boolean {
|
): boolean {
|
||||||
const boxedLabels = new Set(['FRP', 'QNP', 'TNP']);
|
const boxedLabels = new Set(['FRP', 'QNP', 'TNP']);
|
||||||
|
|
||||||
// check finalized selections
|
// Check finalized selections
|
||||||
for (const s of selections) {
|
for (const s of selections) {
|
||||||
if (s && s.label && boxedLabels.has(s.label) && !!s.isBoxed) {
|
if (s && s.label && boxedLabels.has(s.label) && !!s.isBoxed) {
|
||||||
return true;
|
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) {
|
if (current && current.label && boxedLabels.has(String(current.label)) && !!current.isBoxed) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,8 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
maxRowsReached: boolean = false;
|
maxRowsReached: boolean = false;
|
||||||
totalAmountLimitReached: boolean = false;
|
totalAmountLimitReached: boolean = false;
|
||||||
showLimitPopup: 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
|
// TNP logic
|
||||||
tanGroupStage = 0;
|
tanGroupStage = 0;
|
||||||
@ -113,7 +114,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
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');
|
const rpinfo = this.safeGetJSON('rpinfo');
|
||||||
if (rpinfo && rpinfo.structuredRaceCard) {
|
if (rpinfo && rpinfo.structuredRaceCard) {
|
||||||
this.structuredRaceCard = 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.selectionsSubscription = this.selectionService.selections$.subscribe((selections: SelectionData[]) => {
|
||||||
this.currentSelections = selections;
|
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);
|
const totalAmount = selections.reduce((sum: number, selection: SelectionData) => sum + (selection.total || 0), 0);
|
||||||
this.totalAmountLimitReached = totalAmount >= 5000;
|
this.totalAmountLimitReached = totalAmount >= 5000;
|
||||||
this.refreshBlockedLabels(this.selectedLabel);
|
this.refreshBlockedLabels(this.selectedLabel);
|
||||||
@ -175,7 +177,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
this.cdr.markForCheck();
|
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');
|
const data = localStorage.getItem('raceCardData');
|
||||||
if (data) {
|
if (data) {
|
||||||
try { this.raceCardData = JSON.parse(data); } catch { this.raceCardData = this.raceCardData || {}; }
|
try { this.raceCardData = JSON.parse(data); } catch { this.raceCardData = this.raceCardData || {}; }
|
||||||
@ -410,10 +412,10 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
isNumberDisabled(number: number): boolean {
|
isNumberDisabled(number: number): boolean {
|
||||||
// Disable if number not present in actualRunners
|
// Disable if number not present in actualRunners
|
||||||
if (!this.actualRunners.has(number)) return true;
|
if (!this.actualRunners.has(number)) return true;
|
||||||
// Disable if total amount limit reached
|
// Disable if total amount limit reached
|
||||||
if (this.totalAmountLimitReached) return true;
|
if (this.totalAmountLimitReached) return true;
|
||||||
// Allow all numbers for TNP when boxed, but disable selected numbers
|
// Allow all numbers for TNP when boxed, but disable selected numbers
|
||||||
if (this.selectedLabel === 'TNP' && this.isBoxed) {
|
if (this.selectedLabel === 'TNP' && this.isBoxed) {
|
||||||
return this.selectedNumbers.includes(number);
|
return this.selectedNumbers.includes(number);
|
||||||
}
|
}
|
||||||
// TNP (unboxed): Disable numbers already selected in the current group
|
// TNP (unboxed): Disable numbers already selected in the current group
|
||||||
@ -442,6 +444,12 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
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.selectedLabel = label;
|
||||||
this.selectedNumbers = [];
|
this.selectedNumbers = [];
|
||||||
this.padValue = '';
|
this.padValue = '';
|
||||||
@ -497,7 +505,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
this.selectionService.finalizeCurrentRow();
|
this.selectionService.finalizeCurrentRow();
|
||||||
const currentSelections = this.selectionService.getSelections();
|
const currentSelections = this.selectionService.getSelections();
|
||||||
const existingWSP = currentSelections.filter(sel => wspLabels.includes(sel.label));
|
const existingWSP = currentSelections.filter(sel => wspLabels.includes(sel.label));
|
||||||
if (existingWSP.length === 0) {
|
if (existingWSP.length === 0 && !this.hasFinalizedMultiLeg) {
|
||||||
const blankRows = wspLabels.map(lbl => ({
|
const blankRows = wspLabels.map(lbl => ({
|
||||||
label: lbl,
|
label: lbl,
|
||||||
numbers: [],
|
numbers: [],
|
||||||
@ -704,7 +712,17 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onPadEnter() {
|
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) {
|
if (!this.canPrint) {
|
||||||
this.print();
|
this.print();
|
||||||
@ -715,8 +733,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
const labels = ['WNP', 'SHP', 'PLP'];
|
const labels = ['WNP', 'SHP', 'PLP'];
|
||||||
const targetLabel = labels[this.wspTicketStage];
|
const targetLabel = labels[this.wspTicketStage];
|
||||||
const selections = this.selectionService.getSelections();
|
const selections = this.selectionService.getSelections();
|
||||||
// Find the current WSP row to ensure numbers are synchronized
|
// Find the current WSP row to ensure numbers are synchronized
|
||||||
|
|
||||||
const currentWSPRow = selections.find(sel => sel.label === targetLabel);
|
const currentWSPRow = selections.find(sel => sel.label === targetLabel);
|
||||||
if (currentWSPRow) {
|
if (currentWSPRow) {
|
||||||
this.selectedNumbers = [...currentWSPRow.numbers];
|
this.selectedNumbers = [...currentWSPRow.numbers];
|
||||||
@ -733,11 +750,10 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
this.selectionService.setSelections(updatedSelections);
|
this.selectionService.setSelections(updatedSelections);
|
||||||
// Call after setSelections
|
// Call after setSelections
|
||||||
this.refreshBlockedLabels(this.selectedLabel);
|
this.refreshBlockedLabels(this.selectedLabel);
|
||||||
// Only increment stage if not at the last stage (PLP)
|
// Only increment stage if not at the last stage (PLP)
|
||||||
|
|
||||||
if (this.wspTicketStage < 2) {
|
if (this.wspTicketStage < 2) {
|
||||||
this.wspTicketStage++;
|
this.wspTicketStage++;
|
||||||
// Update selectedNumbers for the next stage
|
// Update selectedNumbers for the next stage
|
||||||
const nextLabel = labels[this.wspTicketStage];
|
const nextLabel = labels[this.wspTicketStage];
|
||||||
const nextWSPRow = updatedSelections.find(sel => sel.label === nextLabel);
|
const nextWSPRow = updatedSelections.find(sel => sel.label === nextLabel);
|
||||||
if (nextWSPRow) this.selectedNumbers = [...nextWSPRow.numbers];
|
if (nextWSPRow) this.selectedNumbers = [...nextWSPRow.numbers];
|
||||||
@ -981,7 +997,10 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateCanPrint() {
|
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);
|
this.canPrint = this.padValue.trim().length > 0 && /^[0-9]+$/.test(this.padValue);
|
||||||
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
|
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
|
||||||
const maxLegs = this.getMaxLegs(this.currentPool || '');
|
const maxLegs = this.getMaxLegs(this.currentPool || '');
|
||||||
@ -991,19 +1010,17 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Add this getter for print button enable logic
|
// Add this getter for print button enable logic
|
||||||
get canPrintTicket(): boolean {
|
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') {
|
if (this.selectedLabel === 'WSP') {
|
||||||
// For WSP, require all three rows (WNP, SHP, PLP) to have valid numbers and values >= 1
|
// For WSP, require all three rows (WNP, SHP, PLP) to have valid numbers and values >= 1
|
||||||
const wspLabels = ['WNP', 'SHP', 'PLP'];
|
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 =>
|
const allWSPRowsValid = wspSelections.length === 3 && wspSelections.every(row =>
|
||||||
row.label && row.numbers && row.numbers.length > 0 && row.value >= 1 && row.total > 0
|
row.label && row.numbers && row.numbers.length > 0 && row.value >= 1 && row.total > 0
|
||||||
);
|
);
|
||||||
return this.wspTicketStage === 2 && allWSPRowsValid;
|
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(
|
const hasValidRow = selections.some(
|
||||||
row => !!row.label && !!row.numbers && row.numbers.length > 0 && row.value > 0 && row.total > 0
|
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);
|
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() {
|
print() {
|
||||||
const selectionsTotal = this.currentSelections.reduce((sum, sel) => sum + (sel.total || 0), 0);
|
const selectionsTotal = this.currentSelections.reduce((sum, sel) => sum + (sel.total || 0), 0);
|
||||||
let currentRowAmount = 0;
|
let currentRowAmount = 0;
|
||||||
|
|
||||||
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
|
if (this.multiLegLabels.includes(this.selectedLabel || '')) {
|
||||||
const maxLegs = this.getMaxLegs(this.currentPool || '');
|
const maxLegs = this.getMaxLegs(this.currentPool || '');
|
||||||
const horsesPerLeg = this.multiLegGroups.map((group, index) => {
|
const horsesPerLeg = this.multiLegGroups.map((group, index) => {
|
||||||
@ -1032,6 +1089,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
// Ensure all legs have selections
|
// Ensure all legs have selections
|
||||||
if (horsesPerLeg.some(count => count === 0)) return;
|
if (horsesPerLeg.some(count => count === 0)) return;
|
||||||
|
this.hasFinalizedMultiLeg = true; // Mark multi-leg pool as finalized
|
||||||
} else {
|
} else {
|
||||||
currentRowAmount = this.currentTotal;
|
currentRowAmount = this.currentTotal;
|
||||||
if (selectionsTotal + currentRowAmount > 5000) {
|
if (selectionsTotal + currentRowAmount > 5000) {
|
||||||
@ -1098,7 +1156,7 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (allRows.length === 0) {
|
if (allRows.length === 0) {
|
||||||
console.warn("No valid rows to print.");
|
console.warn("No valid rows to print.");
|
||||||
this.cdr.markForCheck(); // <-- Ensure UI updates
|
this.cdr.markForCheck();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1183,34 +1241,33 @@ export class TouchPadMenuComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let numbersStr = '';
|
let numbersStr = '';
|
||||||
if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
||||||
if (row.isBoxed) {
|
if (row.isBoxed) {
|
||||||
// Keep only numeric tokens; stringify when comparing to '#' to avoid number vs string compare.
|
// Keep only numeric tokens; stringify when comparing to '#' to avoid number vs string compare.
|
||||||
const actualNumbers = displayNumbers
|
const actualNumbers = displayNumbers
|
||||||
.filter((n): n is number => typeof n === 'number' && String(n) !== '#')
|
.filter((n): n is number => typeof n === 'number' && String(n) !== '#')
|
||||||
.map(n => String(n).padStart(2, '0'))
|
.map(n => String(n).padStart(2, '0'))
|
||||||
.join(',');
|
.join(',');
|
||||||
numbersStr = `<<${actualNumbers}>>`;
|
numbersStr = `<<${actualNumbers}>>`;
|
||||||
} else if (['FRP', 'QNP'].includes(row.label)) {
|
} else if (['FRP', 'QNP'].includes(row.label)) {
|
||||||
// Convert every token to string for safe comparisons and joining.
|
// Convert every token to string for safe comparisons and joining.
|
||||||
const actualNumbers = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
const actualNumbers = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
||||||
// Safe check for '#' presence in row.numbers by stringifying elements
|
// Safe check for '#' presence in row.numbers by stringifying elements
|
||||||
const rowHasHash = Array.isArray(row.numbers) && row.numbers.some(x => String(x) === '#');
|
const rowHasHash = Array.isArray(row.numbers) && row.numbers.some(x => String(x) === '#');
|
||||||
if (rowHasHash || row.isBoxed) {
|
if (rowHasHash || row.isBoxed) {
|
||||||
numbersStr = `${actualNumbers} - ${actualNumbers}`;
|
numbersStr = `${actualNumbers} - ${actualNumbers}`;
|
||||||
} else {
|
} else {
|
||||||
numbersStr = actualNumbers;
|
numbersStr = actualNumbers;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// case: TNP but not boxed (falls through here). Use string comparisons consistently.
|
// case: TNP but not boxed (falls through here). Use string comparisons consistently.
|
||||||
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Default: non-FRP/QNP/TNP labels
|
// Default: non-FRP/QNP/TNP labels
|
||||||
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
numbersStr = displayNumbers.map(n => String(n)).filter(s => s !== '#').join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const label = displayLabel.padEnd(10);
|
const label = displayLabel.padEnd(10);
|
||||||
const numbers = numbersStr.padEnd(15);
|
const numbers = numbersStr.padEnd(15);
|
||||||
@ -1231,7 +1288,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
return legs.join('/');
|
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) {
|
function padTicketCountToThree(n: number) {
|
||||||
const num = Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
|
const num = Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
|
||||||
return String(num).padStart(3, '0');
|
return String(num).padStart(3, '0');
|
||||||
@ -1276,14 +1333,14 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
return `${label} ${groupStrs.join('-')}${starPart}`;
|
return `${label} ${groupStrs.join('-')}${starPart}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 NEW RULE: check for "- -" style duplicate groups
|
// 🔹 NEW RULE: check for "- -" style duplicate groups
|
||||||
if (filteredGroups.length === 2) {
|
if (filteredGroups.length === 2) {
|
||||||
const g1 = filteredGroups[0].map(normalizeToken);
|
const g1 = filteredGroups[0].map(normalizeToken);
|
||||||
const g2 = filteredGroups[1].map(normalizeToken);
|
const g2 = filteredGroups[1].map(normalizeToken);
|
||||||
if (g1.join(',') === g2.join(',')) {
|
if (g1.join(',') === g2.join(',')) {
|
||||||
return `${label} <<${g1.join(',')}>>${starPart}`;
|
return `${label} <<${g1.join(',')}>>${starPart}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleTokens = filteredGroups[0] || [];
|
const singleTokens = filteredGroups[0] || [];
|
||||||
if (singleTokens.length >= 2 && singleTokens.length % 2 === 0) {
|
if (singleTokens.length >= 2 && singleTokens.length % 2 === 0) {
|
||||||
@ -1458,14 +1515,27 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
|
|
||||||
console.log('Printer payload:', payload);
|
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 ---------------------------------
|
||||||
|
|
||||||
fetch('http://localhost:9100/print', {
|
.then(response => {
|
||||||
method: 'POST',
|
if (!response.ok) {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
throw new Error(`Printer error: ${response.status}`);
|
||||||
body: JSON.stringify(payload)
|
}
|
||||||
})
|
return response.text();
|
||||||
|
})
|
||||||
// ---------------------sending data to backend ---------------------------------
|
.then(result => {
|
||||||
|
console.log("✅ Print successful:", result);
|
||||||
|
this.erase();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("❌ Print failed:", error);
|
||||||
|
this.erase();
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const existingTicketsStr = localStorage.getItem('localTickets');
|
const existingTicketsStr = localStorage.getItem('localTickets');
|
||||||
@ -1542,6 +1612,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
erase() {
|
erase() {
|
||||||
this.selectionService.clearSelections();
|
this.selectionService.clearSelections();
|
||||||
this.resetSelections();
|
this.resetSelections();
|
||||||
|
this.hasFinalizedMultiLeg = false; // Reset multi-leg finalization flag
|
||||||
this.refreshBlockedLabels(null);
|
this.refreshBlockedLabels(null);
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
}
|
}
|
||||||
@ -1568,7 +1639,7 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
this.fieldInput = '';
|
this.fieldInput = '';
|
||||||
this.fieldFEntered = false;
|
this.fieldFEntered = false;
|
||||||
this.wspTicketStage = 0;
|
this.wspTicketStage = 0;
|
||||||
// Explicitly reset blocked labels (no current label)
|
this.hasFinalizedMultiLeg = false; // Reset multi-leg finalization flag
|
||||||
this.refreshBlockedLabels(null);
|
this.refreshBlockedLabels(null);
|
||||||
this.updateCanPrint();
|
this.updateCanPrint();
|
||||||
this.sharedStateService.updateSharedData({ type: 'multiLegPoolEnd', value: null });
|
this.sharedStateService.updateSharedData({ type: 'multiLegPoolEnd', value: null });
|
||||||
@ -2002,25 +2073,6 @@ if (['FRP', 'QNP', 'TNP'].includes(row.label)) {
|
|||||||
get dedupedEnabledHorseNumbers(): number[] {
|
get dedupedEnabledHorseNumbers(): number[] {
|
||||||
return _.uniq(this.enabledHorseNumbers);
|
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)
|
// add this in the component class (near other helpers)
|
||||||
private refreshBlockedLabels(currentLabel?: string | null) {
|
private refreshBlockedLabels(currentLabel?: string | null) {
|
||||||
// Pass finalized selections and optionally the in-progress/current label
|
// Pass finalized selections and optionally the in-progress/current label
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user