131 lines
3.8 KiB
Vue
131 lines
3.8 KiB
Vue
<script setup lang="ts">
|
|
import { Bluetooth, PlugZap, Usb } from '@lucide/vue';
|
|
import { onMounted, ref } from 'vue';
|
|
import { toast } from 'vue-sonner';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from '@/components/ui/popover';
|
|
import { useThermalPrinter } from '@/composables/useThermalPrinter';
|
|
|
|
const open = ref(false);
|
|
|
|
const {
|
|
isConnected,
|
|
connectionLabel,
|
|
connecting,
|
|
connectUsb,
|
|
connectBluetooth,
|
|
tryReconnect,
|
|
disconnect,
|
|
supportsUsb,
|
|
supportsBluetooth,
|
|
} = useThermalPrinter();
|
|
|
|
onMounted(async () => {
|
|
await tryReconnect();
|
|
});
|
|
|
|
async function handleConnectUsb() {
|
|
try {
|
|
await connectUsb();
|
|
open.value = false;
|
|
toast.success('Printer USB terhubung.');
|
|
} catch (error) {
|
|
const message = error instanceof Error
|
|
? error.message
|
|
: 'Gagal menghubungkan printer USB.';
|
|
|
|
toast.error(message);
|
|
}
|
|
}
|
|
|
|
async function handleConnectBluetooth() {
|
|
try {
|
|
await connectBluetooth();
|
|
open.value = false;
|
|
toast.success('Printer Bluetooth terhubung.');
|
|
} catch (error) {
|
|
const message = error instanceof Error
|
|
? error.message
|
|
: 'Gagal menghubungkan printer Bluetooth.';
|
|
|
|
toast.error(message);
|
|
}
|
|
}
|
|
|
|
function handleDisconnect() {
|
|
disconnect();
|
|
open.value = false;
|
|
toast.success('Printer terputus.');
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Popover v-model:open="open">
|
|
<PopoverTrigger as-child>
|
|
<Button variant="outline" class="shrink-0 gap-2 self-start sm:self-center">
|
|
<PlugZap class="size-4" />
|
|
Printer
|
|
<Badge
|
|
:variant="isConnected ? 'default' : 'secondary'"
|
|
class="rounded-full px-2 text-xs"
|
|
>
|
|
{{ isConnected ? connectionLabel : 'Offline' }}
|
|
</Badge>
|
|
</Button>
|
|
</PopoverTrigger>
|
|
|
|
<PopoverContent align="end" class="w-64 space-y-3 p-4">
|
|
<div class="space-y-1">
|
|
<p class="text-sm font-medium">
|
|
Koneksi Printer
|
|
</p>
|
|
<p class="text-muted-foreground text-xs">
|
|
Hubungkan printer thermal sebelum mencetak struk.
|
|
</p>
|
|
</div>
|
|
|
|
<div v-if="isConnected" class="rounded-md border bg-muted/40 px-3 py-2 text-sm">
|
|
Terhubung via <strong>{{ connectionLabel }}</strong>
|
|
</div>
|
|
|
|
<div class="grid gap-2">
|
|
<Button
|
|
variant="outline"
|
|
class="justify-start gap-2"
|
|
:disabled="!supportsUsb || connecting"
|
|
@click="handleConnectUsb"
|
|
>
|
|
<Usb class="size-4" />
|
|
{{ isConnected && connectionLabel === 'USB' ? 'Hubungkan ulang USB' : 'Hubungkan USB' }}
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
class="justify-start gap-2"
|
|
:disabled="!supportsBluetooth || connecting"
|
|
@click="handleConnectBluetooth"
|
|
>
|
|
<Bluetooth class="size-4" />
|
|
{{ isConnected && connectionLabel === 'Bluetooth' ? 'Hubungkan ulang Bluetooth' : 'Hubungkan Bluetooth' }}
|
|
</Button>
|
|
</div>
|
|
|
|
<Button
|
|
v-if="isConnected"
|
|
variant="ghost"
|
|
size="sm"
|
|
class="w-full"
|
|
:disabled="connecting"
|
|
@click="handleDisconnect"
|
|
>
|
|
Putuskan koneksi
|
|
</Button>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</template>
|