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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
import { useEffect, useMemo, useRef } from 'react';
import { RoutePath } from '../../shared/routes';
import { useScheduler } from '../../shared/scheduler';
import { getNavigationBase } from '../lib/functions/navigation-base';
import { TransitionType, useHistory } from '../lib/history';
import { useEffectEvent } from '../lib/utility-hooks';
import { useSelector } from '../redux/store';
export default function StateTriggeredNavigation() {
const { location, reset } = useHistory();
const connectedToDaemon = useSelector((state) => state.userInterface.connectedToDaemon);
const loginState = useSelector((state) => state.account.status);
const delayScheduler = useScheduler();
const prevPath = useRef<RoutePath>(getNavigationBase(connectedToDaemon, loginState));
const nextPath = useMemo(
() => getNavigationBase(connectedToDaemon, loginState),
[connectedToDaemon, loginState],
);
const updatePath = useEffectEvent((nextPath: RoutePath) => {
const currentPath = location.pathname as RoutePath;
if (currentPath !== nextPath) {
delayScheduler.cancel();
const transition = getNavigationTransition(currentPath, nextPath);
const delay = getNavigationDelay(currentPath, nextPath);
const navigate = () => {
reset(nextPath, { transition });
};
if (delay) {
delayScheduler.schedule(navigate, delay);
} else {
navigate();
}
}
});
useEffect(() => {
if (nextPath !== prevPath.current) {
prevPath.current = nextPath;
updatePath(nextPath);
}
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nextPath]);
return null;
}
function getNavigationDelay(currentPath: RoutePath, nextPath: RoutePath): number | void {
if (
currentPath === RoutePath.login &&
(nextPath === RoutePath.main || nextPath === RoutePath.expired)
) {
return 1000;
}
}
function getNavigationTransition(currentPath: RoutePath, nextPath: RoutePath) {
// First level contains the possible next locations and the second level contains the
// possible current locations.
const navigationTransitions: Partial<
Record<RoutePath, Partial<Record<RoutePath | '*', TransitionType>>>
> = {
[RoutePath.launch]: {
[RoutePath.login]: TransitionType.pop,
[RoutePath.main]: TransitionType.pop,
'*': TransitionType.dismiss,
},
[RoutePath.login]: {
[RoutePath.launch]: TransitionType.push,
[RoutePath.main]: TransitionType.pop,
[RoutePath.deviceRevoked]: TransitionType.pop,
[RoutePath.tooManyDevices]: TransitionType.pop,
'*': TransitionType.dismiss,
},
[RoutePath.main]: {
[RoutePath.launch]: TransitionType.push,
[RoutePath.login]: TransitionType.push,
[RoutePath.tooManyDevices]: TransitionType.push,
'*': TransitionType.dismiss,
},
[RoutePath.expired]: {
[RoutePath.launch]: TransitionType.push,
[RoutePath.login]: TransitionType.push,
[RoutePath.tooManyDevices]: TransitionType.push,
'*': TransitionType.dismiss,
},
[RoutePath.timeAdded]: {
[RoutePath.expired]: TransitionType.push,
[RoutePath.redeemVoucher]: TransitionType.push,
'*': TransitionType.dismiss,
},
[RoutePath.deviceRevoked]: {
'*': TransitionType.pop,
},
[RoutePath.tooManyDevices]: {
[RoutePath.login]: TransitionType.push,
},
};
return navigationTransitions[nextPath]?.[currentPath] ?? navigationTransitions[nextPath]?.['*'];
}
|