diff --git a/app/soapbox/actions/auth.js b/app/soapbox/actions/auth.js
index 9549abead..ee496450b 100644
--- a/app/soapbox/actions/auth.js
+++ b/app/soapbox/actions/auth.js
@@ -18,6 +18,7 @@ import { createApp } from 'soapbox/actions/apps';
import { obtainOAuthToken, revokeOAuthToken } from 'soapbox/actions/oauth';
import sourceCode from 'soapbox/utils/code';
import { getFeatures } from 'soapbox/utils/features';
+import { isStandalone } from 'soapbox/utils/state';
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
@@ -177,6 +178,7 @@ export function logOut(intl) {
return (dispatch, getState) => {
const state = getState();
const account = getLoggedInAccount(state);
+ const standalone = isStandalone(state);
const params = {
client_id: state.getIn(['auth', 'app', 'client_id']),
@@ -185,7 +187,7 @@ export function logOut(intl) {
};
return dispatch(revokeOAuthToken(params)).finally(() => {
- dispatch({ type: AUTH_LOGGED_OUT, account });
+ dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
});
};
diff --git a/app/soapbox/actions/external_auth.js b/app/soapbox/actions/external_auth.js
index f3b52650a..da680c488 100644
--- a/app/soapbox/actions/external_auth.js
+++ b/app/soapbox/actions/external_auth.js
@@ -9,7 +9,7 @@
import { baseClient } from '../api';
import { createApp } from 'soapbox/actions/apps';
import { obtainOAuthToken } from 'soapbox/actions/oauth';
-import { authLoggedIn, verifyCredentials } from 'soapbox/actions/auth';
+import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { parseBaseURL } from 'soapbox/utils/auth';
import { getFeatures } from 'soapbox/utils/features';
import sourceCode from 'soapbox/utils/code';
@@ -73,6 +73,7 @@ export function loginWithCode(code) {
return dispatch(obtainOAuthToken(params, baseURL))
.then(token => dispatch(authLoggedIn(token)))
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
+ .then(account => dispatch(switchAccount(account.id)))
.then(() => window.location.href = '/');
};
}
diff --git a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap
index 82586223c..041b1741d 100644
--- a/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap
+++ b/app/soapbox/features/auth_login/components/__tests__/__snapshots__/login_page-test.js.snap
@@ -1,129 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` renders correctly on load 1`] = `
-
-`;
+exports[` renders correctly on load 1`] = `null`;
-exports[` renders correctly on load 2`] = `
-
-`;
+exports[` renders correctly on load 2`] = `null`;
diff --git a/app/soapbox/features/auth_login/components/login_page.js b/app/soapbox/features/auth_login/components/login_page.js
index 8bd797c52..8cdb07ee0 100644
--- a/app/soapbox/features/auth_login/components/login_page.js
+++ b/app/soapbox/features/auth_login/components/login_page.js
@@ -6,10 +6,12 @@ import { injectIntl } from 'react-intl';
import LoginForm from './login_form';
import OtpAuthForm from './otp_auth_form';
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
+import { isStandalone } from 'soapbox/utils/state';
const mapStateToProps = state => ({
me: state.get('me'),
isLoading: false,
+ standalone: isStandalone(state),
});
export default @connect(mapStateToProps)
@@ -55,8 +57,11 @@ class LoginPage extends ImmutablePureComponent {
}
render() {
+ const { standalone } = this.props;
const { isLoading, mfa_auth_needed, mfa_token, shouldRedirect } = this.state;
+ if (standalone) return ;
+
if (shouldRedirect) return ;
if (mfa_auth_needed) return ;
diff --git a/app/soapbox/features/public_layout/index.js b/app/soapbox/features/public_layout/index.js
index 621e9c25b..09dc1f263 100644
--- a/app/soapbox/features/public_layout/index.js
+++ b/app/soapbox/features/public_layout/index.js
@@ -9,19 +9,7 @@ import Footer from './components/footer';
import LandingPage from '../landing_page';
import AboutPage from '../about';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
-import { isPrerendered } from 'soapbox/precheck';
-
-const validInstance = state => {
- const v = state.getIn(['instance', 'version']);
- return v && typeof v === 'string' && v !== '0.0.0';
-};
-
-const isStandalone = state => {
- const hasInstance = validInstance(state);
- const instanceFetchFailed = state.getIn(['meta', 'instance_fetch_failed']);
-
- return !isPrerendered && !hasInstance && instanceFetchFailed;
-};
+import { isStandalone } from 'soapbox/utils/state';
const mapStateToProps = (state, props) => ({
soapbox: getSoapboxConfig(state),
diff --git a/app/soapbox/reducers/auth.js b/app/soapbox/reducers/auth.js
index 42aaa586f..a3b669dd0 100644
--- a/app/soapbox/reducers/auth.js
+++ b/app/soapbox/reducers/auth.js
@@ -261,7 +261,10 @@ const userSwitched = (oldState, state) => {
};
const maybeReload = (oldState, state, action) => {
- if (userSwitched(oldState, state)) {
+ const loggedOutStandalone = action.type === AUTH_LOGGED_OUT && action.standalone;
+ const switched = userSwitched(oldState, state);
+
+ if (switched || loggedOutStandalone) {
reload(state);
}
};
diff --git a/app/soapbox/utils/state.js b/app/soapbox/utils/state.js
index 9809c25fa..9c69e9043 100644
--- a/app/soapbox/utils/state.js
+++ b/app/soapbox/utils/state.js
@@ -1,4 +1,13 @@
+/**
+ * State: general Redux state utility functions.
+ * @module soapbox/utils/state
+ */
+
import { getSoapboxConfig } from'soapbox/actions/soapbox';
+import { createSelector } from 'reselect';
+import { isPrerendered } from 'soapbox/precheck';
+import { isURL } from 'soapbox/utils/auth';
+import { BACKEND_URL } from 'soapbox/build_config';
export const displayFqn = state => {
const soapbox = getSoapboxConfig(state);
@@ -8,3 +17,15 @@ export const displayFqn = state => {
export const federationRestrictionsDisclosed = state => {
return state.hasIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_policies']);
};
+
+/**
+ * Determine whether Soapbox FE is running in standalone mode.
+ * Standalone mode runs separately from any backend and can login anywhere.
+ * @param {object} state
+ * @returns {boolean}
+ */
+export const isStandalone = state => createSelector([
+ state => state.getIn(['meta', 'instance_fetch_failed'], false),
+], instanceFetchFailed => {
+ return isURL(BACKEND_URL) ? false : (!isPrerendered && instanceFetchFailed);
+});