diff --git a/apps/portal/src/components/TriggerButton.js b/apps/portal/src/components/TriggerButton.js
index 5cc0ef6519..fcb2cd01cf 100644
--- a/apps/portal/src/components/TriggerButton.js
+++ b/apps/portal/src/components/TriggerButton.js
@@ -9,7 +9,7 @@ import {ReactComponent as ButtonIcon3} from '../images/icons/button-icon-3.svg';
import {ReactComponent as ButtonIcon4} from '../images/icons/button-icon-4.svg';
import {ReactComponent as ButtonIcon5} from '../images/icons/button-icon-5.svg';
import TriggerButtonStyle from './TriggerButton.styles';
-import {isInviteOnlySite} from '../utils/helpers';
+import {isInviteOnlySite, isSigninAllowed} from '../utils/helpers';
import {hasMode} from '../utils/check-mode';
const ICON_MAPPING = {
@@ -164,12 +164,21 @@ class TriggerButtonContent extends React.Component {
onToggle() {
const {showPopup, member, site} = this.context;
+
if (showPopup) {
this.context.onAction('closePopup');
- } else {
- const loggedOutPage = isInviteOnlySite({site}) ? 'signin' : 'signup';
- const page = member ? 'accountHome' : loggedOutPage;
+ return;
+ }
+
+ if (member) {
+ this.context.onAction('openPopup', {page: 'accountHome'});
+ return;
+ }
+
+ if (isSigninAllowed({site})) {
+ const page = isInviteOnlySite({site}) ? 'signin' : 'signup';
this.context.onAction('openPopup', {page});
+ return;
}
}
@@ -240,10 +249,11 @@ export default class TriggerButton extends React.Component {
}
render() {
- const {portal_button: portalButton} = this.context.site;
+ const site = this.context.site;
+ const {portal_button: portalButton} = site;
const {showPopup} = this.context;
- if (!portalButton || hasMode(['offerPreview'])) {
+ if (!portalButton || !isSigninAllowed({site}) || hasMode(['offerPreview'])) {
return null;
}
diff --git a/apps/portal/src/components/pages/AccountHomePage/AccountHomePage.js b/apps/portal/src/components/pages/AccountHomePage/AccountHomePage.js
index 7cd092b313..cd55eb6369 100644
--- a/apps/portal/src/components/pages/AccountHomePage/AccountHomePage.js
+++ b/apps/portal/src/components/pages/AccountHomePage/AccountHomePage.js
@@ -4,12 +4,18 @@ import {getSupportAddress} from '../../../utils/helpers';
import AccountFooter from './components/AccountFooter';
import AccountMain from './components/AccountMain';
+import {isSigninAllowed} from '../../../utils/helpers';
export default class AccountHomePage extends React.Component {
static contextType = AppContext;
componentDidMount() {
- const {member} = this.context;
+ const {member, site} = this.context;
+
+ if (!isSigninAllowed({site})) {
+ this.context.onAction('signout');
+ }
+
if (!member) {
this.context.onAction('switchPage', {
page: 'signin',
@@ -31,6 +37,9 @@ export default class AccountHomePage extends React.Component {
if (!member) {
return null;
}
+ if (!isSigninAllowed({site})) {
+ return null;
+ }
return (
diff --git a/apps/portal/src/components/pages/AccountHomePage/components/SubscribeButton.js b/apps/portal/src/components/pages/AccountHomePage/components/SubscribeButton.js
index fd0ab0d63c..e5d4e4ffc2 100644
--- a/apps/portal/src/components/pages/AccountHomePage/components/SubscribeButton.js
+++ b/apps/portal/src/components/pages/AccountHomePage/components/SubscribeButton.js
@@ -1,13 +1,12 @@
import AppContext from '../../../../AppContext';
import ActionButton from '../../../common/ActionButton';
-import {hasOnlyFreePlan} from '../../../../utils/helpers';
+import {isSignupAllowed} from '../../../../utils/helpers';
import {useContext} from 'react';
const SubscribeButton = () => {
const {site, action, brandColor, onAction, t} = useContext(AppContext);
- const {is_stripe_configured: isStripeConfigured} = site;
- if (!isStripeConfigured || hasOnlyFreePlan({site})) {
+ if (!isSignupAllowed({site})) {
return null;
}
const isRunning = ['checkoutPlan:running'].includes(action);
diff --git a/apps/portal/src/components/pages/SigninPage.js b/apps/portal/src/components/pages/SigninPage.js
index 45922a0357..ad60cf44d8 100644
--- a/apps/portal/src/components/pages/SigninPage.js
+++ b/apps/portal/src/components/pages/SigninPage.js
@@ -5,6 +5,8 @@ import CloseButton from '../common/CloseButton';
import AppContext from '../../AppContext';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
+import {isSigninAllowed} from '../../utils/helpers';
+import {ReactComponent as InvitationIcon} from '../../images/icons/invitation.svg';
export default class SigninPage extends React.Component {
static contextType = AppContext;
@@ -116,6 +118,23 @@ export default class SigninPage extends React.Component {
}
renderForm() {
+ const {site, t} = this.context;
+
+ if (!isSigninAllowed({site})) {
+ return (
+
+
+
+ {t('Memberships unavailable, contact the owner for access.')}
+
+
+
+ );
+ }
+
return (
@@ -125,32 +144,52 @@ export default class SigninPage extends React.Component {
onKeyDown={(e, field) => this.onKeyDown(e, field)}
/>
+
);
}
- renderSiteLogo() {
- const siteLogo = this.context.site.icon;
+ renderSiteIcon() {
+ const iconStyle = {};
+ const {site} = this.context;
+ const siteIcon = site.icon;
- const logoStyle = {};
-
- if (siteLogo) {
- logoStyle.backgroundImage = `url(${siteLogo})`;
+ if (siteIcon) {
+ iconStyle.backgroundImage = `url(${siteIcon})`;
return (
-

+

+ );
+ } else if (!isSigninAllowed({site})) {
+ return (
+
);
}
return null;
}
- renderFormHeader() {
- // const siteTitle = this.context.site.title || 'Site Title';
- const {t} = this.context;
+ renderSiteTitle() {
+ const {site, t} = this.context;
+ const siteTitle = site.title;
+ if (!isSigninAllowed({site})) {
+ return (
+
{siteTitle}
+ );
+ } else {
+ return (
+
{t('Sign in')}
+ );
+ }
+ }
+
+ renderFormHeader() {
return (
- {this.renderSiteLogo()}
- {t('Sign in')}
+ {this.renderSiteIcon()}
+ {this.renderSiteTitle()}
);
}
@@ -158,19 +197,12 @@ export default class SigninPage extends React.Component {
render() {
return (
<>
- {/*
-
-
*/}
{this.renderFormHeader()}
{this.renderForm()}
-
>
);
diff --git a/apps/portal/src/components/pages/SigninPage.test.js b/apps/portal/src/components/pages/SigninPage.test.js
index 1e4d4def09..72fa3aba8f 100644
--- a/apps/portal/src/components/pages/SigninPage.test.js
+++ b/apps/portal/src/components/pages/SigninPage.test.js
@@ -1,18 +1,30 @@
-import {render, fireEvent} from '../../utils/test-utils';
+import {render, fireEvent, getByTestId} from '../../utils/test-utils';
import SigninPage from './SigninPage';
+import {getSiteData} from '../../utils/fixtures-generator';
-const setup = () => {
+const setup = (overrides) => {
const {mockOnActionFn, ...utils} = render(
,
{
overrideContext: {
- member: null
+ member: null,
+ ...overrides
}
}
);
- const emailInput = utils.getByLabelText(/email/i);
- const submitButton = utils.queryByRole('button', {name: 'Continue'});
- const signupButton = utils.queryByRole('button', {name: 'Sign up'});
+
+ let emailInput;
+ let submitButton;
+ let signupButton;
+
+ try {
+ emailInput = utils.getByLabelText(/email/i);
+ submitButton = utils.queryByRole('button', {name: 'Continue'});
+ signupButton = utils.queryByRole('button', {name: 'Sign up'});
+ } catch (err) {
+ // ignore
+ }
+
return {
emailInput,
submitButton,
@@ -47,4 +59,17 @@ describe('SigninPage', () => {
fireEvent.click(signupButton);
expect(mockOnActionFn).toHaveBeenCalledWith('switchPage', {page: 'signup'});
});
+
+ describe('when members are disabled', () => {
+ test('renders an informative message', () => {
+ setup({
+ site: getSiteData({
+ membersSignupAccess: 'none'
+ })
+ });
+
+ const message = getByTestId(document.body, 'members-disabled-notification-text');
+ expect(message).toBeInTheDocument();
+ });
+ });
});
diff --git a/apps/portal/src/components/pages/SignupPage.js b/apps/portal/src/components/pages/SignupPage.js
index 3c762b441a..4eebf8440d 100644
--- a/apps/portal/src/components/pages/SignupPage.js
+++ b/apps/portal/src/components/pages/SignupPage.js
@@ -7,7 +7,7 @@ import NewsletterSelectionPage from './NewsletterSelectionPage';
import ProductsSection from '../common/ProductsSection';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
-import {getSiteProducts, getSitePrices, hasOnlyFreePlan, isInviteOnlySite, freeHasBenefitsOrDescription, hasOnlyFreeProduct, getFreeProductBenefits, getFreeTierDescription, hasFreeProductPrice, hasMultipleNewsletters, hasFreeTrialTier} from '../../utils/helpers';
+import {getSiteProducts, getSitePrices, hasOnlyFreePlan, isInviteOnlySite, freeHasBenefitsOrDescription, hasOnlyFreeProduct, getFreeProductBenefits, getFreeTierDescription, hasFreeProductPrice, hasMultipleNewsletters, hasFreeTrialTier, isSignupAllowed} from '../../utils/helpers';
import {ReactComponent as InvitationIcon} from '../../images/icons/invitation.svg';
export const SignupPageStyles = `
@@ -171,7 +171,7 @@ footer.gh-portal-signup-footer.invite-only .gh-portal-signup-message {
margin-top: 0;
}
-.gh-portal-invite-only-notification {
+.gh-portal-invite-only-notification, .gh-portal-members-disabled-notification {
margin: 8px 32px 24px;
padding: 0;
text-align: center;
@@ -670,6 +670,21 @@ class SignupPage extends React.Component {
);
}
+ if (!isSignupAllowed({site})) {
+ return (
+
+
+
+ {t('Memberships unavailable, contact the owner for access.')}
+
+
+
+ );
+ }
+
const freeBenefits = getFreeProductBenefits({site});
const freeDescription = getFreeTierDescription({site});
const showOnlyFree = pageQuery === 'free' && hasFreeProductPrice({site});
@@ -716,22 +731,22 @@ class SignupPage extends React.Component {
);
}
- renderSiteLogo() {
+ renderSiteIcon() {
const {site, pageQuery} = this.context;
+ const siteIcon = site.icon;
- const siteLogo = site.icon;
-
- const logoStyle = {};
-
- if (siteLogo) {
- logoStyle.backgroundImage = `url(${siteLogo})`;
+ if (siteIcon) {
return (
-

+

);
} else if (isInviteOnlySite({site, pageQuery})) {
return (
);
+ } else if (!isSignupAllowed({site})) {
+ return (
+
+ );
}
return null;
}
@@ -741,7 +756,7 @@ class SignupPage extends React.Component {
const siteTitle = site.title || '';
return (
- {this.renderSiteLogo()}
+ {this.renderSiteIcon()}
{siteTitle}
);
@@ -794,10 +809,6 @@ class SignupPage extends React.Component {
{this.renderFormHeader()}
{this.renderForm()}
- {/*