From 8e9f84a2cf8f8cbb93f85fbe38502618410b55af Mon Sep 17 00:00:00 2001 From: karthik Date: Sun, 17 Aug 2025 12:33:05 +0530 Subject: [PATCH] feat : electron sync working --- btc-UI/electron/main.js | 27 +- btc-UI/electron/preload.js | 9 +- .../middle-section.component.ts | 275 +++++++++--------- .../shared-display.component.html | 13 +- .../shared-display.component.ts | 65 ++++- .../shared-table/shared-table.component.html | 96 +++--- .../shared-table/shared-table.component.ts | 30 +- btc-UI/src/electron.d.ts | 21 ++ btc-UI/src/format-numbers.pipe.ts | 15 + 9 files changed, 326 insertions(+), 225 deletions(-) create mode 100644 btc-UI/src/electron.d.ts create mode 100644 btc-UI/src/format-numbers.pipe.ts diff --git a/btc-UI/electron/main.js b/btc-UI/electron/main.js index b105e91..d745384 100644 --- a/btc-UI/electron/main.js +++ b/btc-UI/electron/main.js @@ -1,9 +1,11 @@ +// main.js const { app, BrowserWindow, screen, ipcMain } = require('electron'); const path = require('path'); const fs = require('fs'); let mainWindow; let screenWindow; +let currentSharedData = null; // Store latest data for initial sync function createWindows() { const displays = screen.getAllDisplays(); @@ -18,7 +20,7 @@ function createWindows() { webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, - } + }, }); mainWindow.loadURL('http://10.74.231.124:4200/login'); @@ -33,15 +35,30 @@ function createWindows() { webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, - } + }, }); screenWindow.loadURL('http://10.74.231.124:4200/shared-display'); - ipcMain.on('open-second-screen', () => screenWindow.show()); + // Handle opening second screen and send initial data + ipcMain.on('open-second-screen', () => { + screenWindow.show(); + if (currentSharedData && screenWindow.webContents) { + screenWindow.webContents.send('update-shared-data', currentSharedData); + } + }); + ipcMain.on('close-second-screen', () => screenWindow.hide()); - // ✅ IPC to return BTID + // Handle syncing data + ipcMain.on('sync-shared-data', (event, data) => { + currentSharedData = data; // Store latest data + if (screenWindow && screenWindow.webContents) { + screenWindow.webContents.send('update-shared-data', data); + } + }); + + // Handle BTID request ipcMain.handle('get-btid', () => { try { const filePath = path.join(process.env.HOME || process.env.USERPROFILE, 'BTID', 'betting.txt'); @@ -56,4 +73,4 @@ function createWindows() { } app.whenReady().then(createWindows); -app.on('window-all-closed', () => app.quit()); +app.on('window-all-closed', () => app.quit()); \ No newline at end of file diff --git a/btc-UI/electron/preload.js b/btc-UI/electron/preload.js index 8492231..3d1c198 100644 --- a/btc-UI/electron/preload.js +++ b/btc-UI/electron/preload.js @@ -1,9 +1,12 @@ +// preload.js const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronAPI', { openSecondScreen: () => ipcRenderer.send('open-second-screen'), closeSecondScreen: () => ipcRenderer.send('close-second-screen'), - - // ✅ Ask main process for Btid - getBtid: () => ipcRenderer.invoke('get-btid') + getBtid: () => ipcRenderer.invoke('get-btid'), + // New: Send data to main process + syncSharedData: (data) => ipcRenderer.send('sync-shared-data', data), + // New: Receive data in second window + onUpdateSharedData: (callback) => ipcRenderer.on('update-shared-data', (event, data) => callback(data)), }); \ No newline at end of file diff --git a/btc-UI/src/app/components/middle-section/middle-section.component.ts b/btc-UI/src/app/components/middle-section/middle-section.component.ts index 3f6831c..c1a5437 100755 --- a/btc-UI/src/app/components/middle-section/middle-section.component.ts +++ b/btc-UI/src/app/components/middle-section/middle-section.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core'; +import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SelectionService, SelectionData } from '../selection.service/selection.service'; import { Subscription } from 'rxjs'; @@ -8,17 +8,16 @@ import { Subscription } from 'rxjs'; standalone: true, imports: [CommonModule], templateUrl: './middle-section.component.html', - styleUrls: ['./middle-section.component.css'] + styleUrls: ['./middle-section.component.css'], }) export class MiddleSectionComponent implements OnInit, OnDestroy { @Input() containerHeight: string = '50vh'; @Input() eraseTrigger: any; summaryRows = Array.from({ length: 4 }); - filledRows: SelectionData[] = []; currentRow: SelectionData = { label: '', numbers: [], value: 0, total: 0 }; grandTotal: number = 0; - salesTotal: number = 0; + salesTotal: number = 0; receiveTotal: number = 0; totalClicks: number = 0; showConfirmButton: boolean = false; @@ -26,7 +25,6 @@ export class MiddleSectionComponent implements OnInit, OnDestroy { showRepeatTicket: boolean = false; confirmRepeat: boolean = false; showPrintButton: boolean = false; - private selections: SelectionData[] = []; private sub1!: Subscription; private sub2!: Subscription; @@ -34,12 +32,12 @@ export class MiddleSectionComponent implements OnInit, OnDestroy { constructor(private selectionService: SelectionService) {} ngOnInit() { - this.sub1 = this.selectionService.selections$.subscribe(data => { + this.sub1 = this.selectionService.selections$.subscribe((data) => { this.selections = data; this.updateFilledRows(this.selections, this.currentRow); }); - this.sub2 = this.selectionService.currentRow$.subscribe(row => { + this.sub2 = this.selectionService.currentRow$.subscribe((row) => { this.currentRow = row; this.updateFilledRows(this.selections, row); }); @@ -51,130 +49,133 @@ export class MiddleSectionComponent implements OnInit, OnDestroy { } } + // Helper to sync data to second screen + private syncToSecondScreen() { + if (window.electronAPI && window.electronAPI.syncSharedData) { + window.electronAPI.syncSharedData({ + filledRows: this.filledRows, + summaryRows: [ + { col1: 'Sales', col2: this.totalClicks, col3: this.salesTotal }, + { col1: 'Cancel', col2: 0, col3: 0 }, + { col1: 'Payout', col2: 0, col3: 0 }, + { col1: 'Receive', col2: this.totalClicks, col3: this.receiveTotal }, + ], + grandTotal: this.grandTotal, + salesTotal: this.salesTotal, + receiveTotal: this.receiveTotal, + totalClicks: this.totalClicks, + }); + } + } + updateFilledRows(saved: SelectionData[], current: SelectionData) { const rows: SelectionData[] = [...saved]; - if (rows.length < 5 && current.label) rows.push(current); // Include current row if label is selected - + if (rows.length < 5 && current.label) rows.push(current); const emptyCount = Math.max(5 - rows.length, 0); const emptyRows = Array.from({ length: emptyCount }, () => ({ label: '', numbers: [], value: 0, - total: 0 + total: 0, })); - this.filledRows = [...rows, ...emptyRows].slice(0, 5); this.calculateTotal(); - // Show Confirm button only if at least one row has data (label and numbers) - // and only after repeat is clicked (showRepeatTicket flag) - this.showConfirmButton = this.showRepeatTicket && this.filledRows.some( - row => row.label && row.numbers && row.numbers.length > 0 - ); - + // and only after repeat is clicked (showRepeatTicket flag) + this.showConfirmButton = + this.showRepeatTicket && + this.filledRows.some((row) => row.label && row.numbers && row.numbers.length > 0); // Hide Print button if Confirm is hidden if (!this.showConfirmButton) { this.showPrintButton = false; } + this.syncToSecondScreen(); // Sync after updating rows } + showSalesTotal: boolean = false; calculateTotal() { - this.grandTotal = this.filledRows.reduce((sum, row) => sum + (row.total || 0), 0); - - let storedTotal = 0; - try { - const storedTickets = JSON.parse(localStorage.getItem('localTickets') || '[]'); - if (Array.isArray(storedTickets)) { - storedTotal = storedTickets - .filter(ticket => ticket.type === 'ticket') - .reduce((sum: number, ticket: any) => sum + (ticket.totalAmount || 0), 0); + this.grandTotal = this.filledRows.reduce((sum, row) => sum + (row.total || 0), 0); + let storedTotal = 0; + try { + const storedTickets = JSON.parse(localStorage.getItem('localTickets') || '[]'); + if (Array.isArray(storedTickets)) { + storedTotal = storedTickets + .filter((ticket) => ticket.type === 'ticket') + .reduce((sum: number, ticket: any) => sum + (ticket.totalAmount || 0), 0); + } + } catch (e) { + console.error('❌ Failed to parse localTickets from localStorage:', e); } - } catch (e) { - console.error('❌ Failed to parse localTickets from localStorage:', e); - } - // 👇 Only show printed totals until print happens - const hasPrinted = localStorage.getItem('hasPrinted') === 'true'; - - if (hasPrinted) { - this.salesTotal = storedTotal; - this.receiveTotal = storedTotal; - } else { - this.salesTotal = storedTotal; // do NOT include grandTotal yet - this.receiveTotal = storedTotal; + const hasPrinted = localStorage.getItem('hasPrinted') === 'true'; + if (hasPrinted) { + this.salesTotal = storedTotal; + this.receiveTotal = storedTotal; + } else { + this.salesTotal = storedTotal; + this.receiveTotal = storedTotal; + } + this.totalClicks = Number(localStorage.getItem('printClickCount') || '0'); + this.showSalesTotal = hasPrinted; + this.syncToSecondScreen(); // Sync after calculating totals } - this.totalClicks = Number(localStorage.getItem('printClickCount') || '0'); - - // 👇 Toggle visibility based on localStorage flag - this.showSalesTotal = localStorage.getItem('hasPrinted') === 'true'; -} - - - repeat() { - try { - const storedTickets = localStorage.getItem('localTicketsnew'); - if (storedTickets) { - const tickets = JSON.parse(storedTickets); - const latestTicket = Array.isArray(tickets) - ? (tickets.length > 0 ? tickets[tickets.length - 1] : null) - : tickets; - - if (latestTicket && latestTicket.winLabels) { - // Pass totalAmount as a fallback for missing totals - const parsedRows = this.parseWinLabelsToRows( - latestTicket.winLabels, - latestTicket.totalAmount - ); - - // ✅ Always make sure we have exactly 5 rows - this.updateFilledRows(parsedRows, { label: '', numbers: [], value: 0, total: 0 }); - - console.log('📜 Updated Filled Rows:', parsedRows); - this.showConfirmButton = true; - this.showPrintButton = false; - this.lastTicket = latestTicket; + try { + const storedTickets = localStorage.getItem('localTicketsnew'); + if (storedTickets) { + const tickets = JSON.parse(storedTickets); + const latestTicket = Array.isArray(tickets) + ? tickets.length > 0 + ? tickets[tickets.length - 1] + : null + : tickets; + if (latestTicket && latestTicket.winLabels) { + const parsedRows = this.parseWinLabelsToRows(latestTicket.winLabels, latestTicket.totalAmount); + // ✅ Always make sure we have exactly 5 rows + this.updateFilledRows(parsedRows, { label: '', numbers: [], value: 0, total: 0 }); + console.log('📜 Updated Filled Rows:', parsedRows); + this.showConfirmButton = true; + this.showPrintButton = false; + this.lastTicket = latestTicket; + this.showRepeatTicket = true; + this.syncToSecondScreen(); // Sync after repeat + } else { + console.warn('⚠️ No valid ticket data found in localStorage.'); + } } else { - console.warn('⚠️ No valid ticket data found in localStorage.'); + console.warn('⚠️ No tickets found in localStorage.'); } - } else { - console.warn('⚠️ No tickets found in localStorage.'); + } catch (error) { + console.error('❌ Failed to load ticket from localStorage:', error); } - } catch (error) { - console.error('❌ Failed to load ticket from localStorage:', error); } -} -parseWinLabelsToRows(winLabels: string, fallbackTotal?: number): SelectionData[] { + parseWinLabelsToRows(winLabels: string, fallbackTotal?: number): SelectionData[] { return (winLabels.split('\n') as string[]) - .map(line => { - // Match: LABEL NUMBERS *VALUE [Rs TOTAL optional] - const match = line.match(/^(\S+)\s+(.+?)\s+\*([\d.]+)(?:\s*(?:Rs)?\s*(\d+))?/); + .map((line) => { + const match = line.match(/^(\S+)\s+(.+?)\s+\*([\d.]+)(?:\s*(?:Rs)?\s*(\d+))?/); if (!match) return null; - - const label = match[1].trim(); - const numbersRaw = match[2].trim(); - const value = Number(match[3]); - const total = match[4] ? Number(match[4]) : (fallbackTotal || 0); - + const label = match[1].trim(); + const numbersRaw = match[2].trim(); + const value = Number(match[3]); + const total = match[4] ? Number(match[4]) : fallbackTotal || 0; // If multi-leg ticket, split each part separately - let numbers: string[] | string[][]; - if (numbersRaw.includes('/')) { - numbers = numbersRaw - .split('/') - .map(part => part.split(',').map(s => s.trim()).filter(Boolean)); - } else { - numbers = numbersRaw.split(',').map(s => s.trim()).filter(Boolean); - } - + let numbers: string[] | string[][]; + if (numbersRaw.includes('/')) { + numbers = numbersRaw + .split('/') + .map((part) => part.split(',').map((s) => s.trim()).filter(Boolean)); + } else { + numbers = numbersRaw.split(',').map((s) => s.trim()).filter(Boolean); + } return { - label, - numbers, - value, - total, - isBoxed: numbersRaw.startsWith('#') + label, + numbers, + value, + total, + isBoxed: numbersRaw.startsWith('#'), }; }) .filter(Boolean) as SelectionData[]; @@ -183,29 +184,26 @@ parseWinLabelsToRows(winLabels: string, fallbackTotal?: number): SelectionData[] confirm() { this.showPrintButton = true; // Show Print button after confirming console.log('✅ [DEBUG] Ticket confirmed.'); + this.syncToSecondScreen(); // Sync after confirm } - - //-----------------------REPEAT PRINT LOGIC ---------------------------------- printRepeat() { console.log('🖨️ [DEBUG] Printing ticket...'); - - const userName = localStorage.getItem('userName') || 'Unknown'; - - // Keep currentDate as a Date object - const now = new Date(); - - // 🆕 Create Barcode ID (same combo format) - const day = String(now.getDate()).padStart(2, '0'); - const month = String(now.getMonth() + 1).padStart(2, '0'); - const year = String(now.getFullYear()).slice(-2); - const timeStr = `${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`; - const millis = String(now.getMilliseconds()).padStart(3, '0'); - const barcodeId = `1111${day}${month}${year}${timeStr}${millis}`; + const userName = localStorage.getItem('userName') || 'Unknown'; + const now = new Date(); + const day = String(now.getDate()).padStart(2, '0'); + const month = String(now.getMonth() + 1).padStart(2, '0'); + const year = String(now.getFullYear()).slice(-2); + const timeStr = `${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart( + 2, + '0' + )}${String(now.getSeconds()).padStart(2, '0')}`; + const millis = String(now.getMilliseconds()).padStart(3, '0'); + const barcodeId = `1111${day}${month}${year}${timeStr}${millis}`; const printableRows = this.filledRows - .filter(row => row.label && row.numbers.length > 0 && row.total > 0) - .map(row => { + .filter((row) => row.label && row.numbers.length > 0 && row.total > 0) + .map((row) => { const horses = Array.isArray(row.numbers) ? row.numbers.join(',') : row.numbers; return `${row.label.padEnd(6)} ${horses.padEnd(15)} * ${String(row.value).padEnd(3)} ₹${row.total}`; }) @@ -214,7 +212,6 @@ parseWinLabelsToRows(winLabels: string, fallbackTotal?: number): SelectionData[] const ticketContent = ` BTC Race Ticket ${printableRows} - Barcode ID : ${barcodeId} Printed by : ${userName} Date : ${now.toLocaleString()}`; @@ -224,27 +221,27 @@ Date : ${now.toLocaleString()}`; // ✅ Send to print server const payload = { type: 'repeat', - printedBy: userName, - barcodeId, // send barcode separately + printedBy: userName, + barcodeId, content: ticketContent, - timestamp: now.toLocaleString() + timestamp: now.toLocaleString(), }; fetch('http://localhost:9100/print', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) + body: JSON.stringify(payload), }) - .then(response => { - if (!response.ok) throw new Error(`Printer error: ${response.status}`); - return response.text(); - }) - .then(result => { - console.log("✅ Repeat ticket print successful:", result); - }) - .catch(error => { - console.error("❌ Repeat ticket print failed:", error); - }); + .then((response) => { + if (!response.ok) throw new Error(`Printer error: ${response.status}`); + return response.text(); + }) + .then((result) => { + console.log('✅ Repeat ticket print successful:', result); + }) + .catch((error) => { + console.error('❌ Repeat ticket print failed:', error); + }); // --- Update localStorage for transaction summary like normal print --- // 1. Increment printClickCount @@ -258,14 +255,13 @@ Date : ${now.toLocaleString()}`; const existingTickets = existingTicketsStr ? JSON.parse(existingTicketsStr) : []; // Calculate totalAmount for this repeat print const totalAmount = this.filledRows - .filter(row => row.label && row.numbers.length > 0 && row.total > 0) + .filter((row) => row.label && row.numbers.length > 0 && row.total > 0) .reduce((sum, row) => sum + (row.total || 0), 0); const ticketEntry = { type: 'ticket', printedBy: userName, totalAmount, content: ticketContent, - }; existingTickets.push(ticketEntry); localStorage.setItem('localTickets', JSON.stringify(existingTickets)); @@ -276,25 +272,24 @@ Date : ${now.toLocaleString()}`; // Hide Confirm and Print buttons before clearing selections this.showConfirmButton = false; this.showPrintButton = false; - - this.erase(); // Clear selections after hiding buttons - - // 👉 Recalculate totals after erase to update transaction summary - this.calculateTotal(); -} - + this.erase(); + this.syncToSecondScreen(); // Sync after print + } //------------------------------PRINT REPEAT ENDED HERE-----------------------------------------------------S - erase() { + erase() { this.selectionService.clearSelections(); this.resetSelections(); // 👉 Also recalculate totals after erase to keep summary in sync this.calculateTotal(); + this.syncToSecondScreen(); // Sync after erase } + resetSelections() { // No-op: Prevent error and allow summary to update // (If you want to reset any local state, do it here) } + ngOnDestroy() { this.sub1.unsubscribe(); this.sub2.unsubscribe(); diff --git a/btc-UI/src/app/components/shared-display/shared-display.component.html b/btc-UI/src/app/components/shared-display/shared-display.component.html index 6c3a9f6..ed88d22 100644 --- a/btc-UI/src/app/components/shared-display/shared-display.component.html +++ b/btc-UI/src/app/components/shared-display/shared-display.component.html @@ -8,8 +8,11 @@ - \ No newline at end of file + +
+ +
\ No newline at end of file diff --git a/btc-UI/src/app/components/shared-display/shared-display.component.ts b/btc-UI/src/app/components/shared-display/shared-display.component.ts index ef94141..87cca14 100644 --- a/btc-UI/src/app/components/shared-display/shared-display.component.ts +++ b/btc-UI/src/app/components/shared-display/shared-display.component.ts @@ -1,45 +1,84 @@ - +// shared-display.component.ts import { Component, OnInit, ChangeDetectorRef } from '@angular/core'; -import { SharedStateService } from '../../service/shared-state.service'; import { CommonModule } from '@angular/common'; +import { SharedStateService } from '../../service/shared-state.service'; import { SharedTableComponent } from '../shared-table/shared-table.component'; +import { SelectionData } from '../selection.service/selection.service'; +import { FormatNumbersPipe } from '../../../format-numbers.pipe'; + +interface SharedData { + filledRows: SelectionData[]; + summaryRows: { col1: string; col2: number; col3: number }[]; + grandTotal: number; + salesTotal: number; + receiveTotal: number; + totalClicks: number; +} @Component({ selector: 'app-shared-display', standalone: true, - imports: [CommonModule, SharedTableComponent], + imports: [CommonModule, SharedTableComponent, FormatNumbersPipe], templateUrl: './shared-display.component.html', styleUrls: ['./shared-display.component.css'], }) export class SharedDisplayComponent implements OnInit { selectedVenue: string = 'Select Venue'; selectedRace: string = '1'; - summaryRows = Array.from({ length: 4 }, () => ({ col1: '', col2: '', col3: '' })); - rows = Array.from({ length: 5 }, () => ({ col1: '', col2: '', col3: '', col4: '' })); - totalAmount = ''; + summaryRows: { col1: string; col2: number; col3: number }[] = [ + { col1: 'Sales', col2: 0, col3: 0 }, + { col1: 'Cancel', col2: 0, col3: 0 }, + { col1: 'Payout', col2: 0, col3: 0 }, + { col1: 'Receive', col2: 0, col3: 0 }, + ]; + filledRows: SelectionData[] = Array.from({ length: 5 }, () => ({ + label: '', + numbers: [], + value: 0, + total: 0, + })); + grandTotal: number = 0; + salesTotal: number = 0; + receiveTotal: number = 0; + totalClicks: number = 0; + constructor( private sharedStateService: SharedStateService, private cdRef: ChangeDetectorRef ) {} ngOnInit(): void { + console.log('[SHARED DISPLAY] Initializing, electronAPI available:', !!window.electronAPI); + this.sharedStateService.sharedData$.subscribe((data) => { console.log('[SHARED DISPLAY] Received shared data:', data); - if (!data) return; - if (data.type === 'selectedVenue') { this.selectedVenue = data.value; console.log('[SHARED DISPLAY] Venue updated to:', this.selectedVenue); } - if (data.type === 'selectedRace') { this.selectedRace = data.value; console.log('[SHARED DISPLAY] Race updated to:', this.selectedRace); } - - this.cdRef.detectChanges(); // Force UI update + this.cdRef.detectChanges(); }); - } -} + if (window.electronAPI && window.electronAPI.onUpdateSharedData) { + window.electronAPI.onUpdateSharedData((data: SharedData) => { + console.log('[SHARED DISPLAY] Received IPC data:', data); + if (!data) return; + this.filledRows = data.filledRows || this.filledRows; + this.summaryRows = data.summaryRows || this.summaryRows; + this.grandTotal = data.grandTotal || 0; + this.salesTotal = data.salesTotal || 0; + this.receiveTotal = data.receiveTotal || 0; + this.totalClicks = data.totalClicks || 0; + console.log('[SHARED DISPLAY] Updated filledRows:', this.filledRows.map(row => ({ ...row, numbers: JSON.stringify(row.numbers) }))); + this.cdRef.detectChanges(); + }); + } else { + console.error('[SHARED DISPLAY] electronAPI or onUpdateSharedData not available'); + } + } +} \ No newline at end of file diff --git a/btc-UI/src/app/components/shared-table/shared-table.component.html b/btc-UI/src/app/components/shared-table/shared-table.component.html index 2dfa105..0f8b5ca 100644 --- a/btc-UI/src/app/components/shared-table/shared-table.component.html +++ b/btc-UI/src/app/components/shared-table/shared-table.component.html @@ -1,51 +1,59 @@ +
-
-
-
-
Transaction Summary
+
+ +
+
+
Transaction Summary
+
+ + + + + + + + + + + + + +
{{ row.col1 }}{{ row.col2 }}{{ row.col3 }}
+
+
+
-
- - - - - - - - -
{{ row.col1 }}{{ row.col2 }}{{ row.col3 }}
+ +
+
+ + + + + + + + + + + + + + + +
{{ row.label }} + {{ row.isBoxed ? '# ' : '' }}{{ $any(row.numbers) | formatNumbers }} + {{ row.value || '' }}{{ row.total || '' }}
+
+
+
Amount : ₹ {{ totalAmount }}
+
-
-
- - - - - - - - - -
{{ row.col1 }}{{ row.col2 }}{{ row.col3 }}{{ row.col4 }}
- -
-
Amount : {{ totalAmount }}
-
-
-
-
- - - -
-
- Live Data: {{ message || 'Disconnected' }} -
-
+
diff --git a/btc-UI/src/app/components/shared-table/shared-table.component.ts b/btc-UI/src/app/components/shared-table/shared-table.component.ts index 7cad543..19506b0 100644 --- a/btc-UI/src/app/components/shared-table/shared-table.component.ts +++ b/btc-UI/src/app/components/shared-table/shared-table.component.ts @@ -1,22 +1,20 @@ -import { Component, Input } from '@angular/core'; +// shared-table.component.ts +import { Component, Input, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { WebsocketService } from '../../service/websocket.service'; // adjust path if needed +import { SelectionData } from '../selection.service/selection.service'; +import { FormatNumbersPipe } from '../../../format-numbers.pipe'; +import { WebsocketService } from '../../service/websocket.service'; // Adjust path as needed @Component({ selector: 'app-shared-table', standalone: true, - imports: [CommonModule], + imports: [CommonModule, FormatNumbersPipe], templateUrl: './shared-table.component.html', - styleUrls: ['./shared-table.component.css'] + styleUrls: ['./shared-table.component.css'], }) -// export class SharedTableComponent { -// @Input() summaryRows: any[] = []; -// @Input() rows: any[] = []; -// @Input() totalAmount: string = ''; -// } -export class SharedTableComponent { - @Input() summaryRows: any[] = []; - @Input() rows: any[] = []; +export class SharedTableComponent implements OnInit { + @Input() summaryRows: { col1: string; col2: number; col3: number }[] = []; + @Input() rows: SelectionData[] = []; @Input() totalAmount: string = ''; message = ''; @@ -25,12 +23,14 @@ export class SharedTableComponent { constructor(private websocketService: WebsocketService) {} ngOnInit() { - this.websocketService.message$.subscribe(msg => { + this.websocketService.message$.subscribe((msg) => { this.message = msg; + console.log('[SHARED TABLE] WebSocket message:', msg); }); - this.websocketService.isConnected$.subscribe(status => { + this.websocketService.isConnected$.subscribe((status) => { this.isConnected = status; + console.log('[SHARED TABLE] WebSocket connection status:', status); }); } -} +} \ No newline at end of file diff --git a/btc-UI/src/electron.d.ts b/btc-UI/src/electron.d.ts new file mode 100644 index 0000000..36ebac7 --- /dev/null +++ b/btc-UI/src/electron.d.ts @@ -0,0 +1,21 @@ +// src/electron.d.ts +interface ElectronAPI { + openSecondScreen: () => void; + closeSecondScreen: () => void; + getBtid: () => Promise; + syncSharedData: (data: SharedData) => void; + onUpdateSharedData: (callback: (data: SharedData) => void) => void; +} + +interface SharedData { + filledRows: SelectionData[]; + summaryRows: { col1: string; col2: number; col3: number }[]; + grandTotal: number; + salesTotal: number; + receiveTotal: number; + totalClicks: number; +} + +interface Window { + electronAPI: ElectronAPI; +} \ No newline at end of file diff --git a/btc-UI/src/format-numbers.pipe.ts b/btc-UI/src/format-numbers.pipe.ts new file mode 100644 index 0000000..ae99dde --- /dev/null +++ b/btc-UI/src/format-numbers.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'formatNumbers', + standalone: true, +}) +export class FormatNumbersPipe implements PipeTransform { + transform(values: (string | number)[]): string { + if (!values || !Array.isArray(values)) { + return ''; + } + + return values.map((val) => val.toString()).join(','); + } +}