Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9c54f49
feat(clerk-js): Add legal consent for Sign Up
octoper Sep 30, 2024
4e0f333
feat(clerk-js): Add legal consent checkbox on sign up
octoper Oct 1, 2024
f5bff6e
feat(clerk-js): Handle legal consent in <SignUp/>
octoper Oct 2, 2024
3a4acbc
fix(clerk-js): Fix types for SignUpCreateParams
octoper Oct 3, 2024
cca62a9
fix(clerk-js): Rename legalAccepted to __experimental_legalAccepted
octoper Oct 3, 2024
0de78e2
Update sign up form
octoper Oct 8, 2024
5ff22b3
feat(clerk-js): Add legal consent checkbox to SignUp
octoper Oct 14, 2024
79ec2ae
chore(clerk-js): Make legal accepted as experimental
octoper Oct 15, 2024
857dfca
chore(repo): Add changeset
octoper Oct 16, 2024
921d9b5
chore(clerk-js): Remove localization modifiers
octoper Oct 16, 2024
bc61071
chore(clerk-js): Style the polished checkbox
octoper Oct 16, 2024
11d6e6b
chore(clerk-js): Fix styling
octoper Oct 16, 2024
e0038e5
chore(clerk-js): Add TODO comments to remind me to do action after st…
octoper Oct 16, 2024
9ffd367
test(clerk-js): Add simple tests
octoper Oct 16, 2024
163fd5d
fix(clerk-js): Check missingFields is not null
octoper Oct 17, 2024
1e02572
fix(clerk-js): Fix tests
octoper Oct 17, 2024
016fee1
fix(clerk-js): Fix styling for checkbox
octoper Oct 17, 2024
d3e4c7b
chore(clerk-js): Move Legal consent checkbox to its own component
octoper Oct 17, 2024
0bc578c
chore(clerk-js): Apply lint fixes
octoper Oct 17, 2024
b731ad0
fix(clerk-js,types,localization): Mark legal consent as experimental
octoper Oct 17, 2024
fe370c1
fix(clerk-js): Check if the __experimental_legalAccepted is not undef…
octoper Oct 17, 2024
9b1e072
tests(clerk-js): Revert changes for SignUpStart
octoper Oct 17, 2024
a75f7fd
tests(clerk-js): Fix SignUpContinue tests
octoper Oct 17, 2024
a71579b
chore(clerk-js): Remove label from form control
octoper Oct 18, 2024
cfed76e
chore(clerk-js,types,localization): Introduce LinkRenderer
octoper Oct 18, 2024
94247d1
test(clerk-js): Update tests fixture
octoper Oct 18, 2024
248b505
fix(clerk-js): Increase bundlewatch limit for ui-common
octoper Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/curvy-ghosts-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@clerk/localizations": minor
"@clerk/clerk-js": minor
"@clerk/types": minor
---

Adding experimental support for legal consent for `<SignUp/>` component
2 changes: 1 addition & 1 deletion packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"files": [
{ "path": "./dist/clerk.browser.js", "maxSize": "68kB" },
{ "path": "./dist/clerk.headless.js", "maxSize": "44kB" },
{ "path": "./dist/ui-common*.js", "maxSize": "86KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "87KB" },
{ "path": "./dist/vendors*.js", "maxSize": "70KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "58KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
Expand Down
3 changes: 3 additions & 0 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,7 @@ export class Clerk implements ClerkInterface {
return this.client?.signUp.create({
strategy: 'google_one_tap',
token: params.token,
__experimental_legalAccepted: params.__experimental_legalAccepted,
});
}
throw err;
Expand All @@ -1420,6 +1421,7 @@ export class Clerk implements ClerkInterface {
customNavigate,
unsafeMetadata,
strategy,
__experimental_legalAccepted,
}: ClerkAuthenticateWithWeb3Params): Promise<void> => {
if (!this.client || !this.environment) {
return;
Expand All @@ -1442,6 +1444,7 @@ export class Clerk implements ClerkInterface {
generateSignature,
unsafeMetadata,
strategy,
__experimental_legalAccepted,
});

if (
Expand Down
4 changes: 4 additions & 0 deletions packages/clerk-js/src/core/resources/DisplayConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export class DisplayConfig extends BaseResource implements DisplayConfigResource
afterCreateOrganizationUrl!: string;
googleOneTapClientId?: string;
showDevModeWarning!: boolean;
termsUrl!: string;
privacyPolicyUrl!: string;

public constructor(data: DisplayConfigJSON) {
super();
Expand Down Expand Up @@ -87,6 +89,8 @@ export class DisplayConfig extends BaseResource implements DisplayConfigResource
this.afterCreateOrganizationUrl = data.after_create_organization_url;
this.googleOneTapClientId = data.google_one_tap_client_id;
this.showDevModeWarning = data.show_devmode_warning;
this.termsUrl = data.terms_url;
this.privacyPolicyUrl = data.privacy_policy_url;
return this;
}
}
44 changes: 39 additions & 5 deletions packages/clerk-js/src/core/resources/SignUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class SignUp extends BaseResource implements SignUpResource {
createdSessionId: string | null = null;
createdUserId: string | null = null;
abandonAt: number | null = null;
legalAcceptedAt: number | null = null;

constructor(data: SignUpJSON | null = null) {
super();
Expand Down Expand Up @@ -111,6 +112,12 @@ export class SignUp extends BaseResource implements SignUpResource {
paramsWithCaptcha.strategy = SignUp.clerk.client?.signIn.firstFactorVerification.strategy;
}

// TODO(@vaggelis): Remove this once the legalAccepted is stable
if (typeof params.__experimental_legalAccepted !== 'undefined') {
paramsWithCaptcha.legalAccepted = params.__experimental_legalAccepted;
paramsWithCaptcha.__experimental_legalAccepted = undefined;
}

return this._basePost({
path: this.pathRoot,
body: normalizeUnsafeMetadata(paramsWithCaptcha),
Expand Down Expand Up @@ -190,17 +197,26 @@ export class SignUp extends BaseResource implements SignUpResource {
};

public authenticateWithWeb3 = async (
params: AuthenticateWithWeb3Params & { unsafeMetadata?: SignUpUnsafeMetadata },
params: AuthenticateWithWeb3Params & {
unsafeMetadata?: SignUpUnsafeMetadata;
__experimental_legalAccepted?: boolean;
},
): Promise<SignUpResource> => {
const { generateSignature, identifier, unsafeMetadata, strategy = 'web3_metamask_signature' } = params || {};
const {
generateSignature,
identifier,
unsafeMetadata,
strategy = 'web3_metamask_signature',
__experimental_legalAccepted,
} = params || {};
const provider = strategy.replace('web3_', '').replace('_signature', '') as Web3Provider;

if (!(typeof generateSignature === 'function')) {
clerkMissingOptionError('generateSignature');
}

const web3Wallet = identifier || this.web3wallet!;
await this.create({ web3Wallet, unsafeMetadata });
await this.create({ web3Wallet, unsafeMetadata, __experimental_legalAccepted: __experimental_legalAccepted });
await this.prepareWeb3WalletVerification({ strategy });

const { message } = this.verifications.web3Wallet;
Expand Down Expand Up @@ -229,25 +245,33 @@ export class SignUp extends BaseResource implements SignUpResource {
return this.attemptWeb3WalletVerification({ signature, strategy });
};

public authenticateWithMetamask = async (params?: SignUpAuthenticateWithWeb3Params): Promise<SignUpResource> => {
public authenticateWithMetamask = async (
params?: SignUpAuthenticateWithWeb3Params & {
__experimental_legalAccepted?: boolean;
},
): Promise<SignUpResource> => {
const identifier = await getMetamaskIdentifier();
return this.authenticateWithWeb3({
identifier,
generateSignature: generateSignatureWithMetamask,
unsafeMetadata: params?.unsafeMetadata,
strategy: 'web3_metamask_signature',
__experimental_legalAccepted: params?.__experimental_legalAccepted,
});
};

public authenticateWithCoinbaseWallet = async (
params?: SignUpAuthenticateWithWeb3Params,
params?: SignUpAuthenticateWithWeb3Params & {
__experimental_legalAccepted?: boolean;
},
): Promise<SignUpResource> => {
const identifier = await getCoinbaseWalletIdentifier();
return this.authenticateWithWeb3({
identifier,
generateSignature: generateSignatureWithCoinbaseWallet,
unsafeMetadata: params?.unsafeMetadata,
strategy: 'web3_coinbase_wallet_signature',
__experimental_legalAccepted: params?.__experimental_legalAccepted,
});
};

Expand All @@ -258,6 +282,7 @@ export class SignUp extends BaseResource implements SignUpResource {
continueSignUp = false,
unsafeMetadata,
emailAddress,
__experimental_legalAccepted,
}: AuthenticateWithRedirectParams & {
unsafeMetadata?: SignUpUnsafeMetadata;
}): Promise<void> => {
Expand All @@ -268,6 +293,7 @@ export class SignUp extends BaseResource implements SignUpResource {
actionCompleteRedirectUrl: redirectUrlComplete,
unsafeMetadata,
emailAddress,
__experimental_legalAccepted,
};
return continueSignUp && this.id ? this.update(params) : this.create(params);
};
Expand All @@ -294,6 +320,13 @@ export class SignUp extends BaseResource implements SignUpResource {
};

update = (params: SignUpUpdateParams): Promise<SignUpResource> => {
// TODO(@vaggelis): Remove this once the legalAccepted is stable
if (typeof params.__experimental_legalAccepted !== 'undefined') {
// @ts-expect-error - We need to remove the __experimental_legalAccepted key from the params
params.legalAccepted = params.__experimental_legalAccepted;
params.__experimental_legalAccepted = undefined;
}

return this._basePatch({
body: normalizeUnsafeMetadata(params),
});
Expand Down Expand Up @@ -328,6 +361,7 @@ export class SignUp extends BaseResource implements SignUpResource {
this.createdUserId = data.created_user_id;
this.abandonAt = data.abandon_at;
this.web3wallet = data.web3_wallet;
this.legalAcceptedAt = data.legal_accepted_at;
}
return this;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/clerk-js/src/core/resources/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export class User extends BaseResource implements UserResource {
createOrganizationsLimit: number | null = null;
deleteSelfEnabled = false;
lastSignInAt: Date | null = null;
legalAcceptedAt: Date | null = null;
updatedAt: Date | null = null;
createdAt: Date | null = null;

Expand Down Expand Up @@ -360,6 +361,10 @@ export class User extends BaseResource implements UserResource {
this.lastSignInAt = unixEpochToDate(data.last_sign_in_at);
}

if (data.legal_accepted_at) {
this.legalAcceptedAt = unixEpochToDate(data.legal_accepted_at);
}

this.updatedAt = unixEpochToDate(data.updated_at);
this.createdAt = unixEpochToDate(data.created_at);
return this;
Expand Down
46 changes: 34 additions & 12 deletions packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useClerk } from '@clerk/shared/react';
import React from 'react';
import React, { useMemo } from 'react';

import { useCoreSignUp, useEnvironment, useSignUpContext } from '../../contexts';
import { descriptors, Flex, Flow, localizationKeys } from '../../customizables';
Expand Down Expand Up @@ -38,12 +38,6 @@ function _SignUpContinue() {
getInitialActiveIdentifier(attributes, userSettings.signUp.progressive),
);

// Redirect to sign-up if there is no persisted sign-up
if (!signUp.id) {
void navigate(displayConfig.signUpUrl);
return <LoadingCard />;
}

// TODO: This form should be shared between SignUpStart and SignUpContinue
const formState = {
firstName: useFormControl('firstName', initialValues.firstName || '', {
Expand Down Expand Up @@ -77,8 +71,25 @@ function _SignUpContinue() {
placeholder: localizationKeys('formFieldInputPlaceholder__password'),
validatePassword: true,
}),
__experimental_legalAccepted: useFormControl('__experimental_legalAccepted', '', {
type: 'checkbox',
label: '',
defaultChecked: false,
isRequired: userSettings.signUp.legal_consent_enabled || false,
}),
} as const;

const onlyLegalConsentMissing = useMemo(
() => signUp.missingFields && signUp.missingFields.length === 1 && signUp.missingFields[0] === 'legal_accepted',
[signUp.missingFields],
);

// Redirect to sign-up if there is no persisted sign-up
if (!signUp.id) {
void navigate(displayConfig.signUpUrl);
return <LoadingCard />;
}

const hasEmail = !!formState.emailAddress.value;
const hasVerifiedExternalAccount = signUp.verifications?.externalAccount?.status == 'verified';
const hasVerifiedWeb3 = signUp.verifications?.web3Wallet?.status == 'verified';
Expand All @@ -89,6 +100,7 @@ function _SignUpContinue() {
activeCommIdentifierType,
signUp,
isProgressiveSignUp,
legalConsentRequired: userSettings.signUp.legal_consent_enabled,
});
minimizeFieldsForExistingSignup(fields, signUp);

Expand Down Expand Up @@ -131,12 +143,13 @@ function _SignUpContinue() {
!phoneNumberProvided &&
emailOrPhone(attributes, isProgressiveSignUp)
) {
fieldsToSubmit.push(formState['emailAddress']);
fieldsToSubmit.push(formState['phoneNumber']);
fieldsToSubmit.push(formState.emailAddress);
fieldsToSubmit.push(formState.phoneNumber);
}

card.setLoading();
card.setError(undefined);

return signUp
.update(buildRequest(fieldsToSubmit))
.then(res =>
Expand All @@ -156,13 +169,21 @@ function _SignUpContinue() {
const showOauthProviders = !hasVerifiedExternalAccount && oauthOptions.length > 0;
const showWeb3Providers = !hasVerifiedWeb3 && web3Options.length > 0;

const headerTitle = !onlyLegalConsentMissing
? localizationKeys('signUp.continue.title')
: localizationKeys('signUp.__experimental_legalConsent.continue.title');

const headerSubtitle = !onlyLegalConsentMissing
? localizationKeys('signUp.continue.subtitle')
: localizationKeys('signUp.__experimental_legalConsent.continue.subtitle');

return (
<Flow.Part part='complete'>
<Card.Root>
<Card.Content>
<Header.Root showLogo>
<Header.Title localizationKey={localizationKeys('signUp.continue.title')} />
<Header.Subtitle localizationKey={localizationKeys('signUp.continue.subtitle')} />
<Header.Title localizationKey={headerTitle} />
<Header.Subtitle localizationKey={headerSubtitle} />
</Header.Root>
<Card.Alert>{card.error}</Card.Alert>
<Flex
Expand All @@ -171,7 +192,7 @@ function _SignUpContinue() {
gap={8}
>
<SocialButtonsReversibleContainerWithDivider>
{(showOauthProviders || showWeb3Providers) && (
{(showOauthProviders || showWeb3Providers) && !onlyLegalConsentMissing && (
<SignUpSocialButtons
enableOAuthProviders={showOauthProviders}
enableWeb3Providers={showWeb3Providers}
Expand All @@ -182,6 +203,7 @@ function _SignUpContinue() {
handleSubmit={handleSubmit}
fields={fields}
formState={formState}
onlyLegalAcceptedMissing={onlyLegalConsentMissing}
canToggleEmailPhone={canToggleEmailPhone}
handleEmailPhoneToggle={handleChangeActive}
/>
Expand Down
Loading
Loading