UNPKG

@oxyhq/services

Version:

Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀

399 lines (382 loc) • 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useAsync = useAsync; exports.useAsyncEffect = useAsyncEffect; exports.useClickOutside = useClickOutside; exports.useCounter = useCounter; exports.useDebounce = useDebounce; exports.useFormValidation = useFormValidation; exports.useKeyPress = useKeyPress; exports.useLocalStorage = useLocalStorage; exports.useMediaQuery = useMediaQuery; exports.useOnlineStatus = useOnlineStatus; exports.usePrevious = usePrevious; exports.useScrollPosition = useScrollPosition; exports.useSessionStorage = useSessionStorage; exports.useThrottle = useThrottle; exports.useToggle = useToggle; exports.useWindowSize = useWindowSize; var _react = require("react"); /** * React hook utilities for common patterns and state management */ /** * Hook for managing async operations with loading, error, and data states */ function useAsync(asyncFn, deps = []) { const [data, setData] = (0, _react.useState)(null); const [loading, setLoading] = (0, _react.useState)(false); const [error, setError] = (0, _react.useState)(null); const execute = (0, _react.useCallback)(async () => { setLoading(true); setError(null); try { const result = await asyncFn(); setData(result); return result; } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } finally { setLoading(false); } }, deps); return { data, loading, error, execute }; } /** * Hook for managing async operations that execute on mount */ function useAsyncEffect(asyncFn, deps = []) { const [data, setData] = (0, _react.useState)(null); const [loading, setLoading] = (0, _react.useState)(true); const [error, setError] = (0, _react.useState)(null); (0, _react.useEffect)(() => { let mounted = true; const execute = async () => { try { const result = await asyncFn(); if (mounted) { setData(result); setLoading(false); } } catch (err) { if (mounted) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); setLoading(false); } } }; execute(); return () => { mounted = false; }; }, deps); return { data, loading, error }; } /** * Hook for debounced values */ function useDebounce(value, delay) { const [debouncedValue, setDebouncedValue] = (0, _react.useState)(value); (0, _react.useEffect)(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; } /** * Hook for throttled values */ function useThrottle(value, delay) { const [throttledValue, setThrottledValue] = (0, _react.useState)(value); const lastRun = (0, _react.useRef)(Date.now()); (0, _react.useEffect)(() => { const handler = setTimeout(() => { if (Date.now() - lastRun.current >= delay) { setThrottledValue(value); lastRun.current = Date.now(); } }, delay - (Date.now() - lastRun.current)); return () => { clearTimeout(handler); }; }, [value, delay]); return throttledValue; } /** * Hook for previous value */ function usePrevious(value) { const ref = (0, _react.useRef)(undefined); (0, _react.useEffect)(() => { ref.current = value; }); return ref.current; } /** * Hook for boolean state with toggle */ function useToggle(initialValue = false) { const [value, setValue] = (0, _react.useState)(initialValue); const toggle = (0, _react.useCallback)(() => setValue(v => !v), []); const setTrue = (0, _react.useCallback)(() => setValue(true), []); const setFalse = (0, _react.useCallback)(() => setValue(false), []); return { value, toggle, setTrue, setFalse, setValue }; } /** * Hook for counter state */ function useCounter(initialValue = 0) { const [count, setCount] = (0, _react.useState)(initialValue); const increment = (0, _react.useCallback)(() => setCount(c => c + 1), []); const decrement = (0, _react.useCallback)(() => setCount(c => c - 1), []); const reset = (0, _react.useCallback)(() => setCount(initialValue), [initialValue]); const setValue = (0, _react.useCallback)(value => setCount(value), []); return { count, increment, decrement, reset, setValue }; } /** * Hook for local storage */ function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = (0, _react.useState)(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error(`Error reading localStorage key "${key}":`, error); return initialValue; } }); const setValue = (0, _react.useCallback)(value => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(`Error setting localStorage key "${key}":`, error); } }, [key, storedValue]); return [storedValue, setValue]; } /** * Hook for session storage */ function useSessionStorage(key, initialValue) { const [storedValue, setStoredValue] = (0, _react.useState)(() => { try { const item = window.sessionStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error(`Error reading sessionStorage key "${key}":`, error); return initialValue; } }); const setValue = (0, _react.useCallback)(value => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.sessionStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(`Error setting sessionStorage key "${key}":`, error); } }, [key, storedValue]); return [storedValue, setValue]; } /** * Hook for window size */ function useWindowSize() { const [windowSize, setWindowSize] = (0, _react.useState)({ width: window.innerWidth, height: window.innerHeight }); (0, _react.useEffect)(() => { const handleResize = () => { setWindowSize({ width: window.innerWidth, height: window.innerHeight }); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return windowSize; } /** * Hook for scroll position */ function useScrollPosition() { const [scrollPosition, setScrollPosition] = (0, _react.useState)(0); (0, _react.useEffect)(() => { const handleScroll = () => { setScrollPosition(window.pageYOffset); }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); return scrollPosition; } /** * Hook for online/offline status */ function useOnlineStatus() { const [isOnline, setIsOnline] = (0, _react.useState)(navigator.onLine); (0, _react.useEffect)(() => { const handleOnline = () => setIsOnline(true); const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline; } /** * Hook for media queries */ function useMediaQuery(query) { const [matches, setMatches] = (0, _react.useState)(false); (0, _react.useEffect)(() => { const media = window.matchMedia(query); if (media.matches !== matches) { setMatches(media.matches); } const listener = () => setMatches(media.matches); media.addEventListener('change', listener); return () => media.removeEventListener('change', listener); }, [matches, query]); return matches; } /** * Hook for keyboard events */ function useKeyPress(targetKey) { const [keyPressed, setKeyPressed] = (0, _react.useState)(false); (0, _react.useEffect)(() => { const downHandler = ({ key }) => { if (key === targetKey) { setKeyPressed(true); } }; const upHandler = ({ key }) => { if (key === targetKey) { setKeyPressed(false); } }; window.addEventListener('keydown', downHandler); window.addEventListener('keyup', upHandler); return () => { window.removeEventListener('keydown', downHandler); window.removeEventListener('keyup', upHandler); }; }, [targetKey]); return keyPressed; } /** * Hook for click outside detection */ function useClickOutside(ref, handler) { (0, _react.useEffect)(() => { const listener = event => { if (!ref.current || ref.current.contains(event.target)) { return; } handler(); }; document.addEventListener('mousedown', listener); document.addEventListener('touchstart', listener); return () => { document.removeEventListener('mousedown', listener); document.removeEventListener('touchstart', listener); }; }, [ref, handler]); } /** * Hook for form validation */ function useFormValidation(initialValues, validationSchema) { const [values, setValues] = (0, _react.useState)(initialValues); const [errors, setErrors] = (0, _react.useState)({}); const [touched, setTouched] = (0, _react.useState)({}); const validate = (0, _react.useCallback)(valuesToValidate => { return validationSchema(valuesToValidate); }, [validationSchema]); const setValue = (0, _react.useCallback)((field, value) => { setValues(prev => ({ ...prev, [field]: value })); if (touched[field]) { const newErrors = validate({ ...values, [field]: value }); setErrors(prev => ({ ...prev, [field]: newErrors[field] })); } }, [values, touched, validate]); const setTouchedField = (0, _react.useCallback)(field => { setTouched(prev => ({ ...prev, [field]: true })); const newErrors = validate(values); setErrors(prev => ({ ...prev, [field]: newErrors[field] })); }, [values, validate]); const isValid = (0, _react.useMemo)(() => { const validationErrors = validate(values); return Object.keys(validationErrors).length === 0; }, [values, validate]); return { values, errors, touched, isValid, setValue, setTouchedField, setValues, setErrors, setTouched }; } //# sourceMappingURL=hookUtils.js.map