Skip to content

Commit

Permalink
feat(elements): Add support for restricted mode (#4221)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmilewski authored Oct 10, 2024
1 parent d724a36 commit 1b573c6
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/three-timers-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/elements': minor
---

Adds `restricted` Step for restricted sign-up mode
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ export default function SignUpPage() {
<CustomResendable />
</SignUp.Strategy>
</SignUp.Step>

<SignUp.Step name='restricted'>
<H1>Restricted Access</H1>
<P>Access to this app is limited, and an invitation is required to sign up.</P>
</SignUp.Step>
</div>
</SignUp.Root>
);
Expand Down
7 changes: 7 additions & 0 deletions packages/elements/src/internals/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import type { SignUpModes } from '@clerk/types';

import { safeAccess } from '~/utils/safe-access';

export const SSO_CALLBACK_PATH_ROUTE = '/sso-callback';
export const CHOOSE_SESSION_PATH_ROUTE = '/choose';
export const MAGIC_LINK_VERIFY_PATH_ROUTE = '/verify';

export const SIGN_UP_MODES: Record<string, SignUpModes> = {
PUBLIC: 'public',
RESTRICTED: 'restricted',
};

// TODO: remove reliance on next-specific variables here
export const SIGN_IN_DEFAULT_BASE_PATH = safeAccess(
() => process.env.CLERK_SIGN_IN_URL ?? process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL,
Expand Down
14 changes: 14 additions & 0 deletions packages/elements/src/internals/machines/sign-up/router.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
SEARCH_PARAMS,
SIGN_IN_DEFAULT_BASE_PATH,
SIGN_UP_DEFAULT_BASE_PATH,
SIGN_UP_MODES,
SSO_CALLBACK_PATH_ROUTE,
} from '~/internals/constants';
import { ClerkElementsError, ClerkElementsRuntimeError } from '~/internals/errors';
Expand Down Expand Up @@ -156,6 +157,9 @@ export const SignUpRouterMachine = setup({

isLoggedIn: or(['isStatusComplete', ({ context }) => Boolean(context.clerk.user)]),
isSingleSessionMode: ({ context }) => Boolean(context.clerk?.__unstable__environment?.authConfig.singleSessionMode),
isRestricted: ({ context }) =>
context.clerk?.__unstable__environment?.userSettings.signUp.mode === SIGN_UP_MODES.RESTRICTED,
isRestrictedWithoutTicket: and(['isRestricted', not('hasTicket')]),
isExampleMode: ({ context }) => Boolean(context.exampleMode),
isMissingRequiredFields: and(['isStatusMissingRequirements', 'areFieldsMissing']),
isMissingRequiredUnverifiedFields: and(['isStatusMissingRequirements', 'areFieldsUnverified']),
Expand Down Expand Up @@ -311,6 +315,10 @@ export const SignUpRouterMachine = setup({
actions: { type: 'navigateInternal', params: { force: true, path: '/continue' } },
target: 'Continue',
},
{
guard: 'isRestrictedWithoutTicket',
target: 'Restricted',
},
{
actions: { type: 'navigateInternal', params: { force: true, path: '/' } },
target: 'Start',
Expand Down Expand Up @@ -478,6 +486,12 @@ export const SignUpRouterMachine = setup({
],
},
},
Restricted: {
tags: ['step:restricted'],
on: {
NEXT: 'Start',
},
},
Error: {
tags: ['step:error'],
on: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const SignUpRouterSteps = {
verification: 'step:verification',
callback: 'step:callback',
error: 'step:error',
restricted: 'step:restricted',
} as const;

export type SignUpRouterSteps = keyof typeof SignUpRouterSteps;
Expand Down
20 changes: 20 additions & 0 deletions packages/elements/src/react/sign-up/restricted.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { FormProps } from '~/react/common/form';
import { Form } from '~/react/common/form';
import { useActiveTags } from '~/react/hooks';
import { SignUpRouterCtx } from '~/react/sign-up/context';

export type SignUpRestrictedProps = FormProps;

export function SignUpRestricted(props: SignUpRestrictedProps) {
const routerRef = SignUpRouterCtx.useActorRef();
const activeState = useActiveTags(routerRef, 'step:restricted');

return activeState ? (
<Form
// TODO: Update when sign-up flow is consolidated
// @ts-expect-error - `flowActor` is not a valid prop for `Form`
flowActor={routerRef}
{...props}
/>
) : null;
}
12 changes: 10 additions & 2 deletions packages/elements/src/react/sign-up/step.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ClerkElementsRuntimeError } from '~/internals/errors';

import type { SignUpContinueProps } from './continue';
import { SignUpContinue } from './continue';
import type { SignUpRestrictedProps } from './restricted';
import { SignUpRestricted } from './restricted';
import type { SignUpStartProps } from './start';
import { SignUpStart } from './start';
import type { SignUpVerificationsProps } from './verifications';
Expand All @@ -14,6 +16,7 @@ export const SIGN_UP_STEPS = {
start: 'start',
continue: 'continue',
verifications: 'verifications',
restricted: 'restricted',
} as const;

export type TSignUpStep = (typeof SIGN_UP_STEPS)[keyof typeof SIGN_UP_STEPS];
Expand All @@ -22,7 +25,8 @@ type StepWithProps<N extends TSignUpStep, T> = { name: N } & T;
export type SignUpStepProps =
| StepWithProps<'start', SignUpStartProps>
| StepWithProps<'continue', SignUpContinueProps>
| StepWithProps<'verifications', SignUpVerificationsProps>;
| StepWithProps<'verifications', SignUpVerificationsProps>
| StepWithProps<'restricted', SignUpRestrictedProps>;

/**
* Render different steps of the sign-up flow. Initially the `'start'` step is rendered. Optionally, you can render additional fields in the `'continue'` step. Once a sign-up attempt has been created, `'verifications'` will be displayed.
Expand Down Expand Up @@ -50,7 +54,11 @@ export function SignUpStep(props: SignUpStepProps) {
return <SignUpContinue {...props} />;
case SIGN_UP_STEPS.verifications:
return <SignUpVerifications {...props} />;
case SIGN_UP_STEPS.restricted:
return <SignUpRestricted {...props} />;
default:
throw new ClerkElementsRuntimeError(`Invalid step name. Use 'start', 'continue', or 'verifications'.`);
throw new ClerkElementsRuntimeError(
`Invalid step name. Use 'start', 'continue', 'verifications', or 'restricted'.`,
);
}
}

0 comments on commit 1b573c6

Please sign in to comment.