248 lines
7.5 KiB
JavaScript
Executable File
248 lines
7.5 KiB
JavaScript
Executable File
/** @odoo-module **/
|
|
|
|
import { Component, useState, onWillStart, onWillUnmount } from "@odoo/owl";
|
|
import { useService } from "@web/core/utils/hooks";
|
|
import { BluetoothPrinterConfig } from "./bluetooth_printer_config";
|
|
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
|
import { BluetoothPrinterStorage } from "./storage_manager";
|
|
|
|
/**
|
|
* Bluetooth Connection Status Widget
|
|
*
|
|
* Displays the current connection status of the bluetooth thermal printer
|
|
* with visual indicators and detailed tooltip information.
|
|
*
|
|
* Status states:
|
|
* - connected: Green indicator, printer is connected and ready
|
|
* - disconnected: Red indicator, printer is not connected
|
|
* - connecting: Yellow indicator with animation, attempting to connect
|
|
* - error: Red indicator with error icon, connection error occurred
|
|
*/
|
|
export class BluetoothConnectionStatus extends Component {
|
|
static template = "pos_bluetooth_thermal_printer.BluetoothConnectionStatus";
|
|
|
|
setup() {
|
|
this.dialog = useService("dialog");
|
|
this.notification = useService("notification");
|
|
this.storageManager = new BluetoothPrinterStorage();
|
|
|
|
this.state = useState({
|
|
status: 'disconnected',
|
|
deviceName: null,
|
|
lastError: null,
|
|
reconnectAttempts: 0,
|
|
isReconnecting: false,
|
|
timestamp: null,
|
|
showTooltip: false
|
|
});
|
|
|
|
// Get the bluetooth printer manager service
|
|
// This will be injected when the component is used in the POS
|
|
this.bluetoothManager = this.props.bluetoothManager;
|
|
|
|
onWillStart(() => {
|
|
this._initializeStatus();
|
|
this._subscribeToEvents();
|
|
});
|
|
|
|
onWillUnmount(() => {
|
|
this._unsubscribeFromEvents();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize status from bluetooth manager
|
|
* @private
|
|
*/
|
|
_initializeStatus() {
|
|
if (this.bluetoothManager) {
|
|
const info = this.bluetoothManager.getConnectionInfo();
|
|
this._updateStatus(info);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Subscribe to bluetooth manager events
|
|
* @private
|
|
*/
|
|
_subscribeToEvents() {
|
|
if (this.bluetoothManager) {
|
|
this._statusChangeHandler = (data) => this._onStatusChanged(data);
|
|
this.bluetoothManager.addEventListener(
|
|
'connection-status-changed',
|
|
this._statusChangeHandler
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unsubscribe from bluetooth manager events
|
|
* @private
|
|
*/
|
|
_unsubscribeFromEvents() {
|
|
if (this.bluetoothManager && this._statusChangeHandler) {
|
|
this.bluetoothManager.removeEventListener(
|
|
'connection-status-changed',
|
|
this._statusChangeHandler
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle connection status change event
|
|
* @private
|
|
* @param {Object} data - Event data
|
|
*/
|
|
_onStatusChanged(data) {
|
|
// Get full connection info for complete state update
|
|
const info = this.bluetoothManager.getConnectionInfo();
|
|
this._updateStatus(info);
|
|
}
|
|
|
|
/**
|
|
* Update component state from connection info
|
|
* @private
|
|
* @param {Object} info - Connection information object
|
|
*/
|
|
_updateStatus(info) {
|
|
this.state.status = info.status;
|
|
this.state.deviceName = info.deviceName;
|
|
this.state.lastError = info.lastError;
|
|
this.state.reconnectAttempts = info.reconnectAttempts;
|
|
this.state.isReconnecting = info.isReconnecting;
|
|
this.state.timestamp = info.timestamp;
|
|
|
|
// Check if bypassed on this device
|
|
const posConfigId = this.props.posConfigId || 1;
|
|
if (this.storageManager.getBypassStatus(posConfigId)) {
|
|
this.state.status = 'bypassed';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get CSS class for status indicator
|
|
* @returns {string} CSS class name
|
|
*/
|
|
get statusClass() {
|
|
const baseClass = 'bluetooth-status-indicator';
|
|
const statusClass = `${baseClass}-${this.state.status}`;
|
|
const animationClass = this.state.status === 'connecting' ? 'bluetooth-status-pulse' : '';
|
|
|
|
return `${baseClass} ${statusClass} ${animationClass}`.trim();
|
|
}
|
|
|
|
/**
|
|
* Get icon for status indicator
|
|
* @returns {string} Icon class name
|
|
*/
|
|
get statusIcon() {
|
|
switch (this.state.status) {
|
|
case 'connected':
|
|
return 'fa fa-bluetooth';
|
|
case 'disconnected':
|
|
return 'fa fa-bluetooth-b';
|
|
case 'connecting':
|
|
return 'fa fa-bluetooth';
|
|
case 'bypassed':
|
|
return 'fa fa-ban';
|
|
case 'error':
|
|
return 'fa fa-exclamation-triangle';
|
|
default:
|
|
return 'fa fa-bluetooth-b';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get human-readable status text
|
|
* @returns {string} Status text
|
|
*/
|
|
get statusText() {
|
|
switch (this.state.status) {
|
|
case 'connected':
|
|
return this.state.deviceName
|
|
? `Connected to ${this.state.deviceName}`
|
|
: 'Connected';
|
|
case 'disconnected':
|
|
return 'Printer Disconnected';
|
|
case 'connecting':
|
|
return this.state.isReconnecting
|
|
? `Reconnecting... (${this.state.reconnectAttempts}/3)`
|
|
: 'Connecting...';
|
|
case 'bypassed':
|
|
return 'Printer Bypassed (Web Print)';
|
|
case 'error':
|
|
return 'Connection Error';
|
|
default:
|
|
return 'Unknown Status';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get detailed tooltip content
|
|
* @returns {string} Tooltip HTML content
|
|
*/
|
|
get tooltipContent() {
|
|
const lines = [];
|
|
|
|
lines.push(`<strong>Status:</strong> ${this.statusText}`);
|
|
|
|
if (this.state.deviceName) {
|
|
lines.push(`<strong>Device:</strong> ${this.state.deviceName}`);
|
|
}
|
|
|
|
if (this.state.status === 'connecting' && this.state.isReconnecting) {
|
|
lines.push(`<strong>Reconnect Attempts:</strong> ${this.state.reconnectAttempts}/3`);
|
|
}
|
|
|
|
if (this.state.lastError) {
|
|
lines.push(`<strong>Last Error:</strong> ${this.state.lastError}`);
|
|
}
|
|
|
|
if (this.state.timestamp) {
|
|
const date = new Date(this.state.timestamp);
|
|
const timeStr = date.toLocaleTimeString();
|
|
lines.push(`<strong>Last Update:</strong> ${timeStr}`);
|
|
}
|
|
|
|
return lines.join('<br>');
|
|
}
|
|
|
|
/**
|
|
* Show tooltip
|
|
*/
|
|
onMouseEnter() {
|
|
this.state.showTooltip = true;
|
|
}
|
|
|
|
/**
|
|
* Hide tooltip
|
|
*/
|
|
onMouseLeave() {
|
|
this.state.showTooltip = false;
|
|
}
|
|
|
|
/**
|
|
* Handle click on status indicator
|
|
* Opens the Bluetooth printer configuration dialog
|
|
*/
|
|
async onClick() {
|
|
console.log('Bluetooth status clicked:', this.state);
|
|
|
|
// Open the configuration dialog
|
|
try {
|
|
this.dialog.add(BluetoothPrinterConfig, {
|
|
bluetoothManager: this.bluetoothManager,
|
|
posConfigId: this.props.posConfigId || 1,
|
|
});
|
|
console.log('Dialog opened successfully');
|
|
} catch (error) {
|
|
console.error('Failed to open dialog:', error);
|
|
this.notification.add("Failed to open configuration dialog", {
|
|
type: "danger"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
export default BluetoothConnectionStatus;
|