import { useCallback, useMemo } from 'react';
import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
import { ICustomList } from '../../shared/daemon-rpc-types';
import { messages, relayLocations } from '../../shared/gettext';
import log from '../../shared/logging';
import { useAppContext } from '../context';
import { transitions, useHistory } from '../lib/history';
import { RoutePath } from '../lib/routes';
import { IRelayLocationCountryRedux, RelaySettingsRedux } from '../redux/settings/reducers';
import { useSelector } from '../redux/store';
import { calculateHeaderBarStyle, DefaultHeaderBar } from './HeaderBar';
import ImageView from './ImageView';
import { Container, Layout } from './Layout';
import Map from './Map';
import NotificationArea from './NotificationArea';
import TunnelControl from './TunnelControl';
const StyledContainer = styled(Container)({
position: 'relative',
});
const Content = styled.div({
display: 'flex',
flex: 1,
flexDirection: 'column',
position: 'relative', // need this for z-index to work to cover the map
zIndex: 1,
});
const StatusIcon = styled(ImageView)({
position: 'absolute',
alignSelf: 'center',
marginTop: 94,
});
const StyledNotificationArea = styled(NotificationArea)({
position: 'absolute',
left: 0,
top: 0,
right: 0,
});
const StyledMain = styled.main({
display: 'flex',
flexDirection: 'column',
flex: 1,
});
export default function Connect() {
const history = useHistory();
const { connectTunnel, disconnectTunnel, reconnectTunnel } = useAppContext();
const connection = useSelector((state) => state.connection);
const blockWhenDisconnected = useSelector((state) => state.settings.blockWhenDisconnected);
const relaySettings = useSelector((state) => state.settings.relaySettings);
const relayLocations = useSelector((state) => state.settings.relayLocations);
const customLists = useSelector((state) => state.settings.customLists);
const showSpinner =
connection.status.state === 'connecting' || connection.status.state === 'disconnecting';
const onSelectLocation = useCallback(() => {
history.push(RoutePath.selectLocation, { transition: transitions.show });
}, [history.push]);
const selectedRelayName = useMemo(
() => getRelayName(relaySettings, customLists, relayLocations),
[relaySettings, customLists, relayLocations],
);
const onConnect = useCallback(async () => {
try {
await connectTunnel();
} catch (e) {
const error = e as Error;
log.error(`Failed to connect the tunnel: ${error.message}`);
}
}, []);
const onDisconnect = useCallback(async () => {
try {
await disconnectTunnel();
} catch (e) {
const error = e as Error;
log.error(`Failed to disconnect the tunnel: ${error.message}`);
}
}, []);
const onReconnect = useCallback(async () => {
try {
await reconnectTunnel();
} catch (e) {
const error = e as Error;
log.error(`Failed to reconnect the tunnel: ${error.message}`);
}
}, []);
return (
{showSpinner ? : null}
);
}
function getRelayName(
relaySettings: RelaySettingsRedux,
customLists: Array,
locations: IRelayLocationCountryRedux[],
): string {
if ('normal' in relaySettings) {
const location = relaySettings.normal.location;
if (location === 'any') {
return 'Automatic';
} else if ('customList' in location) {
return customLists.find((list) => list.id === location.customList)?.name ?? 'Unknown';
} else if ('hostname' in location) {
const country = locations.find(({ code }) => code === location.country);
if (country) {
const city = country.cities.find(({ code }) => code === location.city);
if (city) {
return sprintf(
// TRANSLATORS: The selected location label displayed on the main view, when a user selected a specific host to connect to.
// TRANSLATORS: Example: Malmö (se-mma-001)
// TRANSLATORS: Available placeholders:
// TRANSLATORS: %(city)s - a city name
// TRANSLATORS: %(hostname)s - a hostname
messages.pgettext('connect-container', '%(city)s (%(hostname)s)'),
{
city: relayLocations.gettext(city.name),
hostname: location.hostname,
},
);
}
}
} else if ('city' in location) {
const country = locations.find(({ code }) => code === location.country);
if (country) {
const city = country.cities.find(({ code }) => code === location.city);
if (city) {
return relayLocations.gettext(city.name);
}
}
} else if ('country' in location) {
const country = locations.find(({ code }) => code === location.country);
if (country) {
return relayLocations.gettext(country.name);
}
}
return 'Unknown';
} else if (relaySettings.customTunnelEndpoint) {
return 'Custom';
} else {
throw new Error('Unsupported relay settings.');
}
}