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                      106x 3473x 3473x   3473x   3473x 1310x 54x 14x     1256x 1256x   1256x 1256x   1256x         1256x 1256x             3473x 72x 72x 72x     72x   72x   72x 72x 64x 64x 102x   64x     72x           3473x             3473x    
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 };
};