feat : electron sync working
This commit is contained in:
parent
594bd4ae77
commit
8e9f84a2cf
@ -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');
|
||||
|
||||
@ -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)),
|
||||
});
|
||||
@ -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,13 +8,12 @@ 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;
|
||||
@ -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,91 +49,98 @@ 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
|
||||
);
|
||||
|
||||
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')
|
||||
.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);
|
||||
}
|
||||
|
||||
// 👇 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.salesTotal = storedTotal;
|
||||
this.receiveTotal = storedTotal;
|
||||
}
|
||||
this.totalClicks = Number(localStorage.getItem('printClickCount') || '0');
|
||||
|
||||
// 👇 Toggle visibility based on localStorage flag
|
||||
this.showSalesTotal = localStorage.getItem('hasPrinted') === 'true';
|
||||
this.showSalesTotal = hasPrinted;
|
||||
this.syncToSecondScreen(); // Sync after calculating totals
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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.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
|
||||
);
|
||||
|
||||
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.');
|
||||
}
|
||||
@ -149,32 +154,28 @@ export class MiddleSectionComponent implements OnInit, OnDestroy {
|
||||
|
||||
parseWinLabelsToRows(winLabels: string, fallbackTotal?: number): SelectionData[] {
|
||||
return (winLabels.split('\n') as string[])
|
||||
.map(line => {
|
||||
// Match: LABEL NUMBERS *VALUE [Rs TOTAL optional]
|
||||
.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 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));
|
||||
.map((part) => part.split(',').map((s) => s.trim()).filter(Boolean));
|
||||
} else {
|
||||
numbers = numbersRaw.split(',').map(s => s.trim()).filter(Boolean);
|
||||
numbers = numbersRaw.split(',').map((s) => s.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
return {
|
||||
label,
|
||||
numbers,
|
||||
value,
|
||||
total,
|
||||
isBoxed: numbersRaw.startsWith('#')
|
||||
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 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()}`;
|
||||
@ -225,25 +222,25 @@ Date : ${now.toLocaleString()}`;
|
||||
const payload = {
|
||||
type: 'repeat',
|
||||
printedBy: userName,
|
||||
barcodeId, // send barcode separately
|
||||
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 => {
|
||||
.then((response) => {
|
||||
if (!response.ok) throw new Error(`Printer error: ${response.status}`);
|
||||
return response.text();
|
||||
})
|
||||
.then(result => {
|
||||
console.log("✅ Repeat ticket print successful:", result);
|
||||
.then((result) => {
|
||||
console.log('✅ Repeat ticket print successful:', result);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("❌ Repeat ticket print failed:", error);
|
||||
.catch((error) => {
|
||||
console.error('❌ Repeat ticket print failed:', error);
|
||||
});
|
||||
|
||||
// --- Update localStorage for transaction summary like normal print ---
|
||||
@ -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() {
|
||||
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();
|
||||
|
||||
@ -8,8 +8,11 @@
|
||||
<!-- Tables for second screen -->
|
||||
|
||||
|
||||
<!-- shared-display.component.html -->
|
||||
<div class="wrapper">
|
||||
<app-shared-table
|
||||
[summaryRows]="summaryRows"
|
||||
[rows]="rows"
|
||||
[totalAmount]="totalAmount"
|
||||
[rows]="filledRows"
|
||||
[totalAmount]="grandTotal.toString()"
|
||||
></app-shared-table>
|
||||
</div>
|
||||
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,17 @@
|
||||
<!-- shared-table.component.html -->
|
||||
<div class="wrapper">
|
||||
<div class="middle-section-container container-fluid mt-3 px-4">
|
||||
<!-- Transaction Summary -->
|
||||
<div class="transaction-summary mb-3">
|
||||
<div class="p-3 rounded text-white h-100 d-flex flex-column" style="background-color: #546c98">
|
||||
<h5 class="text-center mb-3">Transaction Summary</h5>
|
||||
|
||||
<div class="rounded flex-grow-1" style="background-color: #f1f1f1df; padding: 1rem; overflow: hidden">
|
||||
<table class="table borderless-custom w-100 text-dark mb-0 transaction_tb">
|
||||
<colgroup>
|
||||
<col style="width: 20%" />
|
||||
<col style="width: 15%" />
|
||||
<col style="width: 65%" />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr *ngFor="let row of summaryRows">
|
||||
<td class="custom-cell pure-white col-20">{{ row.col1 }}</td>
|
||||
@ -18,34 +24,36 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Table -->
|
||||
<div class="main-table">
|
||||
<div class="p-2 rounded h-100 d-flex flex-column justify-content-between" style="background-color: #f1f1f1df">
|
||||
<table class="table borderless-custom w-100 mb-2 table-main">
|
||||
<colgroup>
|
||||
<col style="width: 12%" />
|
||||
<col style="width: 60%" />
|
||||
<col style="width: 10%" />
|
||||
<col style="width: 18%" />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr *ngFor="let row of rows">
|
||||
<td class="custom-cell-new">{{ row.col1 }}</td>
|
||||
<td class="custom-cell-new">{{ row.col2 }}</td>
|
||||
<td class="custom-cell-new">{{ row.col3 }}</td>
|
||||
<td class="custom-cell-new">{{ row.col4 }}</td>
|
||||
<td class="custom-cell-new">{{ row.label }}</td>
|
||||
<td class="custom-cell-new">
|
||||
{{ row.isBoxed ? '# ' : '' }}{{ $any(row.numbers) | formatNumbers }}
|
||||
</td>
|
||||
<td class="custom-cell-new">{{ row.value || '' }}</td>
|
||||
<td class="custom-cell-new">{{ row.total || '' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="buttons-custom d-flex justify-content-between align-items-center px-3">
|
||||
<div class="fw-bold">Amount : {{ totalAmount }}</div>
|
||||
<div></div>
|
||||
<div class="fw-bold fs-5">Amount : ₹ {{ totalAmount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <footer class="footer">
|
||||
<div class="live-data-text">Live Data: </div>
|
||||
</footer>
|
||||
|
||||
</div> -->
|
||||
|
||||
<footer class="footer" [ngStyle]="{ 'background-color': isConnected ? '#d1ffd1' : '#ffcccc' }">
|
||||
<div class="live-data-text">
|
||||
Live Data: {{ message || 'Disconnected' }}
|
||||
</div>
|
||||
<div class="live-data-text">Live Data: {{ message || 'Disconnected' }}</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
21
btc-UI/src/electron.d.ts
vendored
Normal file
21
btc-UI/src/electron.d.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// src/electron.d.ts
|
||||
interface ElectronAPI {
|
||||
openSecondScreen: () => void;
|
||||
closeSecondScreen: () => void;
|
||||
getBtid: () => Promise<string | null>;
|
||||
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;
|
||||
}
|
||||
15
btc-UI/src/format-numbers.pipe.ts
Normal file
15
btc-UI/src/format-numbers.pipe.ts
Normal file
@ -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(',');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user