Passed
Push — feature/post-covid-application... ( 4340d4...92a3aa )
by Yonathan
08:31 queued 01:05
created

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

Complexity

Total Complexity 4
Complexity/F 0

Size

Lines of Code 98
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 4
eloc 77
mnd 4
bc 4
fnc 0
dl 0
loc 98
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 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 interface RouterResult {
42
  title: MessageDescriptor;
43
  component: ReactElement;
44
}
45
export const useRouter = (
46
  routes: Routes<any, RouterResult>,
47
  intl: IntlShape,
48
): React.ReactElement | null => {
49
  const location = useLocation();
50
  const router = useMemo(() => new UniversalRouter(routes), [routes]);
51
  const [component, setComponent] = useState<React.ReactElement | null>(null);
52
  const path = location.pathname;
53
  // Render the result of routing
54
  useEffect((): void => {
55
    router.resolve(path).then((result): void => {
56
      // Dynamically update the page title and header on step changes
57
      const title = intl.formatMessage(result.title);
58
      document.title = title;
59
      const h1 = document.querySelector("h1");
60
      if (h1) h1.innerHTML = title;
61
      setComponent(result.component);
62
    });
63
  }, [intl, location, router]);
64
65
  return component;
66
};
67
68
export const navigate = (url: string): void => {
69
  // The history object has been initialized with the app's base url, so ensure it's not also part of the specified url.
70
  const path = removeBaseUrl(url);
71
  HISTORY.push(path);
72
};
73
74
export const redirect = (url: string): void => {
75
  // The history object has been initialized with the app's base url, so ensure it's not also part of the specified url.
76
  const path = removeBaseUrl(url);
77
  HISTORY.replace(path);
78
};
79
80
export const Link: React.FC<{ href: string; title: string }> = ({
81
  href,
82
  title,
83
  children,
84
}): React.ReactElement => (
85
  <a
86
    href={href}
87
    title={title}
88
    onClick={(event): void => {
89
      event.preventDefault();
90
      navigate(href);
91
    }}
92
  >
93
    {children}
94
  </a>
95
);
96