react-native-thermal-pos-printer
Version:
React Native thermal printer package for POS systems supporting Xprinter and other popular brands
295 lines (263 loc) • 8.31 kB
text/typescript
import { PosPrinter } from '../utils/native';
import {
TextOptions,
ImageOptions,
BarcodeOptions,
QRCodeOptions,
PrinterStatus,
ThermalPrinterNativeDevice,
ConnectionOptions
} from '../types/printer';
import { PrinterError, PrinterErrorCode } from '../types/errors';
import { PrinterEvent } from '../types/events';
import { BarcodeTypes } from '../constants/barcodes';
import { ESCPOSCommands } from '../constants/commands';
import { PrinterEventManager } from './PrinterEventManager';
export class ThermalPrinterDevice {
private device: ThermalPrinterNativeDevice;
private connected: boolean = false;
constructor(device: ThermalPrinterNativeDevice) {
this.device = device;
this.connected = device.connected || false;
}
async connect(options?: ConnectionOptions): Promise<void> {
try {
const deviceType = options?.type || this.device.type;
await PosPrinter.connectPrinter(this.device.address, deviceType);
this.connected = true;
this.device.connected = true;
PrinterEventManager.emit(PrinterEvent.DEVICE_CONNECTED, { device: this.device });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.CONNECTION_FAILED,
`Failed to connect to device ${this.device.name}`,
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async disconnect(): Promise<void> {
try {
await PosPrinter.disconnectPrinter();
this.connected = false;
this.device.connected = false;
PrinterEventManager.emit(PrinterEvent.DEVICE_DISCONNECTED, { device: this.device });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.DISCONNECTION_FAILED,
`Failed to disconnect from device ${this.device.name}`,
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async checkConnectionStatus(): Promise<boolean> {
try {
if (!this.device?.address) {
return false;
}
const isConnected = await PosPrinter.isConnected();
this.connected = isConnected;
this.device.connected = isConnected;
return isConnected;
} catch (error) {
console.warn('Failed to check connection status:', error);
this.connected = false;
this.device.connected = false;
return false;
}
}
async getStatus(): Promise<PrinterStatus> {
try {
const rawStatus = await PosPrinter.getStatus();
const status: PrinterStatus = {
online: rawStatus.online ?? true,
paperOut: rawStatus.paperOut ?? false,
coverOpen: rawStatus.coverOpen ?? false,
cutterError: rawStatus.cutterError ?? false,
temperature: rawStatus.temperature ?? 'NORMAL',
voltage: rawStatus.voltage ?? 'NORMAL'
};
return status;
} catch (error) {
throw new PrinterError(
PrinterErrorCode.STATUS_CHECK_FAILED,
'Failed to get printer status',
error
);
}
}
async sendRawCommand(command: number[]): Promise<void> {
const connected = await this.checkConnectionStatus();
if (!connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
try {
await PosPrinter.sendRawCommand(command);
} catch (error) {
throw new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to send raw command',
error
);
}
}
async printText(text: string, options?: TextOptions): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
if (!text || text.trim().length === 0) {
throw new PrinterError(
PrinterErrorCode.INVALID_TEXT,
'Text cannot be empty'
);
}
try {
await PosPrinter.printText(text, options);
PrinterEventManager.emit(PrinterEvent.PRINT_COMPLETED, { device: this.device, data: text });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to print text',
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async printImage(imageUri: string, options?: ImageOptions): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
if (!imageUri) {
throw new PrinterError(
PrinterErrorCode.INVALID_PARAMETER,
'Image URI cannot be empty'
);
}
try {
await PosPrinter.printImage(imageUri, options);
PrinterEventManager.emit(PrinterEvent.PRINT_COMPLETED, { device: this.device, data: imageUri });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to print image',
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async printBarcode(data: string, type: keyof typeof BarcodeTypes, options?: BarcodeOptions): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
if (!data) {
throw new PrinterError(
PrinterErrorCode.INVALID_PARAMETER,
'Barcode data cannot be empty'
);
}
try {
await PosPrinter.printBarcode(data, type, options);
PrinterEventManager.emit(PrinterEvent.PRINT_COMPLETED, { device: this.device, data });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to print barcode',
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async printQRCode(data: string, options?: QRCodeOptions): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
if (!data) {
throw new PrinterError(
PrinterErrorCode.INVALID_PARAMETER,
'QR code data cannot be empty'
);
}
try {
await PosPrinter.printQRCode(data, options);
PrinterEventManager.emit(PrinterEvent.PRINT_COMPLETED, { device: this.device, data });
} catch (error) {
const printerError = new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to print QR code',
error
);
PrinterEventManager.emit(PrinterEvent.PRINT_FAILED, { error: printerError });
throw printerError;
}
}
async cutPaper(): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
try {
await this.sendRawCommand([...ESCPOSCommands.CUT_PAPER]);
} catch (error) {
throw new PrinterError(
PrinterErrorCode.PRINT_FAILED,
'Failed to cut paper',
error
);
}
}
async openCashDrawer(): Promise<void> {
if (!this.connected) {
throw new PrinterError(
PrinterErrorCode.NOT_CONNECTED,
'Device not connected'
);
}
try {
await PosPrinter.openCashDrawer();
} catch (error) {
throw new PrinterError(
PrinterErrorCode.HARDWARE_ERROR,
'Failed to open cash drawer',
error
);
}
}
isConnected(): boolean {
return this.connected;
}
getDevice(): ThermalPrinterNativeDevice {
return this.device;
}
getName(): string {
return this.device.name;
}
getAddress(): string {
return this.device.address;
}
getType(): string {
return this.device.type;
}
}