diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 66541e8ed..c7f2f3c87 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -22,6 +22,7 @@ import WaitlistPage from 'soapbox/features/verification/waitlist_page'; import { createGlobals } from 'soapbox/globals'; import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; +import { useCachedLocationHandler } from 'soapbox/utils/redirect'; import { generateThemeCss } from 'soapbox/utils/theme'; import { checkOnboardingStatus } from '../actions/onboarding'; @@ -64,6 +65,7 @@ const loadInitial = () => { }; const SoapboxMount = () => { + useCachedLocationHandler(); const dispatch = useAppDispatch(); const me = useAppSelector(state => state.me); diff --git a/app/soapbox/features/auth_layout/index.tsx b/app/soapbox/features/auth_layout/index.tsx index f96904580..1ac59b3de 100644 --- a/app/soapbox/features/auth_layout/index.tsx +++ b/app/soapbox/features/auth_layout/index.tsx @@ -1,13 +1,14 @@ import React from 'react'; -import { Link, Redirect, Route, Switch } from 'react-router-dom'; +import { defineMessages, useIntl } from 'react-intl'; +import { Link, Redirect, Route, Switch, useHistory } from 'react-router-dom'; import LandingGradient from 'soapbox/components/landing-gradient'; import SiteLogo from 'soapbox/components/site-logo'; import BundleContainer from 'soapbox/features/ui/containers/bundle_container'; import { NotificationsContainer } from 'soapbox/features/ui/util/async-components'; -import { useAppSelector } from 'soapbox/hooks'; +import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks'; -import { Card, CardBody } from '../../components/ui'; +import { Button, Card, CardBody } from '../../components/ui'; import LoginPage from '../auth_login/components/login_page'; import PasswordReset from '../auth_login/components/password_reset'; import PasswordResetConfirm from '../auth_login/components/password_reset_confirm'; @@ -17,22 +18,52 @@ import RegisterInvite from '../register_invite'; import Verification from '../verification'; import EmailPassthru from '../verification/email_passthru'; +const messages = defineMessages({ + register: { id: 'auth_layout.register', defaultMessage: 'Create an account' }, +}); + const AuthLayout = () => { + const intl = useIntl(); + const history = useHistory(); + const siteTitle = useAppSelector(state => state.instance.title); + const soapboxConfig = useSoapboxConfig(); + const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; + + const features = useFeatures(); + const instance = useAppSelector((state) => state.instance); + const isOpen = features.accountCreation && instance.registrations; + const pepeOpen = useAppSelector(state => state.verification.getIn(['instance', 'registrations'], false) === true); + const isLoginPage = history.location.pathname === '/login'; + const shouldShowRegisterLink = (isLoginPage && (isOpen || (pepeEnabled && pepeOpen))); return (
-
-
-
- - - +
+
+
+
+ + + +
+ + {shouldShowRegisterLink && ( +
+ +
+ )}
-
+
diff --git a/app/soapbox/features/auth_login/components/login_page.js b/app/soapbox/features/auth_login/components/login_page.js index 867a80863..21d47f18c 100644 --- a/app/soapbox/features/auth_login/components/login_page.js +++ b/app/soapbox/features/auth_login/components/login_page.js @@ -7,6 +7,7 @@ import { Redirect } from 'react-router-dom'; import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth'; import { fetchInstance } from 'soapbox/actions/instance'; import { closeModal } from 'soapbox/actions/modals'; +import { getRedirectUrl } from 'soapbox/utils/redirect'; import { isStandalone } from 'soapbox/utils/state'; import LoginForm from './login_form'; @@ -78,7 +79,10 @@ class LoginPage extends ImmutablePureComponent { if (standalone) return ; - if (shouldRedirect) return ; + if (shouldRedirect) { + const redirectUri = getRedirectUrl(); + return ; + } if (mfa_auth_needed) return ; diff --git a/app/soapbox/features/ui/index.tsx b/app/soapbox/features/ui/index.tsx index 6cfab8d89..164198e37 100644 --- a/app/soapbox/features/ui/index.tsx +++ b/app/soapbox/features/ui/index.tsx @@ -37,6 +37,7 @@ import RemoteInstancePage from 'soapbox/pages/remote_instance_page'; import StatusPage from 'soapbox/pages/status_page'; import { getAccessToken } from 'soapbox/utils/auth'; import { getVapidKey } from 'soapbox/utils/auth'; +import { cacheCurrentUrl } from 'soapbox/utils/redirect'; import { isStandalone } from 'soapbox/utils/state'; // import GroupSidebarPanel from '../groups/sidebar_panel'; @@ -278,7 +279,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => { - + @@ -330,6 +331,7 @@ const UI: React.FC = ({ children }) => { const intl = useIntl(); const history = useHistory(); const dispatch = useDispatch(); + const { guestExperience } = useSoapboxConfig(); const [draggingOver, setDraggingOver] = useState(false); const [mobile, setMobile] = useState(isMobile(window.innerWidth)); @@ -479,7 +481,7 @@ const UI: React.FC = ({ children }) => { document.addEventListener('drop', handleDrop, false); document.addEventListener('dragleave', handleDragLeave, false); - if ('serviceWorker' in navigator) { + if ('serviceWorker' in navigator) { navigator.serviceWorker.addEventListener('message', handleServiceWorkerPostMessage); } @@ -608,6 +610,11 @@ const UI: React.FC = ({ children }) => { // Wait for login to succeed or fail if (me === null) return null; + if (!me && !guestExperience) { + cacheCurrentUrl(history.location); + return ; + } + type HotkeyHandlers = { [key: string]: (keyEvent?: KeyboardEvent) => void }; const handlers: HotkeyHandlers = { diff --git a/app/soapbox/features/ui/util/react_router_helpers.tsx b/app/soapbox/features/ui/util/react_router_helpers.tsx index 288851d29..b7dbdb192 100644 --- a/app/soapbox/features/ui/util/react_router_helpers.tsx +++ b/app/soapbox/features/ui/util/react_router_helpers.tsx @@ -86,13 +86,14 @@ const WrappedRoute: React.FC = ({ ); - const renderLoading = () => renderWithLayout(); + const renderLoading = () => renderWithLayout(); const renderForbidden = () => renderWithLayout(); - const renderError = (props: any) => renderWithLayout(); + const renderError = (props: any) => renderWithLayout(); const loginRedirect = () => { const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`); - return ; + localStorage.setItem('soapbox:redirect_uri', actualUrl); + return ; }; const authorized = [ diff --git a/app/soapbox/features/verification/registration.tsx b/app/soapbox/features/verification/registration.tsx index 9fd4808dc..e038ae01a 100644 --- a/app/soapbox/features/verification/registration.tsx +++ b/app/soapbox/features/verification/registration.tsx @@ -11,6 +11,7 @@ import snackbar from 'soapbox/actions/snackbar'; import { createAccount } from 'soapbox/actions/verification'; import { removeStoredVerification } from 'soapbox/actions/verification'; import { useAppSelector } from 'soapbox/hooks'; +import { getRedirectUrl } from 'soapbox/utils/redirect'; import { Button, Form, FormGroup, Input } from '../../components/ui'; @@ -81,7 +82,8 @@ const Registration = () => { }, []); if (shouldRedirect) { - return ; + const redirectUri = getRedirectUrl(); + return ; } return ( diff --git a/app/soapbox/normalizers/soapbox/soapbox_config.ts b/app/soapbox/normalizers/soapbox/soapbox_config.ts index f1fed529b..de7324e00 100644 --- a/app/soapbox/normalizers/soapbox/soapbox_config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox_config.ts @@ -115,6 +115,7 @@ export const SoapboxConfigRecord = ImmutableRecord({ singleUserMode: false, singleUserModeProfile: '', linkFooterMessage: '', + guestExperience: true, links: ImmutableMap(), }, 'SoapboxConfig'); diff --git a/app/soapbox/utils/redirect.ts b/app/soapbox/utils/redirect.ts new file mode 100644 index 000000000..f2b207660 --- /dev/null +++ b/app/soapbox/utils/redirect.ts @@ -0,0 +1,36 @@ +import { Location } from 'history'; +import { useEffect } from 'react'; + +const LOCAL_STORAGE_REDIRECT_KEY = 'soapbox:redirect-uri'; + +const cacheCurrentUrl = (location: Location) => { + const actualUrl = encodeURIComponent(`${location.pathname}${location.search}`); + localStorage.setItem(LOCAL_STORAGE_REDIRECT_KEY, actualUrl); + return actualUrl; +}; + +const getRedirectUrl = () => { + let redirectUri = localStorage.getItem(LOCAL_STORAGE_REDIRECT_KEY); + if (redirectUri) { + redirectUri = decodeURIComponent(redirectUri); + } + + localStorage.removeItem(LOCAL_STORAGE_REDIRECT_KEY); + return redirectUri || '/'; +}; + +const useCachedLocationHandler = () => { + const removeCachedRedirectUri = () => localStorage.removeItem(LOCAL_STORAGE_REDIRECT_KEY); + + useEffect(() => { + window.addEventListener('beforeunload', removeCachedRedirectUri); + + return () => { + window.removeEventListener('beforeunload', removeCachedRedirectUri); + }; + }, []); + + return null; +}; + +export { cacheCurrentUrl, getRedirectUrl, useCachedLocationHandler };