From 41b3d409fde0e1bb07cff31a30387437e1e1fce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corne=CC=81=20Dorrestijn?= Date: Thu, 29 Dec 2022 17:42:54 +0100 Subject: [PATCH 01/21] Allow configuration from root URL path --- app/soapbox/features/public-layout/index.tsx | 11 +++++++++-- app/soapbox/normalizers/soapbox/soapbox-config.ts | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/soapbox/features/public-layout/index.tsx b/app/soapbox/features/public-layout/index.tsx index 0fdc8b946..3671b5ae8 100644 --- a/app/soapbox/features/public-layout/index.tsx +++ b/app/soapbox/features/public-layout/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Switch, Route, Redirect } from 'react-router-dom'; import LandingGradient from 'soapbox/components/landing-gradient'; -import { useAppSelector } from 'soapbox/hooks'; +import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks'; import { isStandalone } from 'soapbox/utils/state'; import AboutPage from '../about'; @@ -13,6 +13,9 @@ import Header from './components/header'; const PublicLayout = () => { const standalone = useAppSelector((state) => isStandalone(state)); + const soapboxConfig = useSoapboxConfig(); + + const shouldRedirectFromRoot = soapboxConfig.redirectRootNoLogin && !soapboxConfig.redirectRootNoLogin.match(/^\/?$/); if (standalone) { return ; @@ -28,7 +31,11 @@ const PublicLayout = () => {
- + {shouldRedirectFromRoot ? ( + + ) : ( + + )}
diff --git a/app/soapbox/normalizers/soapbox/soapbox-config.ts b/app/soapbox/normalizers/soapbox/soapbox-config.ts index b221afabe..06848cc7a 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({ feedInjection: true, tileServer: '', tileServerAttribution: '', + redirectRootNoLogin: '/', }, 'SoapboxConfig'); type SoapboxConfigMap = ImmutableMap; From b325b8933e7ea33f3a5c81b7c2523a15e52fcc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corne=CC=81=20Dorrestijn?= Date: Thu, 5 Jan 2023 20:52:37 +0100 Subject: [PATCH 02/21] Added a options in settings for redirect root no login --- app/soapbox/features/soapbox-config/index.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/soapbox/features/soapbox-config/index.tsx b/app/soapbox/features/soapbox-config/index.tsx index dc1ebdb0e..0b85272b1 100644 --- a/app/soapbox/features/soapbox-config/index.tsx +++ b/app/soapbox/features/soapbox-config/index.tsx @@ -54,6 +54,9 @@ const messages = defineMessages({ feedInjectionHint: { id: 'soapbox_config.feed_injection_hint', defaultMessage: 'Inject the feed with additional content, such as suggested profiles.' }, tileServerLabel: { id: 'soapbox_config.tile_server_label', defaultMessage: 'Map tile server' }, tileServerAttributionLabel: { id: 'soapbox_config.tile_server_attribution_label', defaultMessage: 'Map tiles attribution' }, + redirectRootNoLoginLabel: { id: 'soapbox_config.redirect_root_no_login_label', defaultMessage: 'Redirect root (no login)' }, + redirectRootNoLoginHint: { id: 'soapbox_config.redirect_root_no_login_hint', defaultMessage: 'Path to redirect a user to from the homepage when he is not logged in.' }, + redirectRootNoLoginPlaceholder: { id: 'soapbox_config.redirect_root_no_login_placeholder', defaultMessage: '/timeline/local' }, }); type ValueGetter = (e: React.ChangeEvent) => any; @@ -287,6 +290,18 @@ const SoapboxConfig: React.FC = () => { /> )} + + + e.target.value)} + /> + From 6f0e398a78ac80c580358ee8360c766060367c73 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:01:45 -0600 Subject: [PATCH 03/21] Remove singleUserMode, upgrade to redirectRootNoLogin --- app/soapbox/containers/soapbox.tsx | 6 +-- app/soapbox/features/soapbox-config/index.tsx | 25 ----------- .../components/__tests__/cta-banner.test.tsx | 7 +-- .../features/ui/components/cta-banner.tsx | 4 +- .../components/modals/unauthorized-modal.tsx | 7 ++- app/soapbox/features/ui/components/navbar.tsx | 7 ++- .../ui/components/panels/sign-up-panel.tsx | 5 +-- .../soapbox/__tests__/soapbox-config.test.ts | 11 +++++ .../normalizers/soapbox/soapbox-config.ts | 45 +++++++++++++++++-- 9 files changed, 70 insertions(+), 47 deletions(-) diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index b9603b3b1..d6c17db5f 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -96,7 +96,7 @@ const SoapboxMount = () => { const waitlisted = account && !account.source.get('approved', true); const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding); const showOnboarding = account && !waitlisted && needsOnboarding; - const singleUserMode = soapboxConfig.singleUserMode && soapboxConfig.singleUserModeProfile; + const { redirectRootNoLogin } = soapboxConfig; const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; @@ -134,8 +134,8 @@ const SoapboxMount = () => { /> )} - {!me && (singleUserMode - ? + {!me && (redirectRootNoLogin + ? : )} {!me && ( diff --git a/app/soapbox/features/soapbox-config/index.tsx b/app/soapbox/features/soapbox-config/index.tsx index 8484863b6..761c34d59 100644 --- a/app/soapbox/features/soapbox-config/index.tsx +++ b/app/soapbox/features/soapbox-config/index.tsx @@ -47,10 +47,6 @@ const messages = defineMessages({ authenticatedProfileLabel: { id: 'soapbox_config.authenticated_profile_label', defaultMessage: 'Profiles require authentication' }, authenticatedProfileHint: { id: 'soapbox_config.authenticated_profile_hint', defaultMessage: 'Users must be logged-in to view replies and media on user profiles.' }, displayCtaLabel: { id: 'soapbox_config.cta_label', defaultMessage: 'Display call to action panels if not authenticated' }, - singleUserModeLabel: { id: 'soapbox_config.single_user_mode_label', defaultMessage: 'Single user mode' }, - singleUserModeHint: { id: 'soapbox_config.single_user_mode_hint', defaultMessage: 'Front page will redirect to a given user profile.' }, - singleUserModeProfileLabel: { id: 'soapbox_config.single_user_mode_profile_label', defaultMessage: 'Main user handle' }, - singleUserModeProfileHint: { id: 'soapbox_config.single_user_mode_profile_hint', defaultMessage: '@handle' }, mediaPreviewLabel: { id: 'soapbox_config.media_preview_label', defaultMessage: 'Prefer preview media for thumbnails' }, mediaPreviewHint: { id: 'soapbox_config.media_preview_hint', defaultMessage: 'Some backends provide an optimized version of media for display in timelines. However, these preview images may be too small without additional configuration.' }, feedInjectionLabel: { id: 'soapbox_config.feed_injection_label', defaultMessage: 'Feed injection' }, @@ -283,27 +279,6 @@ const SoapboxConfig: React.FC = () => { /> - - e.target.checked)} - /> - - - {soapbox.get('singleUserMode') && ( - - e.target.value)} - /> - - )} - ', () => { }); }); - describe('with singleUserMode enabled', () => { + describe('with registrations closed', () => { it('renders empty', () => { - const store = { soapbox: ImmutableMap({ singleUserMode: true }) }; + const store = { instance: normalizeInstance({ registrations: false }) }; render(, undefined, store); expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0); diff --git a/app/soapbox/features/ui/components/cta-banner.tsx b/app/soapbox/features/ui/components/cta-banner.tsx index 87860b318..5e06b207c 100644 --- a/app/soapbox/features/ui/components/cta-banner.tsx +++ b/app/soapbox/features/ui/components/cta-banner.tsx @@ -6,10 +6,10 @@ import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks'; const CtaBanner = () => { const instance = useInstance(); - const { displayCta, singleUserMode } = useSoapboxConfig(); + const { displayCta } = useSoapboxConfig(); const me = useAppSelector((state) => state.me); - if (me || !displayCta || singleUserMode) return null; + if (me || !displayCta || !instance.registrations) return null; return (
diff --git a/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx b/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx index 9a7906e87..809abcbda 100644 --- a/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx +++ b/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx @@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom'; import { remoteInteraction } from 'soapbox/actions/interactions'; import { Button, Modal, Stack, Text } from 'soapbox/components/ui'; -import { useAppSelector, useAppDispatch, useFeatures, useSoapboxConfig, useInstance } from 'soapbox/hooks'; +import { useAppSelector, useAppDispatch, useFeatures, useInstance } from 'soapbox/hooks'; import toast from 'soapbox/toast'; const messages = defineMessages({ @@ -31,7 +31,6 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco const dispatch = useAppDispatch(); const instance = useInstance(); - const { singleUserMode } = useSoapboxConfig(); const username = useAppSelector(state => state.accounts.get(accountId)?.display_name); const features = useFeatures(); @@ -98,7 +97,7 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco } secondaryAction={onRegister} secondaryText={} @@ -122,7 +121,7 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco
- {!singleUserMode && ( + {instance.registrations && ( diff --git a/app/soapbox/features/ui/components/navbar.tsx b/app/soapbox/features/ui/components/navbar.tsx index d9829afca..bbb357bfa 100644 --- a/app/soapbox/features/ui/components/navbar.tsx +++ b/app/soapbox/features/ui/components/navbar.tsx @@ -9,7 +9,7 @@ import { openSidebar } from 'soapbox/actions/sidebar'; import SiteLogo from 'soapbox/components/site-logo'; import { Avatar, Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui'; import Search from 'soapbox/features/compose/components/search'; -import { useAppDispatch, useOwnAccount, useSoapboxConfig } from 'soapbox/hooks'; +import { useAppDispatch, useInstance, useOwnAccount } from 'soapbox/hooks'; import ProfileDropdown from './profile-dropdown'; @@ -29,8 +29,7 @@ const Navbar = () => { const node = useRef(null); const account = useOwnAccount(); - const soapboxConfig = useSoapboxConfig(); - const singleUserMode = soapboxConfig.get('singleUserMode'); + const instance = useInstance(); const [isLoading, setLoading] = useState(false); const [username, setUsername] = useState(''); @@ -151,7 +150,7 @@ const Navbar = () => { - {!singleUserMode && ( + {!instance.registrations && ( diff --git a/app/soapbox/features/ui/components/panels/sign-up-panel.tsx b/app/soapbox/features/ui/components/panels/sign-up-panel.tsx index 318080770..117a8a8b9 100644 --- a/app/soapbox/features/ui/components/panels/sign-up-panel.tsx +++ b/app/soapbox/features/ui/components/panels/sign-up-panel.tsx @@ -2,14 +2,13 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Button, Stack, Text } from 'soapbox/components/ui'; -import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks'; +import { useAppSelector, useInstance } from 'soapbox/hooks'; const SignUpPanel = () => { const instance = useInstance(); - const { singleUserMode } = useSoapboxConfig(); const me = useAppSelector((state) => state.me); - if (me || singleUserMode) return null; + if (me || !instance.registrations) return null; return ( diff --git a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts index 9b70eba36..5eccab870 100644 --- a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts +++ b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts @@ -34,4 +34,15 @@ describe('normalizeSoapboxConfig()', () => { expect(ImmutableRecord.isRecord(result.promoPanel.items.get(0))).toBe(true); expect(result.promoPanel.items.get(2)?.icon).toBe('question-circle'); }); + + it('upgrades singleUserModeProfile to redirectRootNoLogin', () => { + expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe('/@alex'); + expect(normalizeSoapboxConfig({ singleUserMode: false, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe(''); + }); + + it('normalizes redirectRootNoLogin', () => { + expect(normalizeSoapboxConfig({ redirectRootNoLogin: 'benis' }).redirectRootNoLogin).toBe('/benis'); + expect(normalizeSoapboxConfig({ redirectRootNoLogin: '/benis' }).redirectRootNoLogin).toBe('/benis'); + expect(normalizeSoapboxConfig({ redirectRootNoLogin: '/' }).redirectRootNoLogin).toBe(''); + }); }); diff --git a/app/soapbox/normalizers/soapbox/soapbox-config.ts b/app/soapbox/normalizers/soapbox/soapbox-config.ts index e899e1e80..f2366bdf1 100644 --- a/app/soapbox/normalizers/soapbox/soapbox-config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox-config.ts @@ -106,8 +106,6 @@ export const SoapboxConfigRecord = ImmutableRecord({ }), aboutPages: ImmutableMap>(), authenticatedProfile: true, - singleUserMode: false, - singleUserModeProfile: '', linkFooterMessage: '', links: ImmutableMap(), displayCta: true, @@ -115,7 +113,7 @@ export const SoapboxConfigRecord = ImmutableRecord({ feedInjection: true, tileServer: '', tileServerAttribution: '', - redirectRootNoLogin: '/', + redirectRootNoLogin: '', /** * Whether to use the preview URL for media thumbnails. * On some platforms this can be too blurry without additional configuration. @@ -198,6 +196,45 @@ const normalizeAdsAlgorithm = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMa } }; +/** Single user mode is now managed by `redirectRootNoLogin`. */ +const upgradeSingleUserMode = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap => { + const singleUserMode = soapboxConfig.get('singleUserMode'); + const singleUserModeProfile = soapboxConfig.get('singleUserModeProfile'); + const redirectRootNoLogin = soapboxConfig.get('redirectRootNoLogin'); + + if (!redirectRootNoLogin && singleUserMode && singleUserModeProfile) { + return soapboxConfig + .set('redirectRootNoLogin', `/@${singleUserModeProfile}`) + .deleteAll(['singleUserMode', 'singleUserModeProfile']); + } else { + return soapboxConfig + .deleteAll(['singleUserMode', 'singleUserModeProfile']); + } +}; + +/** Ensure a valid path is used. */ +const normalizeRedirectRootNoLogin = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap => { + const redirectRootNoLogin = soapboxConfig.get('redirectRootNoLogin'); + + if (!redirectRootNoLogin) return soapboxConfig; + + try { + // Basically just get the pathname with a leading slash. + const normalized = new URL(redirectRootNoLogin, 'a://').pathname; + + if (normalized !== '/') { + return soapboxConfig.set('redirectRootNoLogin', normalized); + } else { + // Prevent infinite redirect(?) + return soapboxConfig.delete('redirectRootNoLogin'); + } + } catch (e) { + console.error('You have configured an invalid redirect in Soapbox Config.'); + console.error(e); + return soapboxConfig.delete('redirectRootNoLogin'); + } +}; + export const normalizeSoapboxConfig = (soapboxConfig: Record) => { return SoapboxConfigRecord( ImmutableMap(fromJS(soapboxConfig)).withMutations(soapboxConfig => { @@ -210,6 +247,8 @@ export const normalizeSoapboxConfig = (soapboxConfig: Record) => { normalizeCryptoAddresses(soapboxConfig); normalizeAds(soapboxConfig); normalizeAdsAlgorithm(soapboxConfig); + upgradeSingleUserMode(soapboxConfig); + normalizeRedirectRootNoLogin(soapboxConfig); }), ); }; From e9a48b45e1ee021d4018e8387704ae7eac13e3e5 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:03:06 -0600 Subject: [PATCH 04/21] Remove redirect code from PublicLayout --- app/soapbox/features/public-layout/index.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/soapbox/features/public-layout/index.tsx b/app/soapbox/features/public-layout/index.tsx index 3671b5ae8..0fdc8b946 100644 --- a/app/soapbox/features/public-layout/index.tsx +++ b/app/soapbox/features/public-layout/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Switch, Route, Redirect } from 'react-router-dom'; import LandingGradient from 'soapbox/components/landing-gradient'; -import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks'; +import { useAppSelector } from 'soapbox/hooks'; import { isStandalone } from 'soapbox/utils/state'; import AboutPage from '../about'; @@ -13,9 +13,6 @@ import Header from './components/header'; const PublicLayout = () => { const standalone = useAppSelector((state) => isStandalone(state)); - const soapboxConfig = useSoapboxConfig(); - - const shouldRedirectFromRoot = soapboxConfig.redirectRootNoLogin && !soapboxConfig.redirectRootNoLogin.match(/^\/?$/); if (standalone) { return ; @@ -31,11 +28,7 @@ const PublicLayout = () => {
- {shouldRedirectFromRoot ? ( - - ) : ( - - )} +
From 5ab380f9bcebf19955774bab0e857b662acc0330 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:04:26 -0600 Subject: [PATCH 05/21] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b2a108d5..37e4eff2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - UI: added backdrop blur behind modals. - Admin: let admins configure media preview for attachment thumbnails. - Login: accept `?server` param in external login, eg `fe.soapbox.pub/login/external?server=gleasonator.com`. +- Admin: redirect the homepage to any URL. ### Changed - Posts: letterbox images to 19:6 again. @@ -32,6 +33,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Posts: let unauthenticated users to translate posts if allowed by backend. - Chats: fix jumpy scrollbar. +### Removed +- Admin: single user mode. Now the homepage can be redirected to any URL. + ## [3.0.0] - 2022-12-25 ### Added From 3e2fe59bfd58357b6638c3a8cd384a96ddddaf84 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:06:27 -0600 Subject: [PATCH 06/21] Update en.json --- app/soapbox/locales/en.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 49883461c..f56507e02 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -1198,12 +1198,11 @@ "soapbox_config.raw_json_hint": "Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click Save to apply your changes.", "soapbox_config.raw_json_invalid": "is invalid", "soapbox_config.raw_json_label": "Advanced: Edit raw JSON data", + "soapbox_config.redirect_root_no_login_hint": "Path to redirect a user to from the homepage when he is not logged in.", + "soapbox_config.redirect_root_no_login_label": "Redirect root (no login)", + "soapbox_config.redirect_root_no_login_placeholder": "/timeline/local", "soapbox_config.save": "Save", "soapbox_config.saved": "Soapbox config saved!", - "soapbox_config.single_user_mode_hint": "Front page will redirect to a given user profile.", - "soapbox_config.single_user_mode_label": "Single user mode", - "soapbox_config.single_user_mode_profile_hint": "@handle", - "soapbox_config.single_user_mode_profile_label": "Main user handle", "soapbox_config.tile_server_attribution_label": "Map tiles attribution", "soapbox_config.tile_server_label": "Map tile server", "soapbox_config.verified_can_edit_name_label": "Allow verified users to edit their own display name.", From 0bff56a9a8efb8f08b9eaa1f4a1bec0f0ebe54f5 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:11:54 -0600 Subject: [PATCH 07/21] redirectRootNoLogin: improve phrasing --- app/soapbox/features/soapbox-config/index.tsx | 4 ++-- app/soapbox/locales/en.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/soapbox/features/soapbox-config/index.tsx b/app/soapbox/features/soapbox-config/index.tsx index 761c34d59..a8ecf1a5a 100644 --- a/app/soapbox/features/soapbox-config/index.tsx +++ b/app/soapbox/features/soapbox-config/index.tsx @@ -53,8 +53,8 @@ const messages = defineMessages({ feedInjectionHint: { id: 'soapbox_config.feed_injection_hint', defaultMessage: 'Inject the feed with additional content, such as suggested profiles.' }, tileServerLabel: { id: 'soapbox_config.tile_server_label', defaultMessage: 'Map tile server' }, tileServerAttributionLabel: { id: 'soapbox_config.tile_server_attribution_label', defaultMessage: 'Map tiles attribution' }, - redirectRootNoLoginLabel: { id: 'soapbox_config.redirect_root_no_login_label', defaultMessage: 'Redirect root (no login)' }, - redirectRootNoLoginHint: { id: 'soapbox_config.redirect_root_no_login_hint', defaultMessage: 'Path to redirect a user to from the homepage when he is not logged in.' }, + redirectRootNoLoginLabel: { id: 'soapbox_config.redirect_root_no_login_label', defaultMessage: 'Redirect homepage' }, + redirectRootNoLoginHint: { id: 'soapbox_config.redirect_root_no_login_hint', defaultMessage: 'Path to redirect the homepage when a user is not logged in.' }, redirectRootNoLoginPlaceholder: { id: 'soapbox_config.redirect_root_no_login_placeholder', defaultMessage: '/timeline/local' }, }); diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index f56507e02..242f95d24 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -1198,8 +1198,8 @@ "soapbox_config.raw_json_hint": "Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click Save to apply your changes.", "soapbox_config.raw_json_invalid": "is invalid", "soapbox_config.raw_json_label": "Advanced: Edit raw JSON data", - "soapbox_config.redirect_root_no_login_hint": "Path to redirect a user to from the homepage when he is not logged in.", - "soapbox_config.redirect_root_no_login_label": "Redirect root (no login)", + "soapbox_config.redirect_root_no_login_hint": "Path to redirect the homepage when a user is not logged in.", + "soapbox_config.redirect_root_no_login_label": "Redirect homepage", "soapbox_config.redirect_root_no_login_placeholder": "/timeline/local", "soapbox_config.save": "Save", "soapbox_config.saved": "Soapbox config saved!", From d64f4edf61ec8297189330a965207ebf9e4a1eaf Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 11 Jan 2023 19:38:05 -0600 Subject: [PATCH 08/21] Fix CtaBanner and UI tests --- app/soapbox/features/ui/__tests__/index.test.tsx | 3 ++- .../features/ui/components/__tests__/cta-banner.test.tsx | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/soapbox/features/ui/__tests__/index.test.tsx b/app/soapbox/features/ui/__tests__/index.test.tsx index 9f04f5fb8..f3e32f5f7 100644 --- a/app/soapbox/features/ui/__tests__/index.test.tsx +++ b/app/soapbox/features/ui/__tests__/index.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import { render, screen, waitFor } from '../../../jest/test-helpers'; -import { normalizeAccount } from '../../../normalizers'; +import { normalizeAccount, normalizeInstance } from '../../../normalizers'; import UI from '../index'; import { WrappedRoute } from '../util/react-router-helpers'; @@ -33,6 +33,7 @@ describe('', () => { avatar: 'test.jpg', }), }), + instance: normalizeInstance({ registrations: true }), }; }); diff --git a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx index 4ab6bdd4b..90ba1dcc3 100644 --- a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx @@ -7,7 +7,9 @@ import CtaBanner from '../cta-banner'; describe('', () => { it('renders the banner', () => { - render(); + const store = { instance: normalizeInstance({ registrations: true }) }; + + render(, undefined, store); expect(screen.getByTestId('cta-banner')).toHaveTextContent(/sign up/i); }); From 0531f8babfe97367f71fe7e46a10a2a4236fd4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corn=C3=A9=20Dorrestijn?= Date: Thu, 12 Jan 2023 20:05:04 +0000 Subject: [PATCH 09/21] Apply 1 suggestion(s) to 1 file(s) --- app/soapbox/normalizers/soapbox/soapbox-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/normalizers/soapbox/soapbox-config.ts b/app/soapbox/normalizers/soapbox/soapbox-config.ts index f2366bdf1..a48f3334e 100644 --- a/app/soapbox/normalizers/soapbox/soapbox-config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox-config.ts @@ -220,7 +220,7 @@ const normalizeRedirectRootNoLogin = (soapboxConfig: SoapboxConfigMap): SoapboxC try { // Basically just get the pathname with a leading slash. - const normalized = new URL(redirectRootNoLogin, 'a://').pathname; + const normalized = new URL(redirectRootNoLogin, 'http://a').pathname; if (normalized !== '/') { return soapboxConfig.set('redirectRootNoLogin', normalized); From 29bf78d09b3380a24a11c70b09f5011f537f5b95 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 13 Jan 2023 18:54:25 -0600 Subject: [PATCH 10/21] Correctly normalize singleUserModeProfile if it has an @ --- .../normalizers/soapbox/__tests__/soapbox-config.test.ts | 1 + app/soapbox/normalizers/soapbox/soapbox-config.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts index 5eccab870..6901254f2 100644 --- a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts +++ b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts @@ -37,6 +37,7 @@ describe('normalizeSoapboxConfig()', () => { it('upgrades singleUserModeProfile to redirectRootNoLogin', () => { expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe('/@alex'); + expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: '@alex' }).redirectRootNoLogin).toBe('/@alex'); expect(normalizeSoapboxConfig({ singleUserMode: false, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe(''); }); diff --git a/app/soapbox/normalizers/soapbox/soapbox-config.ts b/app/soapbox/normalizers/soapbox/soapbox-config.ts index f2366bdf1..eba76454c 100644 --- a/app/soapbox/normalizers/soapbox/soapbox-config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox-config.ts @@ -198,13 +198,13 @@ const normalizeAdsAlgorithm = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMa /** Single user mode is now managed by `redirectRootNoLogin`. */ const upgradeSingleUserMode = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMap => { - const singleUserMode = soapboxConfig.get('singleUserMode'); - const singleUserModeProfile = soapboxConfig.get('singleUserModeProfile'); - const redirectRootNoLogin = soapboxConfig.get('redirectRootNoLogin'); + const singleUserMode = soapboxConfig.get('singleUserMode') as boolean | undefined; + const singleUserModeProfile = soapboxConfig.get('singleUserModeProfile') as string | undefined; + const redirectRootNoLogin = soapboxConfig.get('redirectRootNoLogin') as string | undefined; if (!redirectRootNoLogin && singleUserMode && singleUserModeProfile) { return soapboxConfig - .set('redirectRootNoLogin', `/@${singleUserModeProfile}`) + .set('redirectRootNoLogin', `/@${singleUserModeProfile.replaceAll('@', '')}`) .deleteAll(['singleUserMode', 'singleUserModeProfile']); } else { return soapboxConfig From 82981efe9adfc037446de832114df4fe5f8a8c14 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 13 Jan 2023 19:13:15 -0600 Subject: [PATCH 11/21] Add useRegistrationStatus hook --- app/soapbox/features/auth-layout/index.tsx | 12 +++------- app/soapbox/features/landing-page/index.tsx | 6 ++--- .../public-layout/components/header.tsx | 11 +++------- .../features/ui/components/cta-banner.tsx | 5 +++-- .../components/modals/landing-page-modal.tsx | 12 +++------- app/soapbox/features/ui/components/navbar.tsx | 10 ++++----- .../ui/components/panels/sign-up-panel.tsx | 5 +++-- app/soapbox/hooks/index.ts | 3 ++- app/soapbox/hooks/useRegistrationStatus.ts | 22 +++++++++++++++++++ 9 files changed, 45 insertions(+), 41 deletions(-) create mode 100644 app/soapbox/hooks/useRegistrationStatus.ts diff --git a/app/soapbox/features/auth-layout/index.tsx b/app/soapbox/features/auth-layout/index.tsx index 629bb3c9b..b792bc006 100644 --- a/app/soapbox/features/auth-layout/index.tsx +++ b/app/soapbox/features/auth-layout/index.tsx @@ -4,7 +4,7 @@ import { Link, Redirect, Route, Switch, useHistory, useLocation } from 'react-ro import LandingGradient from 'soapbox/components/landing-gradient'; import SiteLogo from 'soapbox/components/site-logo'; -import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount, useInstance } from 'soapbox/hooks'; +import { useOwnAccount, useInstance, useRegistrationStatus } from 'soapbox/hooks'; import { Button, Card, CardBody } from '../../components/ui'; import LoginPage from '../auth-login/components/login-page'; @@ -28,14 +28,8 @@ const AuthLayout = () => { const account = useOwnAccount(); const instance = useInstance(); - const features = useFeatures(); - const soapboxConfig = useSoapboxConfig(); - - const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; - const isOpen = features.accountCreation && instance.registrations; - const pepeOpen = useAppSelector(state => state.verification.instance.get('registrations') === true); + const { isOpen } = useRegistrationStatus(); const isLoginPage = history.location.pathname === '/login'; - const shouldShowRegisterLink = (isLoginPage && (isOpen || (pepeEnabled && pepeOpen))); return (
@@ -50,7 +44,7 @@ const AuthLayout = () => {
- {shouldShowRegisterLink && ( + {(isLoginPage && isOpen) && (
- {(isOpen || pepeEnabled && pepeOpen) && ( + {isOpen && ( - {(isOpen || pepeEnabled && pepeOpen) && ( + {isOpen && ( diff --git a/app/soapbox/features/ui/components/navbar.tsx b/app/soapbox/features/ui/components/navbar.tsx index bbb357bfa..953526ee2 100644 --- a/app/soapbox/features/ui/components/navbar.tsx +++ b/app/soapbox/features/ui/components/navbar.tsx @@ -9,7 +9,7 @@ import { openSidebar } from 'soapbox/actions/sidebar'; import SiteLogo from 'soapbox/components/site-logo'; import { Avatar, Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui'; import Search from 'soapbox/features/compose/components/search'; -import { useAppDispatch, useInstance, useOwnAccount } from 'soapbox/hooks'; +import { useAppDispatch, useOwnAccount, useRegistrationStatus } from 'soapbox/hooks'; import ProfileDropdown from './profile-dropdown'; @@ -25,11 +25,9 @@ const messages = defineMessages({ const Navbar = () => { const dispatch = useAppDispatch(); const intl = useIntl(); - - const node = useRef(null); - + const { isOpen } = useRegistrationStatus(); const account = useOwnAccount(); - const instance = useInstance(); + const node = useRef(null); const [isLoading, setLoading] = useState(false); const [username, setUsername] = useState(''); @@ -150,7 +148,7 @@ const Navbar = () => { - {!instance.registrations && ( + {!isOpen && ( diff --git a/app/soapbox/features/ui/components/panels/sign-up-panel.tsx b/app/soapbox/features/ui/components/panels/sign-up-panel.tsx index 117a8a8b9..7df125591 100644 --- a/app/soapbox/features/ui/components/panels/sign-up-panel.tsx +++ b/app/soapbox/features/ui/components/panels/sign-up-panel.tsx @@ -2,13 +2,14 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { Button, Stack, Text } from 'soapbox/components/ui'; -import { useAppSelector, useInstance } from 'soapbox/hooks'; +import { useAppSelector, useInstance, useRegistrationStatus } from 'soapbox/hooks'; const SignUpPanel = () => { const instance = useInstance(); + const { isOpen } = useRegistrationStatus(); const me = useAppSelector((state) => state.me); - if (me || !instance.registrations) return null; + if (me || !isOpen) return null; return ( diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index 148aadb60..7c662bca2 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -12,7 +12,8 @@ export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; export { usePrevious } from './usePrevious'; export { useRefEventHandler } from './useRefEventHandler'; +export { useRegistrationStatus } from './useRegistrationStatus'; export { useSettings } from './useSettings'; export { useSoapboxConfig } from './useSoapboxConfig'; export { useSystemTheme } from './useSystemTheme'; -export { useTheme } from './useTheme'; +export { useTheme } from './useTheme'; \ No newline at end of file diff --git a/app/soapbox/hooks/useRegistrationStatus.ts b/app/soapbox/hooks/useRegistrationStatus.ts new file mode 100644 index 000000000..6ede86941 --- /dev/null +++ b/app/soapbox/hooks/useRegistrationStatus.ts @@ -0,0 +1,22 @@ +import { useAppSelector } from './useAppSelector'; +import { useFeatures } from './useFeatures'; +import { useInstance } from './useInstance'; +import { useSoapboxConfig } from './useSoapboxConfig'; + +export const useRegistrationStatus = () => { + const instance = useInstance(); + const features = useFeatures(); + const soapboxConfig = useSoapboxConfig(); + + const pepeOpen = useAppSelector(state => state.verification.instance.get('registrations') === true); + const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; + + return { + /** Registrations are open, either through Pepe or traditional account creation. */ + isOpen: (features.accountCreation && instance.registrations) || (pepeEnabled && pepeOpen), + /** Whether Pepe is open. */ + pepeOpen, + /** Whether Pepe is enabled. */ + pepeEnabled, + }; +}; \ No newline at end of file From e3faadac3de4d92283e914019c4909b6f0dce909 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 13 Jan 2023 19:31:13 -0600 Subject: [PATCH 12/21] Fix CHANGELOG --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a531b1a8..f511a0982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Admin: redirect the homepage to any URL. ### Changed ### Fixed +### Removed +- Admin: single user mode. Now the homepage can be redirected to any URL. + ## [3.1.0] - 2023-01-13 ### Added @@ -19,7 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - UI: added backdrop blur behind modals. - Admin: let admins configure media preview for attachment thumbnails. - Login: accept `?server` param in external login, eg `fe.soapbox.pub/login/external?server=gleasonator.com`. -- Admin: redirect the homepage to any URL. - Backups: restored Pleroma backups functionality. - Export: restored "Export data" to CSV. @@ -46,9 +49,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Composer: fix alignment of icon in submit button. - Login: add a border around QR codes. -### Removed -- Admin: single user mode. Now the homepage can be redirected to any URL. - ## [3.0.0] - 2022-12-25 ### Added From f218496b82ac5325c20d1829052acbbde95fcdf4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 14 Jan 2023 19:18:13 -0600 Subject: [PATCH 13/21] Fix UnauthorizedModal and Navbar --- .../ui/components/modals/unauthorized-modal.tsx | 15 ++++++++------- app/soapbox/features/ui/components/navbar.tsx | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx b/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx index 809abcbda..66d757935 100644 --- a/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx +++ b/app/soapbox/features/ui/components/modals/unauthorized-modal.tsx @@ -4,7 +4,7 @@ import { useHistory } from 'react-router-dom'; import { remoteInteraction } from 'soapbox/actions/interactions'; import { Button, Modal, Stack, Text } from 'soapbox/components/ui'; -import { useAppSelector, useAppDispatch, useFeatures, useInstance } from 'soapbox/hooks'; +import { useAppSelector, useAppDispatch, useFeatures, useInstance, useRegistrationStatus } from 'soapbox/hooks'; import toast from 'soapbox/toast'; const messages = defineMessages({ @@ -30,6 +30,7 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco const history = useHistory(); const dispatch = useAppDispatch(); const instance = useInstance(); + const { isOpen } = useRegistrationStatus(); const username = useAppSelector(state => state.accounts.get(accountId)?.display_name); const features = useFeatures(); @@ -97,10 +98,10 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco } - secondaryAction={onRegister} - secondaryText={} + secondaryAction={isOpen ? onRegister : undefined} + secondaryText={isOpen ? : undefined} >
@@ -121,7 +122,7 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco
- {instance.registrations && ( + {isOpen && ( @@ -141,8 +142,8 @@ const UnauthorizedModal: React.FC = ({ action, onClose, acco onClose={onClickClose} confirmationAction={onLogin} confirmationText={} - secondaryAction={onRegister} - secondaryText={} + secondaryAction={isOpen ? onRegister : undefined} + secondaryText={isOpen ? : undefined} > diff --git a/app/soapbox/features/ui/components/navbar.tsx b/app/soapbox/features/ui/components/navbar.tsx index 953526ee2..0b772f459 100644 --- a/app/soapbox/features/ui/components/navbar.tsx +++ b/app/soapbox/features/ui/components/navbar.tsx @@ -148,7 +148,7 @@ const Navbar = () => { - {!isOpen && ( + {isOpen && ( From 6f40c471c493e6e70a27e3439dcd0b82dd618620 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 14 Jan 2023 19:21:30 -0600 Subject: [PATCH 14/21] soapbox.tsx: simplify pepeEnabled variable --- app/soapbox/containers/soapbox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index d6c17db5f..6c94feb50 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -40,6 +40,7 @@ import { useTheme, useLocale, useInstance, + useRegistrationStatus, } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { normalizeSoapboxConfig } from 'soapbox/normalizers'; @@ -92,14 +93,13 @@ const SoapboxMount = () => { const account = useOwnAccount(); const soapboxConfig = useSoapboxConfig(); const features = useFeatures(); + const { pepeEnabled } = useRegistrationStatus(); const waitlisted = account && !account.source.get('approved', true); const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding); const showOnboarding = account && !waitlisted && needsOnboarding; const { redirectRootNoLogin } = soapboxConfig; - const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; - // @ts-ignore: I don't actually know what these should be, lol const shouldUpdateScroll = (prevRouterProps, { location }) => { return !(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey); From 1b2fcec0d70f87d16ce7b973c6c15362c1ec58f4 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 14 Jan 2023 19:29:34 -0600 Subject: [PATCH 15/21] RedirectRoot: correctly upgrade singleUserModeProfile of a remote user --- .../normalizers/soapbox/__tests__/soapbox-config.test.ts | 1 + app/soapbox/normalizers/soapbox/soapbox-config.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts index 6901254f2..9142a3356 100644 --- a/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts +++ b/app/soapbox/normalizers/soapbox/__tests__/soapbox-config.test.ts @@ -38,6 +38,7 @@ describe('normalizeSoapboxConfig()', () => { it('upgrades singleUserModeProfile to redirectRootNoLogin', () => { expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe('/@alex'); expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: '@alex' }).redirectRootNoLogin).toBe('/@alex'); + expect(normalizeSoapboxConfig({ singleUserMode: true, singleUserModeProfile: 'alex@gleasonator.com' }).redirectRootNoLogin).toBe('/@alex@gleasonator.com'); expect(normalizeSoapboxConfig({ singleUserMode: false, singleUserModeProfile: 'alex' }).redirectRootNoLogin).toBe(''); }); diff --git a/app/soapbox/normalizers/soapbox/soapbox-config.ts b/app/soapbox/normalizers/soapbox/soapbox-config.ts index dfac8a777..3b8b2ea91 100644 --- a/app/soapbox/normalizers/soapbox/soapbox-config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox-config.ts @@ -6,6 +6,7 @@ import { } from 'immutable'; import trimStart from 'lodash/trimStart'; +import { normalizeUsername } from 'soapbox/utils/input'; import { toTailwind } from 'soapbox/utils/tailwind'; import { generateAccent } from 'soapbox/utils/theme'; @@ -204,7 +205,7 @@ const upgradeSingleUserMode = (soapboxConfig: SoapboxConfigMap): SoapboxConfigMa if (!redirectRootNoLogin && singleUserMode && singleUserModeProfile) { return soapboxConfig - .set('redirectRootNoLogin', `/@${singleUserModeProfile.replaceAll('@', '')}`) + .set('redirectRootNoLogin', `/@${normalizeUsername(singleUserModeProfile)}`) .deleteAll(['singleUserMode', 'singleUserModeProfile']); } else { return soapboxConfig From 0a90c3c377c27b0b2236759f67fd6f3df049cc83 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 15 Jan 2023 12:35:34 -0600 Subject: [PATCH 16/21] Add tests to components with signup CTAs --- .../components/__tests__/cta-banner.test.tsx | 14 +++++ .../ui/components/__tests__/navbar.test.tsx | 40 ++++++++++++ .../__tests__/landing-page-modal.test.tsx | 40 ++++++++++++ .../__tests__/unauthorized-modal.test.tsx | 40 ++++++++++++ app/soapbox/features/ui/components/navbar.tsx | 2 +- .../panels/__tests__/sign-up-panel.test.tsx | 35 +++++++++++ .../ui/components/panels/sign-up-panel.tsx | 2 +- .../__tests__/useRegistrationStatus.test.ts | 62 +++++++++++++++++++ 8 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 app/soapbox/features/ui/components/__tests__/navbar.test.tsx create mode 100644 app/soapbox/features/ui/components/modals/__tests__/landing-page-modal.test.tsx create mode 100644 app/soapbox/features/ui/components/modals/__tests__/unauthorized-modal.test.tsx create mode 100644 app/soapbox/features/ui/components/panels/__tests__/sign-up-panel.test.tsx create mode 100644 app/soapbox/hooks/__tests__/useRegistrationStatus.test.ts diff --git a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx index 90ba1dcc3..f7ce106a7 100644 --- a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx @@ -1,3 +1,4 @@ +import { fromJS } from 'immutable'; import React from 'react'; import { normalizeInstance } from 'soapbox/normalizers'; @@ -30,4 +31,17 @@ describe('', () => { expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0); }); }); + + describe('with Pepe enabled', () => { + it('renders the banner', () => { + const store = { + instance: normalizeInstance({ registrations: false }), + soapbox: fromJS({ extensions: { pepe: { enabled: true } } }), + verification: { instance: fromJS({ registrations: true }) }, + }; + + render(, undefined, store); + expect(screen.getByTestId('cta-banner')).toHaveTextContent(/sign up/i); + }); + }); }); diff --git a/app/soapbox/features/ui/components/__tests__/navbar.test.tsx b/app/soapbox/features/ui/components/__tests__/navbar.test.tsx new file mode 100644 index 000000000..92c295bf1 --- /dev/null +++ b/app/soapbox/features/ui/components/__tests__/navbar.test.tsx @@ -0,0 +1,40 @@ +import { fromJS } from 'immutable'; +import React from 'react'; + +import { render, screen } from 'soapbox/jest/test-helpers'; +import { normalizeInstance } from 'soapbox/normalizers'; + +import Navbar from '../navbar'; + +describe('', () => { + it('successfully renders', () => { + render(); + expect(screen.getByTestId('navbar')).toBeInTheDocument(); + }); + + it('doesn\'t display the signup button by default', () => { + render(); + expect(screen.queryByText('Sign up')).not.toBeInTheDocument(); + }); + + describe('with registrations enabled', () => { + it('displays the signup button', () => { + const store = { instance: normalizeInstance({ registrations: true }) }; + render(, undefined, store); + expect(screen.getByText('Sign up')).toBeInTheDocument(); + }); + }); + + describe('with registrations closed, Pepe enabled', () => { + it('displays the signup button', () => { + const store = { + instance: normalizeInstance({ registrations: false }), + soapbox: fromJS({ extensions: { pepe: { enabled: true } } }), + verification: { instance: fromJS({ registrations: true }) }, + }; + + render(, undefined, store); + expect(screen.getByText('Sign up')).toBeInTheDocument(); + }); + }); +}); diff --git a/app/soapbox/features/ui/components/modals/__tests__/landing-page-modal.test.tsx b/app/soapbox/features/ui/components/modals/__tests__/landing-page-modal.test.tsx new file mode 100644 index 000000000..13602d7b2 --- /dev/null +++ b/app/soapbox/features/ui/components/modals/__tests__/landing-page-modal.test.tsx @@ -0,0 +1,40 @@ +import { fromJS } from 'immutable'; +import React from 'react'; + +import { render, screen } from 'soapbox/jest/test-helpers'; +import { normalizeInstance } from 'soapbox/normalizers'; + +import LandingPageModal from '../landing-page-modal'; + +describe('', () => { + it('successfully renders', () => { + render(); + expect(screen.getByTestId('modal')).toBeInTheDocument(); + }); + + it('doesn\'t display the signup button by default', () => { + render(); + expect(screen.queryByText('Register')).not.toBeInTheDocument(); + }); + + describe('with registrations enabled', () => { + it('displays the signup button', () => { + const store = { instance: normalizeInstance({ registrations: true }) }; + render(, undefined, store); + expect(screen.getByText('Register')).toBeInTheDocument(); + }); + }); + + describe('with registrations closed, Pepe enabled', () => { + it('displays the signup button', () => { + const store = { + instance: normalizeInstance({ registrations: false }), + soapbox: fromJS({ extensions: { pepe: { enabled: true } } }), + verification: { instance: fromJS({ registrations: true }) }, + }; + + render(, undefined, store); + expect(screen.getByText('Register')).toBeInTheDocument(); + }); + }); +}); diff --git a/app/soapbox/features/ui/components/modals/__tests__/unauthorized-modal.test.tsx b/app/soapbox/features/ui/components/modals/__tests__/unauthorized-modal.test.tsx new file mode 100644 index 000000000..5f79db2d6 --- /dev/null +++ b/app/soapbox/features/ui/components/modals/__tests__/unauthorized-modal.test.tsx @@ -0,0 +1,40 @@ +import { fromJS } from 'immutable'; +import React from 'react'; + +import { render, screen } from 'soapbox/jest/test-helpers'; +import { normalizeInstance } from 'soapbox/normalizers'; + +import UnauthorizedModal from '../unauthorized-modal'; + +describe('', () => { + it('successfully renders', () => { + render(); + expect(screen.getByTestId('modal')).toBeInTheDocument(); + }); + + it('doesn\'t display the signup button by default', () => { + render(); + expect(screen.queryByText('Sign up')).not.toBeInTheDocument(); + }); + + describe('with registrations enabled', () => { + it('displays the signup button', () => { + const store = { instance: normalizeInstance({ registrations: true }) }; + render(, undefined, store); + expect(screen.getByText('Sign up')).toBeInTheDocument(); + }); + }); + + describe('with registrations closed, Pepe enabled', () => { + it('displays the signup button', () => { + const store = { + instance: normalizeInstance({ registrations: false }), + soapbox: fromJS({ extensions: { pepe: { enabled: true } } }), + verification: { instance: fromJS({ registrations: true }) }, + }; + + render(, undefined, store); + expect(screen.getByText('Sign up')).toBeInTheDocument(); + }); + }); +}); diff --git a/app/soapbox/features/ui/components/navbar.tsx b/app/soapbox/features/ui/components/navbar.tsx index 0b772f459..dc8896e33 100644 --- a/app/soapbox/features/ui/components/navbar.tsx +++ b/app/soapbox/features/ui/components/navbar.tsx @@ -63,7 +63,7 @@ const Navbar = () => { if (mfaToken) return ; return ( -