{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "use-online-status", "dependencies": [ "lodash" ], "files": [ { "path": "registry/hooks/use-online-status.tsx", "content": "\"use client\"\n\nimport { useCallback, useEffect, useState } from \"react\"\nimport { debounce } from \"lodash\"\n\ninterface ConnectionState {\n isOnline: boolean\n lastChanged: string\n connectionQuality: \"excellent\" | \"good\" | \"poor\" | \"unknown\"\n latency: number\n isRetrying: boolean\n}\n\nconst useOnlineStatus = (\n options = {\n debounceTime: 1000,\n pingInterval: 30000,\n pingTimeout: 5000,\n pingURL: \"https://www.google.com/favicon.ico\",\n }\n) => {\n const [state, setState] = useState({\n isOnline: navigator.onLine,\n lastChanged: new Date().toISOString(),\n connectionQuality: \"unknown\",\n latency: 0,\n isRetrying: false,\n })\n\n // Measure connection quality using Resource Timing API\n const checkConnectionQuality = useCallback(async () => {\n try {\n const startTime = performance.now()\n const response = await fetch(options.pingURL, {\n mode: \"no-cors\",\n cache: \"no-cache\",\n })\n console.log(response)\n const endTime = performance.now()\n const latency = endTime - startTime\n\n let quality: \"excellent\" | \"good\" | \"poor\" | \"unknown\" = \"unknown\"\n if (latency < 100) quality = \"excellent\"\n else if (latency < 300) quality = \"good\"\n else quality = \"poor\"\n\n setState((prev) => ({\n ...prev,\n connectionQuality: quality,\n latency,\n }))\n } catch (error) {\n setState((prev) => ({\n ...prev,\n isOnline: false,\n connectionQuality: \"unknown\",\n latency: -1,\n }))\n }\n }, [options.pingURL])\n\n // Debounced status update to prevent rapid changes\n const updateOnlineStatus = useCallback(\n debounce((isOnline: boolean) => {\n setState((prev) => ({\n ...prev,\n isOnline,\n lastChanged: new Date().toISOString(),\n isRetrying: false,\n }))\n if (isOnline) {\n checkConnectionQuality()\n }\n }, options.debounceTime),\n [checkConnectionQuality, options.debounceTime]\n )\n\n // Manual retry connection\n const retryConnection = useCallback(async () => {\n if (state.isOnline || state.isRetrying) return\n\n setState((prev) => ({\n ...prev,\n isRetrying: true,\n }))\n\n try {\n await fetch(options.pingURL, { mode: \"no-cors\" })\n updateOnlineStatus(true)\n } catch (error) {\n setState((prev) => ({\n ...prev,\n isRetrying: false,\n }))\n }\n }, [state.isOnline, state.isRetrying, options.pingURL, updateOnlineStatus])\n\n useEffect(() => {\n const handleOnline = () => updateOnlineStatus(true)\n const handleOffline = () => updateOnlineStatus(false)\n\n window.addEventListener(\"online\", handleOnline)\n window.addEventListener(\"offline\", handleOffline)\n\n // Set up periodic connection quality checks\n const intervalId = setInterval(checkConnectionQuality, options.pingInterval)\n\n // Initial connection quality check\n checkConnectionQuality()\n\n return () => {\n window.removeEventListener(\"online\", handleOnline)\n window.removeEventListener(\"offline\", handleOffline)\n clearInterval(intervalId)\n updateOnlineStatus.cancel()\n }\n }, [updateOnlineStatus, checkConnectionQuality, options.pingInterval])\n\n return {\n ...state,\n checkConnectionNow: checkConnectionQuality,\n retryConnection,\n }\n}\n\nexport default useOnlineStatus\n", "type": "registry:hook", "target": "hooks/use-online-status.tsx" } ], "type": "registry:hook" }