From 7eb8ccae48b0cc18a9dcaa9c3626a02df8e6d919 Mon Sep 17 00:00:00 2001
From: JustZvan <justzvan@justzvan.xyz>
Date: Fri, 6 Feb 2026 13:22:33 +0100
Subject: feat: initial commit!

---
 lib/device.tsx | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 lib/device.tsx

(limited to 'lib/device.tsx')

diff --git a/lib/device.tsx b/lib/device.tsx
new file mode 100644
index 0000000..e0ec600
--- /dev/null
+++ b/lib/device.tsx
@@ -0,0 +1,90 @@
+import {
+  createContext,
+  ReactNode,
+  useCallback,
+  useContext,
+  useEffect,
+  useState,
+} from "react";
+import { apiClient, getDevices } from "../api";
+import { Device } from "../api/types";
+import { useAuth } from "./auth";
+
+type DeviceContextType = {
+  devices: Device[];
+  selectedDevice: Device | null;
+  isLoading: boolean;
+  selectDevice: (device: Device) => Promise<void>;
+  refreshDevices: () => Promise<void>;
+};
+
+const DeviceContext = createContext<DeviceContextType | null>(null);
+
+export function DeviceProvider({ children }: { children: ReactNode }) {
+  const [devices, setDevices] = useState<Device[]>([]);
+  const [selectedDevice, setSelectedDevice] = useState<Device | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const { isAuthenticated } = useAuth();
+
+  const refreshDevices = useCallback(async () => {
+    if (!isAuthenticated) {
+      setIsLoading(false);
+      return;
+    }
+
+    setIsLoading(true);
+    try {
+      const fetchedDevices = await getDevices();
+      setDevices(fetchedDevices);
+
+      // If no device is selected, try to restore from storage or select first device
+      if (!selectedDevice && fetchedDevices.length > 0) {
+        const savedDeviceId = apiClient.getSelectedDeviceId();
+        const savedDevice = fetchedDevices.find((d) => d.id === savedDeviceId);
+
+        if (savedDevice) {
+          setSelectedDevice(savedDevice);
+        } else {
+          // Select first device by default
+          setSelectedDevice(fetchedDevices[0]!);
+          await apiClient.setSelectedDevice(fetchedDevices[0]!.id);
+        }
+      }
+    } catch (e) {
+      console.error("Failed to refresh devices", e);
+    } finally {
+      setIsLoading(false);
+    }
+  }, [selectedDevice, isAuthenticated]);
+
+  useEffect(() => {
+    refreshDevices();
+  }, [refreshDevices]);
+
+  const selectDevice = useCallback(async (device: Device) => {
+    setSelectedDevice(device);
+    await apiClient.setSelectedDevice(device.id);
+  }, []);
+
+  return (
+    <DeviceContext.Provider
+      value={{
+        devices,
+        selectedDevice,
+        isLoading,
+        selectDevice,
+        refreshDevices,
+      }}
+    >
+      {children}
+    </DeviceContext.Provider>
+  );
+}
+
+export function useDevice() {
+  const context = useContext(DeviceContext);
+  if (!context) {
+    throw new Error("useDevice must be used within a DeviceProvider");
+  }
+  return context;
+}
-- 
cgit v1.2.3

