diff --git a/ts/components/OnionStatusDialog.tsx b/ts/components/OnionStatusDialog.tsx index bee29d826..8a5aa1a86 100644 --- a/ts/components/OnionStatusDialog.tsx +++ b/ts/components/OnionStatusDialog.tsx @@ -18,6 +18,11 @@ import countryLookup from 'country-code-lookup'; import { useTheme } from 'styled-components'; import { Snode } from '../data/data'; import { onionPathModal } from '../state/ducks/modalDialog'; +import { + getFirstOnionPath, + getFirstOnionPathLength, + getOnionPathsCount, +} from '../state/selectors/onions'; // tslint:disable-next-line: no-submodule-imports import useNetworkState from 'react-use/lib/useNetworkState'; @@ -35,8 +40,7 @@ export type StatusLightType = { }; const OnionPathModalInner = () => { - const onionNodes = useSelector((state: StateType) => state.onionPaths.snodePath); - const onionPath = onionNodes; + const onionPath = useSelector(getFirstOnionPath); // including the device and destination in calculation const glowDuration = onionPath.length + 2; @@ -44,7 +48,7 @@ const OnionPathModalInner = () => { { label: window.i18n('device'), }, - ...onionNodes, + ...onionPath, { label: window.i18n('destination'), }, @@ -133,29 +137,21 @@ export const ActionPanelOnionStatusLight = (props: { }) => { const { isSelected, handleClick } = props; - let iconColor; const theme = useTheme(); - const firstOnionPath = useSelector((state: StateType) => state.onionPaths.snodePath); - const hasOnionPath = firstOnionPath.length > 2; + const onionPathsCount = useSelector(getOnionPathsCount); + const firstPathLength = useSelector(getFirstOnionPathLength); + const isOnline = useNetworkState().online; // Set icon color based on result const red = theme.colors.destructive; const green = theme.colors.accent; const orange = theme.colors.warning; - iconColor = hasOnionPath ? theme.colors.accent : theme.colors.destructive; - const onionState = useSelector((state: StateType) => state.onionPaths); - - iconColor = red; - const isOnline = useNetworkState().online; - if (!(onionState && onionState.snodePath) || !isOnline) { - iconColor = red; - } else { - const onionSnodePath = onionState.snodePath; - if (onionState && onionSnodePath && onionSnodePath.length > 0) { - const onionNodeCount = onionSnodePath.length; - iconColor = onionNodeCount > 2 ? green : onionNodeCount > 1 ? orange : red; - } + // start with red + let iconColor = red; + //if we are not online or the first path is not valid, we keep red as color + if (isOnline && firstPathLength > 1) { + iconColor = onionPathsCount > 2 ? green : onionPathsCount > 1 ? orange : red; } return ( diff --git a/ts/session/onions/onionPath.ts b/ts/session/onions/onionPath.ts index 8160bb951..1154ca408 100644 --- a/ts/session/onions/onionPath.ts +++ b/ts/session/onions/onionPath.ts @@ -136,7 +136,7 @@ export async function getOnionPath(toExclude?: Snode): Promise> { if (onionPaths.length <= 0) { window.inboxStore?.dispatch(updateOnionPaths([])); } else { - window.inboxStore?.dispatch(updateOnionPaths(onionPaths[0])); + window.inboxStore?.dispatch(updateOnionPaths(onionPaths)); } const onionPathsWithoutExcluded = toExclude diff --git a/ts/state/ducks/onion.tsx b/ts/state/ducks/onion.tsx index 4c6566762..2c607adf3 100644 --- a/ts/state/ducks/onion.tsx +++ b/ts/state/ducks/onion.tsx @@ -2,11 +2,11 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { Snode } from '../../data/data'; export type OnionState = { - snodePath: Array; + snodePaths: Array>; }; export const initialOnionPathState = { - snodePath: new Array(), + snodePaths: new Array>(), }; /** @@ -16,8 +16,8 @@ const onionSlice = createSlice({ name: 'onionPaths', initialState: initialOnionPathState, reducers: { - updateOnionPaths(state: OnionState, action: PayloadAction>) { - return { snodePath: action.payload }; + updateOnionPaths(state: OnionState, action: PayloadAction>>) { + return { snodePaths: action.payload }; }, }, }); diff --git a/ts/state/selectors/onions.ts b/ts/state/selectors/onions.ts new file mode 100644 index 000000000..1e3d95a0d --- /dev/null +++ b/ts/state/selectors/onions.ts @@ -0,0 +1,23 @@ +import { createSelector } from 'reselect'; + +import { StateType } from '../reducer'; +import { SectionType } from '../../components/session/ActionsPanel'; +import { OnionState } from '../ducks/onion'; +import { Snode } from '../../data/data'; + +export const getOnionPaths = (state: StateType): OnionState => state.onionPaths; + +export const getOnionPathsCount = createSelector( + getOnionPaths, + (state: OnionState): SectionType => state.snodePaths.length +); + +export const getFirstOnionPath = createSelector( + getOnionPaths, + (state: OnionState): Array => state.snodePaths?.[0] || [] +); + +export const getFirstOnionPathLength = createSelector( + getFirstOnionPath, + (state: Array): number => state.length || 0 +);