Skip to content

Commit c906385

Browse files
authored
feat(clerk-js,ui,types): Hide sign up url from <SignIn /> component mode is restricted (clerk#4206)
1 parent 737bcbb commit c906385

9 files changed

Lines changed: 75 additions & 15 deletions

File tree

.changeset/gold-lamps-appear.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@clerk/clerk-js": minor
3+
"@clerk/types": minor
4+
---
5+
6+
Hide sign up url from `<SignIn />` component when mode is `restricted`

packages/clerk-js/bundlewatch.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"files": [
3-
{ "path": "./dist/clerk.browser.js", "maxSize": "64kB" },
3+
{ "path": "./dist/clerk.browser.js", "maxSize": "64.1kB" },
44
{ "path": "./dist/clerk.headless.js", "maxSize": "43kB" },
55
{ "path": "./dist/ui-common*.js", "maxSize": "86KB" },
66
{ "path": "./dist/vendors*.js", "maxSize": "70KB" },

packages/clerk-js/src/core/constants.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { SignUpModes } from '@clerk/types';
2+
13
// TODO: Do we still have a use for this or can we simply preserve all params?
24
export const PRESERVED_QUERYSTRING_PARAMS = [
35
'redirect_url',
@@ -29,3 +31,8 @@ export const SIGN_IN_INITIAL_VALUE_KEYS = ['email_address', 'phone_number', 'use
2931
export const SIGN_UP_INITIAL_VALUE_KEYS = ['email_address', 'phone_number', 'username', 'first_name', 'last_name'];
3032

3133
export const DEBOUNCE_MS = 350;
34+
35+
export const SIGN_UP_MODES: Record<string, SignUpModes> = {
36+
PUBLIC: 'public',
37+
RESTRICTED: 'restricted',
38+
};

packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isWebAuthnAutofillSupported, isWebAuthnSupported } from '@clerk/shared/
33
import type { ClerkAPIError, SignInCreateParams, SignInResource } from '@clerk/types';
44
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
55

6-
import { ERROR_CODES } from '../../../core/constants';
6+
import { ERROR_CODES, SIGN_UP_MODES } from '../../../core/constants';
77
import { clerkInvalidFAPIResponse } from '../../../core/errors';
88
import { getClerkQueryParam, removeClerkQueryParam } from '../../../utils';
99
import type { SignInStartIdentifier } from '../../common';
@@ -410,13 +410,15 @@ export function _SignInStart(): JSX.Element {
410410
</Col>
411411
</Card.Content>
412412
<Card.Footer>
413-
<Card.Action elementId='signIn'>
414-
<Card.ActionText localizationKey={localizationKeys('signIn.start.actionText')} />
415-
<Card.ActionLink
416-
localizationKey={localizationKeys('signIn.start.actionLink')}
417-
to={clerk.buildUrlWithAuth(signUpUrl)}
418-
/>
419-
</Card.Action>
413+
{userSettings.signUp.mode === SIGN_UP_MODES.PUBLIC && (
414+
<Card.Action elementId='signIn'>
415+
<Card.ActionText localizationKey={localizationKeys('signIn.start.actionText')} />
416+
<Card.ActionLink
417+
localizationKey={localizationKeys('signIn.start.actionLink')}
418+
to={clerk.buildUrlWithAuth(signUpUrl)}
419+
/>
420+
</Card.Action>
421+
)}
420422
</Card.Footer>
421423
</Card.Root>
422424
</Flow.Part>

packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,29 @@ describe('SignInStart', () => {
111111
});
112112
});
113113

114+
describe('Restricted mode', () => {
115+
it('"Don\'t have an account?" text should not be presented', async () => {
116+
const { wrapper } = await createFixtures(f => {
117+
f.withEmailAddress();
118+
f.withRestrictedMode();
119+
});
120+
render(<SignInStart />, { wrapper });
121+
expect(screen.queryByText(/Dont have an account/i)).not.toBeInTheDocument();
122+
});
123+
124+
it('"Don\'t have an account?" text should be visible', async () => {
125+
const { wrapper, fixtures } = await createFixtures(f => {
126+
f.withEmailAddress();
127+
});
128+
render(<SignInStart />, { wrapper });
129+
130+
const signUpLink = screen.getByText(/Dont have an account/i).nextElementSibling;
131+
expect(signUpLink?.textContent).toBe('Sign up');
132+
expect(signUpLink?.tagName.toUpperCase()).toBe('A');
133+
expect(signUpLink?.getAttribute('href')).toMatch(fixtures.environment.displayConfig.signUpUrl);
134+
});
135+
});
136+
114137
describe('Social OAuth', () => {
115138
it.each(OAUTH_PROVIDERS)('shows the "Continue with $name" social OAuth button', async ({ provider, name }) => {
116139
const { wrapper } = await createFixtures(f => {

packages/clerk-js/src/ui/utils/test/fixtureHelpers.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717
VerificationJSON,
1818
} from '@clerk/types';
1919

20+
import { SIGN_UP_MODES } from '../../../core/constants';
2021
import type { OrgParams } from '../../../core/test/fixtures';
2122
import { createUser, getOrganizationId } from '../../../core/test/fixtures';
2223
import { createUserFixture } from './fixtures';
@@ -318,6 +319,8 @@ const createUserSettingsFixtureHelpers = (environment: EnvironmentJSON) => {
318319
show_zxcvbn: false,
319320
min_zxcvbn_strength: 0,
320321
};
322+
us.sign_up.mode = SIGN_UP_MODES.PUBLIC;
323+
321324
const emptyAttribute = {
322325
first_factors: [],
323326
second_factors: [],
@@ -477,6 +480,10 @@ const createUserSettingsFixtureHelpers = (environment: EnvironmentJSON) => {
477480
};
478481
};
479482

483+
const withRestrictedMode = () => {
484+
us.sign_up.mode = SIGN_UP_MODES.RESTRICTED;
485+
};
486+
480487
// TODO: Add the rest, consult pkg/generate/auth_config.go
481488

482489
return {
@@ -494,5 +501,6 @@ const createUserSettingsFixtureHelpers = (environment: EnvironmentJSON) => {
494501
withAuthenticatorApp,
495502
withPasskey,
496503
withPasskeySettings,
504+
withRestrictedMode,
497505
};
498506
};

packages/types/src/userSettings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,13 @@ export type SignInData = {
4747
};
4848
};
4949

50+
export type SignUpModes = 'public' | 'restricted';
51+
5052
export type SignUpData = {
5153
allowlist_only: boolean;
5254
progressive: boolean;
5355
captcha_enabled: boolean;
56+
mode: SignUpModes;
5457
};
5558

5659
export type PasswordSettingsData = {

packages/ui/src/components/sign-in/steps/start.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import { PhoneNumberField } from '~/common/phone-number-field';
1111
import { PhoneNumberOrUsernameField } from '~/common/phone-number-or-username-field';
1212
import { UsernameField } from '~/common/username-field';
1313
import { LOCALIZATION_NEEDED } from '~/constants/localizations';
14+
import { SIGN_UP_MODES } from '~/constants/user-settings';
1415
import { useAppearance } from '~/contexts';
1516
import { useAttributes } from '~/hooks/use-attributes';
1617
import { useCard } from '~/hooks/use-card';
1718
import { useDevModeWarning } from '~/hooks/use-dev-mode-warning';
1819
import { useDisplayConfig } from '~/hooks/use-display-config';
1920
import { useEnabledConnections } from '~/hooks/use-enabled-connections';
21+
import { useEnvironment } from '~/hooks/use-environment';
2022
import { useLocalizations } from '~/hooks/use-localizations';
2123
import { Button } from '~/primitives/button';
2224
import * as Card from '~/primitives/card';
@@ -27,6 +29,7 @@ import { Separator } from '~/primitives/separator';
2729
export function SignInStart() {
2830
const enabledConnections = useEnabledConnections();
2931
const { t } = useLocalizations();
32+
const { userSettings } = useEnvironment();
3033
const { enabled: usernameEnabled } = useAttributes('username');
3134
const { enabled: phoneNumberEnabled } = useAttributes('phone_number');
3235
const { enabled: emailAddressEnabled } = useAttributes('email_address');
@@ -184,12 +187,14 @@ export function SignInStart() {
184187
</Card.Content>
185188

186189
<Card.Footer {...footerProps}>
187-
<Card.FooterAction>
188-
<Card.FooterActionText>
189-
{t('signIn.start.actionText')}{' '}
190-
<Card.FooterActionLink href='/sign-up'> {t('signIn.start.actionLink')}</Card.FooterActionLink>
191-
</Card.FooterActionText>
192-
</Card.FooterAction>
190+
{userSettings.signUp.mode === SIGN_UP_MODES.PUBLIC ? (
191+
<Card.FooterAction>
192+
<Card.FooterActionText>
193+
{t('signIn.start.actionText')}{' '}
194+
<Card.FooterActionLink href='/sign-up'> {t('signIn.start.actionLink')}</Card.FooterActionLink>
195+
</Card.FooterActionText>
196+
</Card.FooterAction>
197+
) : null}
193198
</Card.Footer>
194199
</Card.Root>
195200
</SignIn.Step>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { SignUpModes } from '@clerk/types';
2+
3+
export const SIGN_UP_MODES: Record<string, SignUpModes> = {
4+
PUBLIC: 'public',
5+
RESTRICTED: 'restricted',
6+
};

0 commit comments

Comments
 (0)