Passed
Push — dev ( 4bcf07...4220fc )
by
unknown
04:21
created

resources/assets/js/helpers/router.tsx   A

Complexity

Total Complexity 5
Complexity/F 0

Size

Lines of Code 104
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 5
eloc 81
c 0
b 0
f 0
dl 0
loc 104
rs 10
mnd 5
bc 5
fnc 0
bpm 0
cpm 0
noi 0
1
import { createBrowserHistory, Location } from "history";
2
import UniversalRouter, { Routes } from "universal-router";
3
import React, { useState, useEffect, useMemo, ReactElement } from "react";
4
import { IntlShape, MessageDescriptor } from "react-intl";
5
import { removeBaseUrl } from "./routes";
6
7
const HISTORY = createBrowserHistory();
8
9
// Current implementation adapted from https://codesandbox.io/s/vyx8q7jvk7
10
11
export const useLocation = (): Location<any> => {
12
  const history = HISTORY;
13
  const [location, setLocation] = useState(history.location);
14
  useEffect((): (() => void) => {
15
    const unListen = history.listen(({ location: newLocation }): void =>
16
      setLocation(newLocation),
17
    );
18
    return (): void => unListen();
19
  }, [history]);
20
  return location;
21
};
22
23
// Scroll to element specified in the url hash, if possible
24
export const useUrlHash = (): void => {
25
  const location = useLocation();
26
  const [hashFound, setHashFound] = useState(false);
27
  useEffect((): void => {
28
    if (location.hash && !hashFound) {
29
      const hash = location.hash.startsWith("#")
30
        ? location.hash.substring(1)
31
        : location.hash;
32
      const element = document.getElementById(hash);
33
      if (element) {
34
        setHashFound(true);
35
        window.scrollTo(0, element.offsetTop);
36
      }
37
    }
38
  }, [location.hash, hashFound]);
39
};
40
41
export const navigate = (url: string): void => {
42
  // The history object has been initialized with the app's base url, so ensure it's not also part of the specified url.
43
  const path = removeBaseUrl(url);
44
  HISTORY.push(path);
45
};
46
47
export const redirect = (url: string): void => {
48
  // The history object has been initialized with the app's base url, so ensure it's not also part of the specified url.
49
  const path = removeBaseUrl(url);
50
  HISTORY.replace(path);
51
};
52
53
export interface RouterResult {
54
  title: MessageDescriptor;
55
  component: ReactElement;
56
  redirect?: string;
57
}
58
59
export const useRouter = (
60
  routes: Routes<any, RouterResult>,
61
  intl: IntlShape,
62
): React.ReactElement | null => {
63
  const location = useLocation();
64
  const router = useMemo(() => new UniversalRouter(routes), [routes]);
65
  const [component, setComponent] = useState<React.ReactElement | null>(null);
66
  const path = location.pathname;
67
  // Render the result of routing
68
  useEffect((): void => {
69
    router.resolve(path).then((result): void => {
70
      if (result.redirect) {
71
        redirect(result.redirect);
72
      } else {
73
        // Dynamically update the page title and header on step changes
74
        const title = intl.formatMessage(result.title);
75
        document.title = title;
76
        const h1 = document.querySelector("h1");
77
        if (h1) h1.innerHTML = title;
78
        setComponent(result.component);
79
      }
80
    });
81
  }, [intl, location, router]);
82
83
  return component;
84
};
85
86
export const Link: React.FC<{ href: string; title: string }> = ({
87
  href,
88
  title,
89
  children,
90
  ...props
91
}): React.ReactElement => (
92
  <a
93
    href={href}
94
    title={title}
95
    {...props}
96
    onClick={(event): void => {
97
      event.preventDefault();
98
      navigate(href);
99
    }}
100
  >
101
    {children}
102
  </a>
103
);
104