All files / memory-monitor/src/hooks useSettings.ts

77.14% Statements 27/35
68.18% Branches 15/22
75% Functions 9/12
78.12% Lines 25/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139                                                                            64x   64x 27x     27x 15x 15x                                                     64x   64x 64x           64x     64x 27x         27x 27x       27x       64x   15x 15x             64x 54x 27x   54x     64x             64x             64x              
import { useState, useCallback, useEffect, useRef } from "react";
import type { PanelSettings } from "../types";
import { DEFAULT_SETTINGS, DEFAULT_STORAGE_KEY } from "../constants";
import { safeGetJSON, safeSetJSON, isBrowser } from "../utils/storage";
 
/**
 * Options for useSettings hook
 */
export interface UseSettingsOptions {
  /** Storage key for persistence */
  storageKey?: string;
  /** Whether to persist settings */
  persist?: boolean;
  /** Initial settings override */
  initialSettings?: Partial<PanelSettings>;
}
 
/**
 * Return type for useSettings hook
 */
export interface UseSettingsReturn {
  /** Current settings */
  settings: PanelSettings;
  /** Update settings (partial update) */
  updateSettings: (updates: Partial<PanelSettings>) => void;
  /** Reset settings to defaults */
  resetSettings: () => void;
  /** Whether settings have been loaded */
  isLoaded: boolean;
}
 
/**
 * Debounce function for saving settings
 */
function debounce<T extends (...args: never[]) => void>(
  fn: T,
  delay: number
): T {
  let timeoutId: ReturnType<typeof setTimeout> | null = null;
 
  return ((...args: Parameters<T>) => {
    Iif (timeoutId) {
      clearTimeout(timeoutId);
    }
    timeoutId = setTimeout(() => {
      fn(...args);
      timeoutId = null;
    }, delay);
  }) as T;
}
 
/**
 * Hook to manage panel settings with optional persistence
 *
 * @param options - Configuration options
 * @returns Settings and update functions
 *
 * @example
 * ```tsx
 * const { settings, updateSettings } = useSettings({
 *   storageKey: 'my-panel-settings',
 *   persist: true,
 * });
 *
 * // Update a single setting
 * updateSettings({ warningThreshold: 80 });
 * ```
 */
export function useSettings(options: UseSettingsOptions = {}): UseSettingsReturn {
  const {
    storageKey = DEFAULT_STORAGE_KEY,
    persist = true,
    initialSettings = {},
  } = options;
 
  const [isLoaded, setIsLoaded] = useState(false);
  const [settings, setSettings] = useState<PanelSettings>(() => ({
    ...DEFAULT_SETTINGS,
    ...initialSettings,
  }));
 
  // Ref to track if we should save
  const shouldSaveRef = useRef(false);
 
  // Load settings from storage on mount
  useEffect(() => {
    Iif (!isBrowser() || !persist) {
      setIsLoaded(true);
      return;
    }
 
    const stored = safeGetJSON<Partial<PanelSettings>>(storageKey, {});
    setSettings((prev) => ({
      ...prev,
      ...stored,
    }));
    setIsLoaded(true);
  }, [storageKey, persist]);
 
  // Debounced save function
  const saveToStorage = useCallback(
    debounce((settingsToSave: PanelSettings) => {
      Eif (persist && isBrowser()) {
        safeSetJSON(storageKey, settingsToSave);
      }
    }, 500),
    [storageKey, persist]
  );
 
  // Save settings when they change
  useEffect(() => {
    if (shouldSaveRef.current && isLoaded) {
      saveToStorage(settings);
    }
    shouldSaveRef.current = true;
  }, [settings, saveToStorage, isLoaded]);
 
  const updateSettings = useCallback((updates: Partial<PanelSettings>) => {
    setSettings((prev) => ({
      ...prev,
      ...updates,
    }));
  }, []);
 
  const resetSettings = useCallback(() => {
    setSettings({ ...DEFAULT_SETTINGS, ...initialSettings });
    if (persist && isBrowser()) {
      safeSetJSON(storageKey, { ...DEFAULT_SETTINGS, ...initialSettings });
    }
  }, [initialSettings, persist, storageKey]);
 
  return {
    settings,
    updateSettings,
    resetSettings,
    isLoaded,
  };
}