import { create } from 'zustand'; import { api } from '@/lib/api'; import type { Device, DeviceEvent } from '@/types/device'; import { showSuccess, showError, showApiError } from '@/lib/toast'; import { getTranslation } from '@/lib/i18n'; import { useActivityStore } from './activity-store'; interface DeviceState { devices: Device[]; selectedDevice: Device | null; loading: boolean; scanning: boolean; connectingId: string | null; disconnectingId: string | null; udevHint: boolean; fetchDevices: () => Promise; scanDevices: () => Promise; fetchDevice: (id: string) => Promise; connectDevice: (id: string) => Promise; disconnectDevice: (id: string) => Promise; handleEvent: (event: DeviceEvent) => void; } export const useDeviceStore = create((set, get) => ({ devices: [], selectedDevice: null, loading: false, scanning: false, connectingId: null, disconnectingId: null, udevHint: false, scanDevices: async () => { set({ scanning: true }); try { const res = await api.post<{ devices: Device[]; udevHint?: boolean }>('/devices/scan'); if (res.success && res.data) { set({ devices: res.data.devices || [], scanning: false, udevHint: !!res.data.udevHint }); } else { set({ scanning: false }); showApiError(res.error); } } catch { set({ scanning: false }); showError(getTranslation().t('errors.failedToLoadDevices')); } }, fetchDevices: async () => { set({ loading: true }); try { const res = await api.get<{ devices: Device[]; udevHint?: boolean }>('/devices'); if (res.success && res.data) { set({ devices: res.data.devices || [], loading: false, udevHint: !!res.data.udevHint }); } else { set({ loading: false }); showApiError(res.error); } } catch { set({ loading: false }); showError(getTranslation().t('errors.failedToLoadDevices')); } }, fetchDevice: async (id) => { const res = await api.get(`/devices/${id}`); if (res.success && res.data) { set({ selectedDevice: res.data }); } else { showApiError(res.error); } }, connectDevice: async (id) => { set({ connectingId: id }); try { const res = await api.post(`/devices/${id}/connect`); if (res.success) { showSuccess(getTranslation().t('errors.deviceConnected')); const name = get().devices.find((d) => d.id === id)?.name || id; useActivityStore.getState().addActivity('device_connect', `Device connected: ${name}`); } else { const msg = res.error?.message || ''; if (/winusb|error.{0,5}code.{0,5}28|KP_ERROR_CONNECT_FAILED/i.test(msg)) { showApiError({ code: 'DRIVER_NOT_INSTALLED', message: '連線失敗:Kneron WinUSB driver 尚未安裝。\n' + '請點擊右上角「安裝 USB Driver」按鈕(需要系統管理員權限),安裝完成後重新點選連線。', }); } else { showApiError(res.error); } } } finally { set({ connectingId: null }); get().fetchDevices(); } }, disconnectDevice: async (id) => { set({ disconnectingId: id }); try { const res = await api.post(`/devices/${id}/disconnect`); if (res.success) { showSuccess(getTranslation().t('errors.deviceDisconnected')); const name = get().devices.find((d) => d.id === id)?.name || id; useActivityStore.getState().addActivity('device_disconnect', `Device disconnected: ${name}`); } else { showApiError(res.error); } } finally { set({ disconnectingId: null }); get().fetchDevices(); } }, handleEvent: (event) => { set((state) => { const devices = [...state.devices]; const idx = devices.findIndex((d) => d.id === event.device.id); if (event.event === 'discovered') { if (idx === -1) devices.push(event.device); } else if (event.event === 'removed') { if (idx !== -1) devices.splice(idx, 1); } else if (event.event === 'updated') { if (idx !== -1) devices[idx] = event.device; } return { devices }; }); }, }));