fix : race card fetching from the server and working
This commit is contained in:
parent
5974bf5535
commit
b680150a88
@ -19,20 +19,19 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
private subscription!: Subscription;
|
private subscription!: Subscription;
|
||||||
userName: string = '';
|
userName: string = '';
|
||||||
btid: string | null = null;
|
btid: string | null = null;
|
||||||
|
|
||||||
liveStatusOk: boolean = true;
|
liveStatusOk: boolean = true;
|
||||||
|
|
||||||
showVenueModal = false;
|
showVenueModal = false;
|
||||||
showRaceModal = false;
|
showRaceModal = false;
|
||||||
selectedVenue = 'Select Venue';
|
selectedVenue = 'Select Venue';
|
||||||
selectedRace: number = 1;
|
selectedRace: number = 1;
|
||||||
currentLegRaceDisplay: string = ''; // Display current leg's race or pool start
|
currentLegRaceDisplay: string = '';
|
||||||
|
|
||||||
showWalletModal = false;
|
showWalletModal = false;
|
||||||
showResultModal = false;
|
showResultModal = false;
|
||||||
showMessagesModal = false;
|
showMessagesModal = false;
|
||||||
showLogModal = false;
|
showLogModal = false;
|
||||||
raceCardData: any = {};
|
raceCardData: any = null;
|
||||||
raceData: any[] = [];
|
raceData: any[] = [];
|
||||||
objectKeys = Object.keys;
|
objectKeys = Object.keys;
|
||||||
|
|
||||||
@ -41,37 +40,19 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
multiLegBaseRaceIdx: number = 0;
|
multiLegBaseRaceIdx: number = 0;
|
||||||
currentPool: string | null = null;
|
currentPool: string | null = null;
|
||||||
|
|
||||||
private prevEnabledKey = ''; // For memoization
|
private prevEnabledKey = '';
|
||||||
|
|
||||||
wallet = {
|
wallet = { withdraw: 0, deposit: 0, payout: 0, cancel: 0, ticketing: 0, balance: 0 };
|
||||||
withdraw: 0,
|
|
||||||
deposit: 0,
|
|
||||||
payout: 0,
|
|
||||||
cancel: 0,
|
|
||||||
ticketing: 0,
|
|
||||||
balance: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
logs = [{
|
logs = [{ description: '', venue: '', ticketNumber: '', poolName: '', totalAmount: '' }];
|
||||||
description: '',
|
|
||||||
venue: '',
|
|
||||||
ticketNumber: '',
|
|
||||||
poolName: '',
|
|
||||||
totalAmount: '',
|
|
||||||
}];
|
|
||||||
|
|
||||||
messages: string[] = [
|
messages: string[] = ['System ready.', 'Please select a venue.', 'Races updated.', 'Live status stable.'];
|
||||||
'System ready.',
|
|
||||||
'Please select a venue.',
|
|
||||||
'Races updated.',
|
|
||||||
'Live status stable.',
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private btcService: BtcService,
|
private btcService: BtcService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private sharedStateService: SharedStateService,
|
private sharedStateService: SharedStateService,
|
||||||
private zone: NgZone // <-- Add NgZone
|
private zone: NgZone
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -79,30 +60,19 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
this.btid = localStorage.getItem('btid');
|
this.btid = localStorage.getItem('btid');
|
||||||
// Use NgZone to run setInterval outside Angular's change detection
|
// Use NgZone to run setInterval outside Angular's change detection
|
||||||
this.zone.runOutsideAngular(() => {
|
this.zone.runOutsideAngular(() => {
|
||||||
setInterval(() => {
|
setInterval(() => { this.zone.run(() => this.updateDateTime()); }, 1000);
|
||||||
this.zone.run(() => this.updateDateTime());
|
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.subscription = interval(5000)
|
this.subscription = interval(5000)
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(() =>
|
switchMap(() =>
|
||||||
this.btcService.pingLiveStatus().pipe(
|
this.btcService.pingLiveStatus().pipe(
|
||||||
catchError((error) => {
|
catchError((error) => { console.error('[LIVE STATUS] Ping failed:', error); this.liveStatusOk = false; return of(null); })
|
||||||
console.error('[LIVE STATUS] Ping failed:', error);
|
|
||||||
this.liveStatusOk = false;
|
|
||||||
return of(null);
|
|
||||||
})
|
|
||||||
))
|
))
|
||||||
).subscribe((response) => {
|
).subscribe((response) => {
|
||||||
if (response !== null) {
|
if (response !== null) { this.liveStatusOk = true; console.log('[LIVE STATUS] OK'); }
|
||||||
console.log('[LIVE STATUS] OK');
|
|
||||||
this.liveStatusOk = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.sharedStateService.sharedData$.subscribe(data => {
|
this.sharedStateService.sharedData$.subscribe(data => {
|
||||||
if (data.type === 'currentLegRace') {
|
if (data.type === 'currentLegRace') {
|
||||||
this.selectedRace = data.value;
|
this.selectedRace = data.value;
|
||||||
@ -117,11 +87,11 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
if (data.type === 'multiLegPoolStart') {
|
if (data.type === 'multiLegPoolStart') {
|
||||||
const { label, baseRaceIdx } = data.value;
|
const { label, baseRaceIdx } = data.value;
|
||||||
this.currentPool = label;
|
this.currentPool = this.normalizePoolName(label);
|
||||||
this.multiLegBaseRaceIdx = baseRaceIdx;
|
this.multiLegBaseRaceIdx = baseRaceIdx;
|
||||||
this.currentLegRaceDisplay = `Starting at Race ${baseRaceIdx} for ${label}`;
|
this.currentLegRaceDisplay = `Starting at Race ${baseRaceIdx} for ${this.currentPool}`;
|
||||||
this.updateEnabledHorseNumbersForMultiLeg(baseRaceIdx);
|
this.updateEnabledHorseNumbersForMultiLeg(baseRaceIdx);
|
||||||
console.log(`[Multi-leg Pool] Selected: ${label}, Base Race: ${baseRaceIdx}`);
|
console.log(`[Multi-leg Pool] Selected: ${this.currentPool}, Base Race: ${baseRaceIdx}`);
|
||||||
}
|
}
|
||||||
if (data.type === 'multiLegPoolEnd') {
|
if (data.type === 'multiLegPoolEnd') {
|
||||||
this.currentPool = null;
|
this.currentPool = null;
|
||||||
@ -137,115 +107,115 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
this.updateEnabledHorseNumbers();
|
this.updateEnabledHorseNumbers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.loadRaceCardData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private safeGetJSON(key: string): any | null {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(key);
|
||||||
|
if (!raw) return null;
|
||||||
|
return JSON.parse(raw);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`[safeGetJSON] failed parse ${key}`, err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadRaceCardData() {
|
||||||
|
const cached = this.safeGetJSON('rpinfo');
|
||||||
|
if (cached && cached.structuredRaceCard) {
|
||||||
|
this.raceCardData = cached.structuredRaceCard;
|
||||||
|
this.selectedVenue = this.raceCardData?.venue || 'Select Venue';
|
||||||
|
this.updateEnabledHorseNumbers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rc = this.safeGetJSON('raceCardData');
|
||||||
|
if (rc) {
|
||||||
|
this.raceCardData = rc;
|
||||||
|
this.selectedVenue = this.raceCardData?.venue || 'Select Venue';
|
||||||
|
this.updateEnabledHorseNumbers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.raceCardData = { error: 'Race card not available locally' };
|
||||||
|
this.selectedVenue = 'Select Venue';
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizePoolName(name: string | null | undefined): string | null {
|
||||||
|
if (!name) return null;
|
||||||
|
const n = String(name).toLowerCase();
|
||||||
|
if (n.startsWith('trb') || n.startsWith('tbp')) return n.includes('2') ? 'trb2' : 'trb1';
|
||||||
|
if (n.startsWith('mjp')) return n.includes('2') ? 'mjp2' : 'mjp1';
|
||||||
|
if (n.startsWith('jkp') || n.startsWith('jpp') || n.startsWith('jk')) return n.includes('2') ? 'jkp2' : 'jkp1';
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLegIndexForRace(poolName: string, race: number): number {
|
private getLegIndexForRace(poolName: string, race: number): number {
|
||||||
const raceMap: { [key: string]: number[] } = {
|
if (!this.raceCardData) return 0;
|
||||||
'mjp1': [1, 2, 3, 4],
|
const normalized = this.normalizePoolName(poolName) || poolName;
|
||||||
'jkp1': [3, 4, 5, 6, 7],
|
const poolMap: { [key: string]: number[] } = this.raceCardData?.pools || {};
|
||||||
'trb1': [2, 3, 4],
|
const arr = poolMap[normalized] || poolMap[poolName] || [];
|
||||||
'trb2': [5, 6, 7]
|
return arr.indexOf(race) >= 0 ? arr.indexOf(race) : 0;
|
||||||
};
|
|
||||||
return raceMap[poolName]?.indexOf(race) ?? 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateEnabledHorseNumbersForMultiLeg(baseRaceIdx: number) {
|
private updateEnabledHorseNumbersForMultiLeg(baseRaceIdx: number) {
|
||||||
const raceCardData = this.raceCardData?.raceVenueRaces?.races || [];
|
const racesArr = this.raceCardData?.raceVenueRaces?.races || [];
|
||||||
const legCount = this.getLegCountForLabel();
|
const legCount = this.getLegCountForLabel();
|
||||||
const key = `${this.currentPool}-${baseRaceIdx}-${legCount}`;
|
const poolKey = this.currentPool || '';
|
||||||
|
const key = `${poolKey}-${baseRaceIdx}-${legCount}`;
|
||||||
if (this.prevEnabledKey === key) return; // 🧠 Memoization
|
if (this.prevEnabledKey === key) return;
|
||||||
this.prevEnabledKey = key;
|
this.prevEnabledKey = key;
|
||||||
|
|
||||||
let combinedHorseNumbers: number[] = [];
|
let combinedHorseNumbers: number[] = [];
|
||||||
|
const raceIndices = Array.from({ length: legCount }, (_, i) => this.getRaceForLeg(poolKey, i) - 1);
|
||||||
const raceIndices = Array.from({ length: legCount }, (_, i) =>
|
|
||||||
this.getRaceForLeg(this.currentPool || '', i) - 1
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const raceIdx of raceIndices) {
|
for (const raceIdx of raceIndices) {
|
||||||
const race = raceCardData[raceIdx] || [];
|
const race = racesArr[raceIdx] || {};
|
||||||
if (Array.isArray(race)) {
|
if (Array.isArray(race.horses)) {
|
||||||
const horses = race
|
const horses = race.horses.filter((n: any) => typeof n === 'number' && n >= 1 && n <= 30);
|
||||||
.map((runner: any) => runner?.horseNumber)
|
|
||||||
.filter((n: number) => typeof n === 'number' && n >= 1 && n <= 30);
|
|
||||||
combinedHorseNumbers.push(...horses);
|
combinedHorseNumbers.push(...horses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enabledHorseNumbers = Array.from(new Set(combinedHorseNumbers));
|
this.enabledHorseNumbers = Array.from(new Set(combinedHorseNumbers));
|
||||||
|
this.sharedStateService.updateSharedData({ type: 'enabledHorseNumbers', value: this.enabledHorseNumbers });
|
||||||
this.sharedStateService.updateSharedData({
|
|
||||||
type: 'enabledHorseNumbers',
|
|
||||||
value: this.enabledHorseNumbers,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('[Multi-leg Pool] Updated enabled horse numbers:', this.enabledHorseNumbers);
|
console.log('[Multi-leg Pool] Updated enabled horse numbers:', this.enabledHorseNumbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLegCountForLabel(): number {
|
private getLegCountForLabel(): number {
|
||||||
switch (this.currentPool) {
|
const p = (this.currentPool || '').toLowerCase();
|
||||||
case 'mjp1': return 4;
|
switch (p) {
|
||||||
case 'jkp1': return 5;
|
case 'mjp1': case 'mjp2': return 4;
|
||||||
case 'trb1':
|
case 'jkp1': case 'jkp2': return 5;
|
||||||
case 'trb2': return 3;
|
case 'trb1': case 'trb2': return 3;
|
||||||
default: return 3;
|
default: return 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRaceForLeg(poolName: string, leg: number): number {
|
private getRaceForLeg(poolName: string, leg: number): number {
|
||||||
const raceMap: { [key: string]: number[] } = {
|
const normalized = this.normalizePoolName(poolName) || poolName;
|
||||||
'mjp1': [1, 2, 3, 4],
|
const poolMap: { [key: string]: number[] } = this.raceCardData?.pools || {};
|
||||||
'jkp1': [3, 4, 5, 6, 7],
|
const arr = poolMap[normalized] || poolMap[poolName] || [];
|
||||||
'trb1': [2, 3, 4],
|
if (arr.length > leg) return arr[leg];
|
||||||
'trb2': [5, 6, 7]
|
return (this.multiLegBaseRaceIdx || 1) + leg;
|
||||||
};
|
|
||||||
return raceMap[poolName]?.[leg] || (this.multiLegBaseRaceIdx + leg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDateTime() {
|
updateDateTime() { this.dateTime = new Date().toLocaleString(); }
|
||||||
const now = new Date();
|
|
||||||
this.dateTime = now.toLocaleString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(event: any) {
|
onResize(event: any) {
|
||||||
this.screenWidth = event.target.innerWidth;
|
this.screenWidth = event.target.innerWidth;
|
||||||
if (this.screenWidth > 800) {
|
if (this.screenWidth > 800) this.isMenuOpen = false;
|
||||||
this.isMenuOpen = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleMenu() {
|
toggleMenu() { this.isMenuOpen = !this.isMenuOpen; }
|
||||||
this.isMenuOpen = !this.isMenuOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
openVenueModal() {
|
openVenueModal() { this.loadRaceCardData(); this.showVenueModal = true; }
|
||||||
|
|
||||||
const cachedData = localStorage.getItem('raceCardData');
|
|
||||||
if (cachedData) {
|
|
||||||
this.raceCardData = JSON.parse(cachedData);
|
|
||||||
// console.log('📦 Loaded race card from localStorage:', this.raceCardData); // comment out for perf
|
|
||||||
this.selectedVenue = this.raceCardData?.Venue || 'Select Venue';
|
|
||||||
this.updateEnabledHorseNumbers();
|
|
||||||
} else {
|
|
||||||
this.raceCardData = { raceVenueRaces: { races: [] }, pools: {} };
|
|
||||||
// console.warn('⚠️ No race card data found in localStorage.'); // comment out for perf
|
|
||||||
}
|
|
||||||
console.log('[MODAL] Opening venue modal');
|
|
||||||
this.showVenueModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
openRaceModal() {
|
openRaceModal() {
|
||||||
console.log('[MODAL] Opening race modal');
|
|
||||||
this.showRaceModal = true;
|
this.showRaceModal = true;
|
||||||
|
const race = this.raceCardData?.raceVenueRaces?.races?.[this.selectedRaceId];
|
||||||
const venueIndex = Object.keys(this.raceCardData?.raceVenueRaces?.races || [])
|
this.raceData = race ? (race.horses || []) : [];
|
||||||
.findIndex((_, idx) => idx === this.selectedRaceId);
|
|
||||||
|
|
||||||
if (venueIndex !== -1) {
|
|
||||||
this.raceData = this.raceCardData.raceVenueRaces.races[venueIndex] || [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closeModals() {
|
closeModals() {
|
||||||
@ -259,16 +229,9 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectVenue(index: number) {
|
selectVenue(index: number) {
|
||||||
const venue = this.raceCardData?.Venue || 'Unknown Venue';
|
this.selectedVenue = this.raceCardData?.venue || 'Unknown Venue';
|
||||||
this.selectedVenue = venue;
|
|
||||||
this.selectedRaceId = index;
|
this.selectedRaceId = index;
|
||||||
|
this.sharedStateService.updateSharedData({ type: 'selectedVenue', value: this.selectedVenue });
|
||||||
this.sharedStateService.updateSharedData({
|
|
||||||
type: 'selectedVenue',
|
|
||||||
value: this.selectedVenue,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('[VENUE] Venue resolved to:', this.selectedVenue);
|
|
||||||
this.closeModals();
|
this.closeModals();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,244 +240,103 @@ export class NavbarComponent implements OnInit, OnDestroy {
|
|||||||
this.currentPool = null;
|
this.currentPool = null;
|
||||||
this.multiLegBaseRaceIdx = 0;
|
this.multiLegBaseRaceIdx = 0;
|
||||||
this.currentLegRaceDisplay = '';
|
this.currentLegRaceDisplay = '';
|
||||||
|
this.sharedStateService.updateSharedData({ type: 'selectedRace', value: this.selectedRace });
|
||||||
|
|
||||||
this.sharedStateService.updateSharedData({
|
const raceData = this.raceCardData?.raceVenueRaces?.races?.[race - 1] || {};
|
||||||
type: 'selectedRace',
|
const runnerCount = Array.isArray(raceData.horses) ? raceData.horses.length : (raceData.runners?.length || 12);
|
||||||
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.sharedStateService.setRunnerCount(runnerCount);
|
||||||
this.updateEnabledHorseNumbers();
|
this.updateEnabledHorseNumbers();
|
||||||
|
|
||||||
console.log('[RACE] Race selected:', this.selectedRace, '| Runner count:', runnerCount);
|
|
||||||
this.closeModals();
|
this.closeModals();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEnabledHorseNumbers() {
|
updateEnabledHorseNumbers() {
|
||||||
const raceIndex = this.selectedRace - 1;
|
const raceIndex = this.selectedRace - 1;
|
||||||
const race = this.raceCardData?.raceVenueRaces?.races?.[raceIndex];
|
const race = this.raceCardData?.raceVenueRaces?.races?.[raceIndex] || {};
|
||||||
|
let horses: any[] = [];
|
||||||
|
|
||||||
if (Array.isArray(race)) {
|
if (Array.isArray(race?.horses)) horses = race.horses;
|
||||||
this.enabledHorseNumbers = race
|
else if (Array.isArray(race?.runners)) horses = race.runners.map((r: any) => r.number ?? r);
|
||||||
.map((runner: any) => runner?.horseNumber)
|
else if (Array.isArray(race)) horses = race;
|
||||||
.filter((n: any) => typeof n === 'number' && n >= 1 && n <= 30);
|
|
||||||
} else {
|
|
||||||
this.enabledHorseNumbers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sharedStateService.updateSharedData({
|
|
||||||
type: 'enabledHorseNumbers',
|
|
||||||
value: this.enabledHorseNumbers,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
this.enabledHorseNumbers = horses.map((n: any) => Number(n)).filter((n: number) => !Number.isNaN(n) && n >= 1 && n <= 30);
|
||||||
|
this.sharedStateService.updateSharedData({ type: 'enabledHorseNumbers', value: this.enabledHorseNumbers });
|
||||||
console.log('[HORSE NUMBERS] Enabled horse numbers:', this.enabledHorseNumbers);
|
console.log('[HORSE NUMBERS] Enabled horse numbers:', this.enabledHorseNumbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectHorseNumber(number: number) {
|
selectHorseNumber(number: number) { console.log('[HORSE] Selected horse number:', number); }
|
||||||
console.log('[HORSE] Selected horse number:', number);
|
|
||||||
}
|
|
||||||
|
|
||||||
openWalletModal() {
|
openWalletModal() { this.showWalletModal = true; }
|
||||||
console.log('[MODAL] Opening wallet modal');
|
openResultModal() { this.showResultModal = true; }
|
||||||
this.showWalletModal = true;
|
openMessagesModal() { this.showMessagesModal = true; }
|
||||||
}
|
openLogModal() { this.showLogModal = true; }
|
||||||
|
|
||||||
openResultModal() {
|
formattedTicketLogs: any[] = [];
|
||||||
console.log('[MODAL] Opening result modal');
|
|
||||||
this.showResultModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
openMessagesModal() {
|
openViewLog() {
|
||||||
console.log('[MODAL] Opening messages modal');
|
const storedTickets = localStorage.getItem('localTicketsViewlog');
|
||||||
this.showMessagesModal = true;
|
if (!storedTickets) { this.formattedTicketLogs = []; this.showLogModal = true; return; }
|
||||||
}
|
|
||||||
|
|
||||||
openLogModal() {
|
|
||||||
console.log('[MODAL] Opening log modal');
|
|
||||||
this.showLogModal = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// formattedTicketLogs: {
|
|
||||||
// label: string;
|
|
||||||
// numbers: number[];
|
|
||||||
// count: number;
|
|
||||||
// amount: number;
|
|
||||||
// }[] = [];
|
|
||||||
formattedTicketLogs: {
|
|
||||||
pool: string;
|
|
||||||
horses: string;
|
|
||||||
horsesArray: string[][];
|
|
||||||
ticketCountLabel: string;
|
|
||||||
price: string;
|
|
||||||
numbers: number[];
|
|
||||||
count: number;
|
|
||||||
amount: number;
|
|
||||||
maskedBarcode: string;
|
|
||||||
displayBarcode: string;
|
|
||||||
}[] = [];
|
|
||||||
|
|
||||||
openViewLog() {
|
|
||||||
const storedTickets = localStorage.getItem('localTicketsViewlog');
|
|
||||||
|
|
||||||
if (storedTickets) {
|
|
||||||
const tickets = JSON.parse(storedTickets);
|
const tickets = JSON.parse(storedTickets);
|
||||||
|
this.formattedTicketLogs = tickets.map((ticket: any) => {
|
||||||
this.formattedTicketLogs = tickets.map((ticket: any, index: number) => {
|
|
||||||
const rawLabel = ticket.winLabels?.trim() || '';
|
const rawLabel = ticket.winLabels?.trim() || '';
|
||||||
const numbers = ticket.numbers || [];
|
const barcodeId = ticket.barcodeId || '';
|
||||||
const count = ticket.ticketCount || 0;
|
let pool = '', horses = '', horsesArray: string[][] = [], ticketCountLabel = '', price = '', maskedBarcode = '', displayBarcode = '';
|
||||||
const amount = ticket.totalAmount || 0;
|
|
||||||
const barcodeId = ticket.barcodeId || '';
|
|
||||||
let pool = '', horses = '', horsesArray: string[][] = [], ticketCountLabel = '', price = '', maskedBarcode = '' , displayBarcode = '';
|
|
||||||
|
|
||||||
if (rawLabel) {
|
if (rawLabel) {
|
||||||
// 1️⃣ Extract pool (first word)
|
|
||||||
const parts = rawLabel.split(/\s+/);
|
const parts = rawLabel.split(/\s+/);
|
||||||
pool = parts[0];
|
pool = parts[0];
|
||||||
|
|
||||||
// 2️⃣ Extract ticket count (*n) & price if exists
|
|
||||||
const countMatch = rawLabel.match(/\*(\d+)(?:\s+(Rs\s*\d+))?/);
|
const countMatch = rawLabel.match(/\*(\d+)(?:\s+(Rs\s*\d+))?/);
|
||||||
if (countMatch) {
|
if (countMatch) { ticketCountLabel = `*${countMatch[1]}`; price = countMatch[2] || ''; }
|
||||||
ticketCountLabel = `*${countMatch[1]}`;
|
|
||||||
price = countMatch[2] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3️⃣ Extract horses part (between pool name & ticket count)
|
|
||||||
const horsesPartMatch = rawLabel.match(/^\w+\s+(.+?)\s+\*\d+/);
|
const horsesPartMatch = rawLabel.match(/^\w+\s+(.+?)\s+\*\d+/);
|
||||||
if (horsesPartMatch) {
|
if (horsesPartMatch) {
|
||||||
horses = horsesPartMatch[1].trim();
|
horses = horsesPartMatch[1].trim();
|
||||||
|
if (['MJP', 'JKP', 'TRE', 'trb1', 'trb2', 'mjp1', 'jkp1'].includes(pool)) {
|
||||||
// Special pools split into races
|
horsesArray = horses.split('/').map((r: string) => r.trim().split(',').map(h => h.trim()));
|
||||||
if (['MJP', 'JKP', 'TRE'].includes(pool)) {
|
|
||||||
horsesArray = horses.split('/').map(r =>
|
|
||||||
r.trim().split(',').map(h => h.trim())
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
horsesArray = [horses.split(',').map(h => h.trim())];
|
horsesArray = [horses.split(',').map(h => h.trim())];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barcodeId) {
|
if (barcodeId) {
|
||||||
const last4 = barcodeId.slice(-4);
|
const last4 = barcodeId.slice(-4);
|
||||||
|
maskedBarcode = btoa(barcodeId.slice(0, -4));
|
||||||
|
displayBarcode = '********' + last4;
|
||||||
|
}
|
||||||
|
|
||||||
// Encrypt everything except last4
|
return { pool, horses, horsesArray, ticketCountLabel, price, numbers: ticket.numbers || [], count: ticket.ticketCount || 0, amount: ticket.totalAmount || 0, maskedBarcode, displayBarcode };
|
||||||
const encryptedPart = btoa(barcodeId.slice(0, -4));
|
|
||||||
|
|
||||||
// Store masked barcode (if you still need encrypted form)
|
|
||||||
maskedBarcode = encryptedPart;
|
|
||||||
|
|
||||||
// For GUI → show ******** + last4
|
|
||||||
displayBarcode = '********' + last4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
console.log(maskedBarcode);
|
|
||||||
console.log('Decoded:', atob(maskedBarcode));
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
pool,
|
|
||||||
horses,
|
|
||||||
horsesArray,
|
|
||||||
ticketCountLabel,
|
|
||||||
price,
|
|
||||||
numbers,
|
|
||||||
count,
|
|
||||||
amount,
|
|
||||||
maskedBarcode,
|
|
||||||
displayBarcode
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
console.log('No tickets found in localStorage.');
|
this.showLogModal = true;
|
||||||
this.formattedTicketLogs = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showLogModal = true;
|
logout(): void {
|
||||||
console.log('Log modal opened. Final formattedTicketLogs:', this.formattedTicketLogs);
|
const name = localStorage.getItem('userName') || 'Unknown User';
|
||||||
}
|
const employeeId = localStorage.getItem('employeeId') || '000000';
|
||||||
|
const printData = { name, employeeId, action: 'logout', type: 'logout' };
|
||||||
|
console.log('[LOGOUT] Initiating logout with printData:', printData);
|
||||||
|
|
||||||
|
|
||||||
logout(): void {
|
fetch('http://localhost:9100/print', {
|
||||||
const name = localStorage.getItem('userName') || 'Unknown User';
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(printData),
|
||||||
const employeeId = localStorage.getItem('employeeId') || '000000';
|
|
||||||
|
|
||||||
const printData = {
|
|
||||||
name,
|
|
||||||
employeeId,
|
|
||||||
action: 'logout',
|
|
||||||
type: 'logout' // 👈 This is the missing piece
|
|
||||||
};
|
|
||||||
|
|
||||||
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) => {
|
.then((res) => {
|
||||||
console.error('[LOGOUT] Error printing:', err);
|
if (!res.ok) throw new Error('Logout print failed');
|
||||||
(window as any).electronAPI?.closeSecondScreen?.();
|
console.log('[LOGOUT] Print successful');
|
||||||
localStorage.clear();
|
(window as any).electronAPI?.closeSecondScreen?.();
|
||||||
this.router.navigate(['/logout']);
|
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']);
|
||||||
// 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 {
|
ngOnDestroy(): void {
|
||||||
if (this.subscription) {
|
if (this.subscription) this.subscription.unsubscribe();
|
||||||
this.subscription.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add trackByHorse for use in *ngFor
|
trackByHorse(index: number, item: number): number { return item; }
|
||||||
trackByHorse(index: number, item: number): number {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -221,7 +221,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- View RC Modal -->
|
<!-- View RC Modal -->
|
||||||
<div class="viewrc-modal-overlay" *ngIf="showViewRc">
|
<!-- <div class="viewrc-modal-overlay" *ngIf="showViewRc">
|
||||||
<div class="viewrc-modal-box">
|
<div class="viewrc-modal-box">
|
||||||
<h3 class="viewrc-modal-title">VIEW RC</h3>
|
<h3 class="viewrc-modal-title">VIEW RC</h3>
|
||||||
<div class="viewrc-modal-body">
|
<div class="viewrc-modal-body">
|
||||||
@ -271,6 +271,61 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="viewrc-modal-footer">
|
||||||
|
<button class="viewrc-cancel-btn" (click)="closeViewRcPopup()">CANCEL</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="viewrc-modal-overlay" *ngIf="showViewRc">
|
||||||
|
<div class="viewrc-modal-box">
|
||||||
|
<h3 class="viewrc-modal-title">VIEW RC</h3>
|
||||||
|
<div class="viewrc-modal-body">
|
||||||
|
<ng-container *ngIf="raceCardData && !raceCardData.error; else errorTpl">
|
||||||
|
<p class="top"><strong>📍 Venue:</strong> {{ raceCardData.venue }}</p>
|
||||||
|
<p class="top"><strong>📅 Date:</strong> {{ raceCardData.date }}</p>
|
||||||
|
|
||||||
|
<div class="rc-table-container">
|
||||||
|
<h4>🏇 Race Lists</h4>
|
||||||
|
<table class="rc-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="new">Races</th>
|
||||||
|
<th class="new">Race Numbers</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let race of raceCardData.raceVenueRaces.races">
|
||||||
|
<td class="table_col">Race {{ race.raceNo }}</td>
|
||||||
|
<td class="table_col1">{{ race.horses.join(', ') }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rc-table-container" *ngIf="raceCardData.pools?.comboRaces">
|
||||||
|
<h4>🎯Races</h4>
|
||||||
|
<table class="rc-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="new">Pool</th>
|
||||||
|
<th class="new">Races</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let pool of objectKeys(raceCardData.pools.comboRaces)">
|
||||||
|
<td class="table_col">{{ pool }}</td>
|
||||||
|
<td class="table_col1">{{ raceCardData.pools.comboRaces[pool].join(', ') }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-template #errorTpl>
|
||||||
|
<p class="error-text">❌ {{ raceCardData?.error }}</p>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="viewrc-modal-footer">
|
<div class="viewrc-modal-footer">
|
||||||
<button class="viewrc-cancel-btn" (click)="closeViewRcPopup()">CANCEL</button>
|
<button class="viewrc-cancel-btn" (click)="closeViewRcPopup()">CANCEL</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -441,17 +441,52 @@ ${receiptText}
|
|||||||
raceCardData: any = null; // ✅ Hold fetched data
|
raceCardData: any = null; // ✅ Hold fetched data
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private btcService: BtcService
|
// openViewRcPopup() {
|
||||||
|
// const cachedData = localStorage.getItem('rpinfo');
|
||||||
|
|
||||||
) {}
|
// if (cachedData) {
|
||||||
|
// this.raceCardData = JSON.parse(cachedData);
|
||||||
|
// console.log('📦 Loaded race card from localStorage:', this.raceCardData);
|
||||||
|
// } else {
|
||||||
|
// this.raceCardData = { error: 'Race card not available locally' };
|
||||||
|
// console.warn('⚠️ No race card data found in localStorage.');
|
||||||
|
// }
|
||||||
|
|
||||||
openViewRcPopup() {
|
// this.showViewRc = true;
|
||||||
const cachedData = localStorage.getItem('raceCardData');
|
// }
|
||||||
|
|
||||||
|
// openViewRcPopup() {
|
||||||
|
// const cachedData = localStorage.getItem('rpinfo');
|
||||||
|
|
||||||
|
// if (cachedData) {
|
||||||
|
// try {
|
||||||
|
// this.raceCardData = JSON.parse(cachedData); // now it's an array
|
||||||
|
// console.log('📦 Loaded race card from localStorage:', this.raceCardData);
|
||||||
|
// } catch (e) {
|
||||||
|
// console.error('Error parsing rpinfo:', e);
|
||||||
|
// this.raceCardData = { error: 'Invalid race card data' };
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// this.raceCardData = { error: 'Race card not available locally' };
|
||||||
|
// console.warn('⚠️ No race card data found in localStorage.');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// this.showViewRc = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
openViewRcPopup() {
|
||||||
|
const cachedData = localStorage.getItem('rpinfo');
|
||||||
|
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
this.raceCardData = JSON.parse(cachedData);
|
try {
|
||||||
console.log('📦 Loaded race card from localStorage:', this.raceCardData);
|
const parsed = JSON.parse(cachedData);
|
||||||
|
this.raceCardData = parsed.structuredRaceCard; // ✅ only keep structured
|
||||||
|
console.log('📦 Loaded structured race card:', this.raceCardData);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing rpinfo:', e);
|
||||||
|
this.raceCardData = { error: 'Invalid race card data' };
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.raceCardData = { error: 'Race card not available locally' };
|
this.raceCardData = { error: 'Race card not available locally' };
|
||||||
console.warn('⚠️ No race card data found in localStorage.');
|
console.warn('⚠️ No race card data found in localStorage.');
|
||||||
@ -460,6 +495,8 @@ ${receiptText}
|
|||||||
this.showViewRc = true;
|
this.showViewRc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
objectKeys = Object.keys;
|
objectKeys = Object.keys;
|
||||||
|
|
||||||
closeViewRcPopup() {
|
closeViewRcPopup() {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,8 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
console.log('🏠 HomeComponent loaded');
|
console.log('🏠 HomeComponent loaded');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.btcService.getAllRaceEventsToday().subscribe({
|
this.btcService.getAllRaceEventsToday().subscribe({
|
||||||
next: (response: HttpResponse<HorseRaceModel[]>) => {
|
next: (response: HttpResponse<HorseRaceModel[]>) => {
|
||||||
const horseRaceData = response.body;
|
const horseRaceData = response.body;
|
||||||
@ -64,13 +66,13 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const raceCardCached = localStorage.getItem('raceCardData');
|
const raceCardCached = localStorage.getItem('rpinfo');
|
||||||
if (!raceCardCached) {
|
if (!raceCardCached) {
|
||||||
this.btcService.getRaceCard().subscribe({
|
this.btcService.getRaceCard().subscribe({
|
||||||
next: (res) => {
|
next: (res) => {
|
||||||
const raceCardData = res.body;
|
const raceCardData = res.body;
|
||||||
console.log('📦 Race card preloaded:', raceCardData);
|
console.log('📦 Race card preloaded:', raceCardData);
|
||||||
localStorage.setItem('raceCardData', JSON.stringify(raceCardData));
|
localStorage.setItem('rpinfo', JSON.stringify(raceCardData));
|
||||||
this.updateRunnerCount(0);
|
this.updateRunnerCount(0);
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
@ -118,7 +120,7 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateRunnerCount(raceIdx: number) {
|
private updateRunnerCount(raceIdx: number) {
|
||||||
const raceCardData = JSON.parse(localStorage.getItem('raceCardData') || '{}');
|
const raceCardData = JSON.parse(localStorage.getItem('rpinfo') || '{}');
|
||||||
const race = raceCardData?.raceVenueRaces?.races?.[raceIdx] || [];
|
const race = raceCardData?.raceVenueRaces?.races?.[raceIdx] || [];
|
||||||
const runnerCount = Array.isArray(race) ? race.length : 12;
|
const runnerCount = Array.isArray(race) ? race.length : 12;
|
||||||
if (!raceCardData?.raceVenueRaces?.races?.[raceIdx]) {
|
if (!raceCardData?.raceVenueRaces?.races?.[raceIdx]) {
|
||||||
|
|||||||
@ -213,6 +213,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||||||
this.passwordStatus = true;
|
this.passwordStatus = true;
|
||||||
}
|
}
|
||||||
//--------------------------------------NEW LOGIN LOGIC ----------------------------------------//
|
//--------------------------------------NEW LOGIN LOGIC ----------------------------------------//
|
||||||
|
//--------------------------------------NEW LOGIN LOGIC ----------------------------------------//
|
||||||
async onSubmit(): Promise<void> {
|
async onSubmit(): Promise<void> {
|
||||||
if (this.loginForm.invalid) {
|
if (this.loginForm.invalid) {
|
||||||
this.loginForm.markAllAsTouched();
|
this.loginForm.markAllAsTouched();
|
||||||
@ -239,103 +240,37 @@ async onSubmit(): Promise<void> {
|
|||||||
const btid = this.btcService.btid;
|
const btid = this.btcService.btid;
|
||||||
console.log("📦 BTID from file (via service):", btid);
|
console.log("📦 BTID from file (via service):", btid);
|
||||||
|
|
||||||
// ✅ Prepare print data
|
|
||||||
const printData = {
|
|
||||||
name: userName,
|
|
||||||
employeeId: employeeId,
|
|
||||||
// btid: btid || "unknown",
|
|
||||||
action: 'login',
|
|
||||||
type: 'login'
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(printData.name);
|
|
||||||
console.log(printData.employeeId);
|
|
||||||
//console.log(printData.btid);
|
|
||||||
console.log(btid);
|
|
||||||
|
|
||||||
// ✅ Store in localStorage
|
// ✅ Store in localStorage
|
||||||
localStorage.setItem('userName', userName);
|
localStorage.setItem('userName', userName);
|
||||||
localStorage.setItem('employeeId', employeeId);
|
localStorage.setItem('employeeId', employeeId);
|
||||||
localStorage.setItem('password', password);
|
localStorage.setItem('password', password);
|
||||||
localStorage.setItem('btid', btid || "unknown");
|
localStorage.setItem('btid', btid || "unknown");
|
||||||
|
|
||||||
// ✅ Print first — login only if printing succeeds
|
// ✅ Fetch race card after login success
|
||||||
// fetch('http://localhost:9100/print', {
|
this.btcService
|
||||||
// method: 'POST',
|
.fetchRaceCard("021804111066", password, btid || "0483") // pass correct payload here
|
||||||
// headers: { 'Content-Type': 'application/json' },
|
.subscribe({
|
||||||
// body: JSON.stringify(printData),
|
next: (rpinfo) => {
|
||||||
// })
|
console.log("📦 Race Card:", rpinfo);
|
||||||
// .then((res) => {
|
|
||||||
// if (!res.ok) throw new Error('Print failed');
|
|
||||||
// console.log('🖨️ Print successful');
|
|
||||||
|
|
||||||
// ✅ Only here we allow login
|
// Save in localStorage for later use
|
||||||
(window as any).electronAPI?.openSecondScreen?.();
|
localStorage.setItem('rpinfo', JSON.stringify(rpinfo));
|
||||||
this.router.navigate(['/home']);
|
|
||||||
// })
|
// ✅ Navigate once race card stored
|
||||||
// .catch((err) => {
|
(window as any).electronAPI?.openSecondScreen?.();
|
||||||
// console.error('‼️ Print failed', err);
|
this.router.navigate(['/home']);
|
||||||
// this.loginError = 'Login failed: printing service unavailable.';
|
},
|
||||||
// this.passwordStatus = false; // reset status
|
error: (err) => {
|
||||||
// });
|
console.error("‼️ Failed to fetch race card", err);
|
||||||
|
this.loginError = "Could not load race card.";
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: () => {
|
error: () => {
|
||||||
this.loginError = 'Invalid login credentials';
|
this.loginError = 'Invalid login credentials';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//-------------------------NEW LOGIN ENDS HERE -------------------------------------------------//
|
|
||||||
|
|
||||||
|
|
||||||
// async onSubmit(): Promise<void> {
|
|
||||||
// if (this.loginForm.invalid) {
|
|
||||||
// this.loginForm.markAllAsTouched();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const { email, password } = this.loginForm.value;
|
|
||||||
|
|
||||||
// // ✅ Await service (since it’s async)
|
|
||||||
// (await this.btcService.userLogin(email, password)).subscribe({
|
|
||||||
// next: (response) => {
|
|
||||||
// const employee = response.body;
|
|
||||||
// console.log('🧠 Raw employee response:', employee);
|
|
||||||
|
|
||||||
// const userName = employee?.userName || 'Unknown User';
|
|
||||||
// const employeeId = employee?.userIdNumber || email;
|
|
||||||
|
|
||||||
// console.log('✅ Parsed name:', userName);
|
|
||||||
// console.log('✅ Parsed ID:', employeeId);
|
|
||||||
|
|
||||||
// this.passwordStatus = true;
|
|
||||||
|
|
||||||
// // ✅ Get the BTID the service fetched
|
|
||||||
// const btid = this.btcService.btid;
|
|
||||||
// console.log("📦 BTID from file (via service):", btid);
|
|
||||||
|
|
||||||
// // Prepare print data
|
|
||||||
// const printData = {
|
|
||||||
// name: userName,
|
|
||||||
// employeeId: employeeId,
|
|
||||||
// action: 'login',
|
|
||||||
// type: 'login'
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // ✅ Store in localStorage
|
|
||||||
// localStorage.setItem('userName', userName);
|
|
||||||
// localStorage.setItem('employeeId', employeeId);
|
|
||||||
// localStorage.setItem('password', password);
|
|
||||||
// localStorage.setItem('btid', btid || "unknown");
|
|
||||||
|
|
||||||
// // ✅ Open second screen + navigate
|
|
||||||
// (window as any).electronAPI?.openSecondScreen?.();
|
|
||||||
// this.router.navigate(['/home']);
|
|
||||||
// },
|
|
||||||
// error: () => {
|
|
||||||
// this.loginError = 'Invalid login credentials';
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
showConfirmModal : boolean = false;
|
showConfirmModal : boolean = false;
|
||||||
|
|
||||||
|
|||||||
@ -1,70 +1,154 @@
|
|||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
// import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
// import { Injectable } from '@angular/core';
|
||||||
import { ApplicationHttpRouts } from '../constants/http-routs';
|
// import { ApplicationHttpRouts } from '../constants/http-routs';
|
||||||
|
|
||||||
@Injectable({
|
// @Injectable({
|
||||||
providedIn: 'root',
|
// providedIn: 'root',
|
||||||
})
|
// })
|
||||||
|
|
||||||
|
// // export class BtcService {
|
||||||
|
// // constructor(private http: HttpClient) {}
|
||||||
|
// // btid: string | null = null;
|
||||||
|
// // //user login
|
||||||
|
// // public userLogin(employeeId: string, password: string) {
|
||||||
|
// // console.log('Login route ' + ApplicationHttpRouts.LOG_IN);
|
||||||
|
// // this.btid = localStorage.getItem('btid');
|
||||||
|
// // if (this.btid) {
|
||||||
|
// // employeeId += "," + this.btid;
|
||||||
|
// // } else {
|
||||||
|
// // employeeId += ",null"; // or just "," if you don’t want "null"
|
||||||
|
// // }
|
||||||
|
// // return this.http.get<any>(ApplicationHttpRouts.LOG_IN, {
|
||||||
|
// // headers: this.basicAuthCredentialsBuilder(employeeId, password),
|
||||||
|
// // withCredentials: true,
|
||||||
|
// // observe: 'response',
|
||||||
|
// // });
|
||||||
|
// // }
|
||||||
|
|
||||||
// export class BtcService {
|
// export class BtcService {
|
||||||
// constructor(private http: HttpClient) {}
|
// constructor(private http: HttpClient) {}
|
||||||
// btid: string | null = null;
|
// btid: string | null = null;
|
||||||
// //user login
|
|
||||||
// public userLogin(employeeId: string, password: string) {
|
// // user login
|
||||||
// console.log('Login route ' + ApplicationHttpRouts.LOG_IN);
|
// public async userLogin(employeeId: string, password: string) {
|
||||||
// this.btid = localStorage.getItem('btid');
|
// console.log('Login route ' + ApplicationHttpRouts.LOG_IN);
|
||||||
// if (this.btid) {
|
|
||||||
// employeeId += "," + this.btid;
|
// try {
|
||||||
// } else {
|
// if ((window as any).electronAPI?.getBtid) {
|
||||||
// employeeId += ",null"; // or just "," if you don’t want "null"
|
// this.btid = await (window as any).electronAPI.getBtid();
|
||||||
|
// } else {
|
||||||
|
// console.warn('Electron API not available — fallback to null');
|
||||||
|
// this.btid = null;
|
||||||
|
// }
|
||||||
|
// } catch (err) {
|
||||||
|
// console.error('Error fetching BTID:', err);
|
||||||
|
// this.btid = null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Append BTID after comma
|
||||||
|
// if (this.btid) {
|
||||||
|
// employeeId += ',' + this.btid;
|
||||||
|
// } else {
|
||||||
|
// employeeId += ',null';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return this.http.get<any>(ApplicationHttpRouts.LOG_IN, {
|
||||||
|
// headers: this.basicAuthCredentialsBuilder(employeeId, password),
|
||||||
|
// withCredentials: true,
|
||||||
|
// observe: 'response',
|
||||||
|
// });
|
||||||
// }
|
// }
|
||||||
// return this.http.get<any>(ApplicationHttpRouts.LOG_IN, {
|
|
||||||
// headers: this.basicAuthCredentialsBuilder(employeeId, password),
|
// // what goes to the backend for auth ... is the same as postman's basic auth
|
||||||
|
// private basicAuthCredentialsBuilder(
|
||||||
|
// employeeOrUserId: string,
|
||||||
|
// password: string
|
||||||
|
// ): HttpHeaders {
|
||||||
|
// console.log(`username and password${employeeOrUserId} p = ${password}`);
|
||||||
|
|
||||||
|
// return new HttpHeaders().set(
|
||||||
|
// 'Authorization',
|
||||||
|
// 'basic ' + window.btoa(employeeOrUserId + ':' + password)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public pingLiveStatus() {
|
||||||
|
// return this.http.get<any>(ApplicationHttpRouts.PING, {
|
||||||
// withCredentials: true,
|
// withCredentials: true,
|
||||||
// observe: 'response',
|
// observe: 'response',
|
||||||
|
// responseType: 'text' as 'json',
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// // Fetch all race events today
|
||||||
|
|
||||||
|
// public getAllRaceEventsToday() {
|
||||||
|
// return this.http.get<any>(ApplicationHttpRouts.RACE_EVENTS_TODAY, {
|
||||||
|
// withCredentials: true,
|
||||||
|
// observe: 'response',
|
||||||
|
// responseType: 'json',
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public getRaceCard(){
|
||||||
|
// return this.http.get<any>(ApplicationHttpRouts.RACE_CARD, {
|
||||||
|
// withCredentials: true,
|
||||||
|
// observe: 'response',
|
||||||
|
// responseType: 'json',
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ApplicationHttpRouts } from '../constants/http-routs';
|
||||||
|
import { of,Observable, tap } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
export class BtcService {
|
export class BtcService {
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient) {}
|
||||||
btid: string | null = null;
|
btid: string | null = null;
|
||||||
|
private raceCard: any = null; // cache race card in memory
|
||||||
|
|
||||||
// user login
|
// user login
|
||||||
public async userLogin(employeeId: string, password: string) {
|
public async userLogin(employeeId: string, password: string) {
|
||||||
console.log('Login route ' + ApplicationHttpRouts.LOG_IN);
|
console.log('Login route ' + ApplicationHttpRouts.LOG_IN);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ((window as any).electronAPI?.getBtid) {
|
if ((window as any).electronAPI?.getBtid) {
|
||||||
this.btid = await (window as any).electronAPI.getBtid();
|
this.btid = await (window as any).electronAPI.getBtid();
|
||||||
} else {
|
} else {
|
||||||
console.warn('Electron API not available — fallback to null');
|
console.warn('Electron API not available — fallback to null');
|
||||||
|
this.btid = null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching BTID:', err);
|
||||||
this.btid = null;
|
this.btid = null;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error('Error fetching BTID:', err);
|
// Append BTID after comma
|
||||||
this.btid = null;
|
if (this.btid) {
|
||||||
|
employeeId += ',' + this.btid;
|
||||||
|
} else {
|
||||||
|
employeeId += ',null';
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.http.get<any>(ApplicationHttpRouts.LOG_IN, {
|
||||||
|
headers: this.basicAuthCredentialsBuilder(employeeId, password),
|
||||||
|
withCredentials: true,
|
||||||
|
observe: 'response',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append BTID after comma
|
// basic auth header
|
||||||
if (this.btid) {
|
|
||||||
employeeId += ',' + this.btid;
|
|
||||||
} else {
|
|
||||||
employeeId += ',null';
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.http.get<any>(ApplicationHttpRouts.LOG_IN, {
|
|
||||||
headers: this.basicAuthCredentialsBuilder(employeeId, password),
|
|
||||||
withCredentials: true,
|
|
||||||
observe: 'response',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// what goes to the backend for auth ... is the same as postman's basic auth
|
|
||||||
private basicAuthCredentialsBuilder(
|
private basicAuthCredentialsBuilder(
|
||||||
employeeOrUserId: string,
|
employeeOrUserId: string,
|
||||||
password: string
|
password: string
|
||||||
): HttpHeaders {
|
): HttpHeaders {
|
||||||
console.log(`username and password${employeeOrUserId} p = ${password}`);
|
console.log(`username and password = ${employeeOrUserId} p = ${password}`);
|
||||||
|
|
||||||
return new HttpHeaders().set(
|
return new HttpHeaders().set(
|
||||||
'Authorization',
|
'Authorization',
|
||||||
@ -72,6 +156,7 @@ export class BtcService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ping backend
|
||||||
public pingLiveStatus() {
|
public pingLiveStatus() {
|
||||||
return this.http.get<any>(ApplicationHttpRouts.PING, {
|
return this.http.get<any>(ApplicationHttpRouts.PING, {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
@ -81,7 +166,6 @@ export class BtcService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all race events today
|
// Fetch all race events today
|
||||||
|
|
||||||
public getAllRaceEventsToday() {
|
public getAllRaceEventsToday() {
|
||||||
return this.http.get<any>(ApplicationHttpRouts.RACE_EVENTS_TODAY, {
|
return this.http.get<any>(ApplicationHttpRouts.RACE_EVENTS_TODAY, {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
@ -90,11 +174,75 @@ export class BtcService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRaceCard(){
|
/**
|
||||||
return this.http.get<any>(ApplicationHttpRouts.RACE_CARD, {
|
* Fetch Race Card from backend (POST /download/rpinfo)
|
||||||
withCredentials: true,
|
* Stores result in memory for reuse
|
||||||
observe: 'response',
|
// */
|
||||||
responseType: 'json',
|
// public fetchRaceCard(
|
||||||
})
|
// opCard: string,
|
||||||
|
// password: string,
|
||||||
|
// btId: string,
|
||||||
|
// usrId: string = '',
|
||||||
|
// btMake: number = 0
|
||||||
|
// ): Observable<any> {
|
||||||
|
// const payload = { opCard, password, btId, usrId, btMake };
|
||||||
|
|
||||||
|
// return this.http
|
||||||
|
// .post<any>('http://localhost:8082/download/rpinfo', payload)
|
||||||
|
// .pipe(
|
||||||
|
// tap((data) => {
|
||||||
|
// console.log('📦 Race Card fetched:', data);
|
||||||
|
// this.raceCard = data; // cache it
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Return cached race card (if available)
|
||||||
|
// */
|
||||||
|
// public getRaceCard(): any {
|
||||||
|
// return this.raceCard;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
public fetchRaceCard(
|
||||||
|
opCard: string,
|
||||||
|
password: string,
|
||||||
|
btId: string,
|
||||||
|
usrId: string = '',
|
||||||
|
btMake: number = 0
|
||||||
|
): Observable<any> {
|
||||||
|
const payload = { opCard, password, btId, usrId, btMake };
|
||||||
|
|
||||||
|
return this.http
|
||||||
|
.post<any>('http://localhost:8082/download/rpinfo', payload)
|
||||||
|
.pipe(
|
||||||
|
tap((data) => {
|
||||||
|
console.log('📦 Race Card fetched:', data);
|
||||||
|
this.raceCard = data; // store in memory
|
||||||
|
localStorage.setItem('rpinfo', JSON.stringify(data)); // store in localStorage
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return cached race card:
|
||||||
|
* - from memory (fastest)
|
||||||
|
* - fallback to localStorage (if reloaded)
|
||||||
|
*/
|
||||||
|
public getRaceCard(): Observable<any> {
|
||||||
|
if (this.raceCard) {
|
||||||
|
return of(this.raceCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cached = localStorage.getItem('rpinfo');
|
||||||
|
if (cached) {
|
||||||
|
this.raceCard = JSON.parse(cached);
|
||||||
|
return of(this.raceCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing available, return empty object
|
||||||
|
return of(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,50 +3,23 @@ version: '3.8'
|
|||||||
|
|
||||||
# Define the services for our application stack
|
# Define the services for our application stack
|
||||||
services:
|
services:
|
||||||
# PostgreSQL database service
|
|
||||||
postgres:
|
|
||||||
# Using the official PostgreSQL base image.
|
|
||||||
# 'postgres:16' is recommended for a stable, recent version.
|
|
||||||
# You can use 'postgres:latest' for the very newest, but versions like 13, 14, 15, 16 are common.
|
|
||||||
image: postgres:16 # Or postgres:latest, postgres:13-alpine, etc.
|
|
||||||
container_name: postgres_db # Assign a friendly name to the container
|
|
||||||
environment:
|
|
||||||
# --- CRITICAL: These settings will ONLY take effect if ./dbData directory is EMPTY on first run ---
|
|
||||||
POSTGRES_DB: horse # Your database name
|
|
||||||
POSTGRES_USER: postgres # Set to 'postgres', the default superuser for the official image
|
|
||||||
POSTGRES_PASSWORD: root # Your desired password for the 'postgres' user
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
ports:
|
|
||||||
- "5434:5432" # Map host port 5434 to container port 5432
|
|
||||||
volumes:
|
|
||||||
# Using a bind mount. You MUST delete the ./dbData directory manually if you change user/pass/db.
|
|
||||||
# This directory MUST be empty when the container first starts to trigger initialization.
|
|
||||||
- ./dbData:/var/lib/postgresql/data # Persist PostgreSQL data to a local directory
|
|
||||||
# Added command for more verbose logging during startup (optional, but highly recommended here)
|
|
||||||
command: postgres -c log_statement=all
|
|
||||||
networks:
|
|
||||||
- app_network # Connect to our custom application network
|
|
||||||
# networks:
|
|
||||||
# - app_network # Connect to our custom application network
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
#image: mathewfrancisv/spring_back_postgres:v1.0.0
|
#image: mathewfrancisv/spring_back_postgres:v1.0.0
|
||||||
image: mathewfrancisv/btc_cezen_backend:v1.1.6
|
image: mathewfrancisv/btc_cezen_backend:v2.3.0
|
||||||
container_name: spring_app
|
container_name: spring_app
|
||||||
ports:
|
ports:
|
||||||
- "8083:8080"
|
- "8083:8080"
|
||||||
environment:
|
environment:
|
||||||
# jdbc:postgresql://localhost:5432/horse
|
# jdbc:postgresql://localhost:5432/horse
|
||||||
# SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/horse
|
# SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/horse
|
||||||
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/horse
|
SPRING_DATASOURCE_CORSIP: http://10.236.119.124:4200
|
||||||
SPRING_DATASOURCE_USERNAME: postgres # Ensure this matches POSTGRES_USER
|
|
||||||
SPRING_DATASOURCE_PASSWORD: root # Ensure this matches POSTGRES_PASSWORD
|
|
||||||
SPRING_DATASOURCE_CORSIP: http://10.74.231.61:4200
|
|
||||||
#network_mode: host
|
#network_mode: host
|
||||||
networks:
|
networks:
|
||||||
- app_network
|
- app_network
|
||||||
depends_on:
|
# depends_on:
|
||||||
- postgres
|
# - postgres
|
||||||
|
|
||||||
# Angular frontend application service
|
# Angular frontend application service
|
||||||
angular-dev:
|
angular-dev:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user