All files / react-app/src/hooks useParams.ts

80% Statements 32/40
72.22% Branches 13/18
75% Functions 6/8
83.33% Lines 30/36

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                      107x 3705x 3705x   3705x   3705x 1439x 54x 34x     1385x 1385x   1385x 1385x   1385x         1385x 1385x             3705x 74x 74x 74x     74x   74x   74x 74x 66x 66x 106x   66x     74x           3705x             3705x    
import LZ from "lz-string";
import { useMemo } from "react";
import { useSearchParams } from "react-router";
 
import { useLocalStorage } from "./useLocalStorage";
 
/**
 * useLzQuery syncs a url query parameter with a given state.
 * LZ is a library which can compresses JSON into a uri string
 * and can decompresses JSON strings into state objects
 */
export const useLzUrl = <T>(props: { key: string; initValue?: T; redirectTab?: string }) => {
  const [params, setParams] = useSearchParams();
  const [query, setQuery] = useLocalStorage("osQuery", null);
 
  const queryString = params.get(props.key) || "";
 
  const state: T = useMemo(() => {
    if (!queryString) {
      if (query) return JSON.parse(query);
      return props.initValue;
    }
 
    const decompress = LZ.decompressFromEncodedURIComponent(queryString);
    Iif (!decompress) return props.initValue;
 
    try {
      const parsed = JSON.parse(decompress);
 
      Iif (props.redirectTab && parsed.tab !== props.redirectTab) {
        setQuery(JSON.stringify(props.initValue));
        return props.initValue;
      }
 
      setQuery(decompress);
      return parsed;
    } catch {
      return props.initValue;
    }
    // adding props.initValue causes this to loop
  }, [queryString, query, setQuery]); // eslint-disable-line react-hooks/exhaustive-deps
 
  const onSet = (arg: (arg: T) => T | T, shouldIsolate?: boolean) => {
    const val = (() => {
      Iif (typeof arg !== "function") return arg;
      return arg(state);
    })();
 
    const compressedValue = LZ.compressToEncodedURIComponent(JSON.stringify(val));
 
    setParams(
      (s) => {
        const prevParams = (() => {
          if (shouldIsolate) return {};
          const nextVal = {} as Record<string, string>;
          for (const param of s.keys()) {
            nextVal[param] = s.get(param) || "";
          }
          return nextVal;
        })();
 
        return { ...prevParams, [props.key]: compressedValue };
      },
      { replace: true },
    );
  };
 
  const onClear = () => {
    setParams((s) => {
      s.delete(props.key);
      return s;
    });
  };
 
  return { state, queryString, onSet, onClear };
};