"use client"; import { useState, useEffect, useCallback } from "react"; import { useRouter } from "next/navigation"; import { useAuth } from "@/lib/auth-context"; import { api } from "@/lib/api"; import { QRCodeSVG } from "qrcode.react"; import { Card } from "@/components/ui/Card"; import { GradientSpinner } from "@/components/ui/GradientSpinner"; import { Smartphone, RefreshCw, Check, Clock, Copy, Trash2, AlertCircle } from "lucide-react"; import { cn } from "@/utils/cn"; interface DeviceLinkCode { code: string; expiresAt: string; expiresIn: number; } interface LinkedDevice { id: string; name: string; lastUsed: string; createdAt: string; } export default function DeviceLinkPage() { const router = useRouter(); const { isAuthenticated, isLoading: authLoading } = useAuth(); const [linkCode, setLinkCode] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const [timeRemaining, setTimeRemaining] = useState(0); const [codeUsed, setCodeUsed] = useState(false); const [devices, setDevices] = useState([]); const [isLoadingDevices, setIsLoadingDevices] = useState(true); const [copied, setCopied] = useState(false); const [error, setError] = useState(null); // Redirect if not authenticated useEffect(() => { if (!authLoading && !isAuthenticated) { router.push("/login"); } }, [isAuthenticated, authLoading, router]); // Load linked devices const loadDevices = useCallback(async () => { try { const response = await api.request("/device-link/devices"); setDevices(response); } catch (err) { console.error("Failed to load devices:", err); } finally { setIsLoadingDevices(false); } }, []); useEffect(() => { if (isAuthenticated) { loadDevices(); } }, [isAuthenticated, loadDevices]); // Generate a new link code const generateCode = async () => { setIsGenerating(true); setError(null); setCodeUsed(false); try { const response = await api.request("/device-link/generate", { method: "POST", }); setLinkCode(response); setTimeRemaining(response.expiresIn); } catch (err) { setError(err instanceof Error ? err.message : "Failed to generate code"); } finally { setIsGenerating(false); } }; // Countdown timer useEffect(() => { if (timeRemaining <= 0 || codeUsed) return; const timer = setInterval(() => { setTimeRemaining((prev) => { if (prev <= 1) { clearInterval(timer); return 0; } return prev - 1; }); }, 1000); return () => clearInterval(timer); }, [timeRemaining, codeUsed]); // Poll for code usage useEffect(() => { if (!linkCode || timeRemaining <= 0 || codeUsed) return; const pollInterval = setInterval(async () => { try { const status = await api.request<{ status: string; deviceName?: string }>( `/device-link/status/${linkCode.code}` ); if (status.status === "used") { setCodeUsed(true); loadDevices(); // Refresh devices list } } catch (err) { console.error("Failed to check code status:", err); } }, 2000); return () => clearInterval(pollInterval); }, [linkCode, timeRemaining, codeUsed, loadDevices]); // Copy code to clipboard const copyCode = () => { if (linkCode) { navigator.clipboard.writeText(linkCode.code); setCopied(true); setTimeout(() => setCopied(false), 2000); } }; // Revoke a device const revokeDevice = async (deviceId: string) => { try { await api.request(`/device-link/devices/${deviceId}`, { method: "DELETE", }); setDevices((prev) => prev.filter((d) => d.id !== deviceId)); } catch (err) { console.error("Failed to revoke device:", err); } }; // Format time remaining const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, "0")}`; }; // Build QR code URL (contains code and server URL) const getQRValue = () => { if (!linkCode) return ""; const serverUrl = typeof window !== "undefined" ? window.location.origin : ""; return `lidify://link?code=${linkCode.code}&server=${encodeURIComponent(serverUrl)}`; }; if (authLoading) { return (
); } return (
{/* Header gradient */}
{/* Title */}

Link Mobile Device

Scan the QR code or enter the code in the Lidify app to link your device

{/* QR Code Section */}

Device Link Code

{error && (
{error}
)} {!linkCode && !isGenerating && (

Generate a one-time code to link your mobile device

)} {isGenerating && (
)} {linkCode && !isGenerating && (
{codeUsed ? (

Device Linked!

Your device has been successfully connected

) : timeRemaining <= 0 ? (

Code Expired

Generate a new code to continue

) : ( <> {/* QR Code */}
{/* Code Display */}

Or enter this code manually:

{linkCode.code}
{/* Timer */}
Expires in {formatTime(timeRemaining)}
)}
)}
{/* Linked Devices Section */}

Linked Devices

{isLoadingDevices ? (
) : devices.length === 0 ? (

No devices linked yet

) : (
{devices.map((device) => (

{device.name}

Last used:{" "} {new Date(device.lastUsed).toLocaleDateString()}

))}
)}
{/* Instructions */}

How to Link Your Device

  1. 1 Open the Lidify app on your mobile device
  2. 2 Tap "Scan QR Code" or "Enter Code" on the login screen
  3. 3 Scan the QR code above, or manually enter the 6-digit code
  4. 4 Your device will be automatically logged in and linked to your account
); }