store/resources/js/composables/useThermalPrinter.ts

105 lines
3.0 KiB
TypeScript

import { computed, ref } from 'vue';
import { encodeOrderReceipt } from '@/lib/thermal-printer/encode-order-receipt';
import { normalizeEncoderOptions } from '@/lib/thermal-printer/normalize-encoder-options';
import {
connectBluetooth,
connectionState,
connectUsb,
disconnect as disconnectTransport,
getBluetoothEncoderSettings,
isWebBluetoothSupported,
isWebSerialSupported,
restoreConnection,
sendPrintData,
tryReconnect as tryReconnectTransport,
} from '@/lib/thermal-printer/stable-transport';
import type { PaperSize } from '@/lib/thermal-printer/types';
import type { OrderListItem } from '@/types/order';
const connecting = ref(false);
async function withConnecting<T>(callback: () => Promise<T>): Promise<T> {
connecting.value = true;
try {
return await callback();
} finally {
connecting.value = false;
}
}
export type PrintOrderReceiptOptions = {
order: OrderListItem;
paperSize: PaperSize;
storeName: string;
storeAddress: string;
};
async function printOrderReceipt(options: PrintOrderReceiptOptions): Promise<void> {
const { order, paperSize, storeName, storeAddress } = options;
let connection = connectionState.value;
if (!connection) {
const restored = await restoreConnection();
connection = connectionState.value;
if (!restored || !connection) {
throw new Error('Printer belum terhubung. Hubungkan printer terlebih dahulu.');
}
}
const bluetoothSettings = connection === 'bluetooth'
? getBluetoothEncoderSettings()
: null;
const encoderOptions = normalizeEncoderOptions({
language: bluetoothSettings?.language,
codepageMapping: bluetoothSettings?.codepageMapping,
});
const encoded = encodeOrderReceipt(order, {
storeName,
storeAddress,
paperSize,
language: connection === 'bluetooth' ? encoderOptions.language : undefined,
codepageMapping: connection === 'bluetooth' ? encoderOptions.codepageMapping : undefined,
});
await sendPrintData(encoded);
}
export function useThermalPrinter() {
const isConnected = computed(() => connectionState.value !== null);
const connectionLabel = computed(() => {
const connection = connectionState.value;
if (connection === 'usb') {
return 'USB';
}
if (connection === 'bluetooth') {
return 'Bluetooth';
}
return null;
});
return {
activeConnection: connectionState,
isConnected,
connectionLabel,
connecting,
connectUsb: () => withConnecting(connectUsb),
connectBluetooth: () => withConnecting(connectBluetooth),
tryReconnect: () => withConnecting(tryReconnectTransport),
disconnect: disconnectTransport,
printOrderReceipt,
supportsUsb: isWebSerialSupported(),
supportsBluetooth: isWebBluetoothSupported(),
};
}
export function getPaperSizeLabel(paperSize: PaperSize): string {
return paperSize;
}