Add terms and conditions checkbox to sign-up methods (#45)
A checkbox has been added for user acceptance of terms and conditions during sign-up. This change includes adding a new adjustable flag in the configuration to control the display of the checkbox. A new file "terms-and-conditions-form-field.tsx" is added to handle the checkbox UI part. Also, localization support has been added for the feature.
This commit is contained in:
committed by
GitHub
parent
3393863dd2
commit
a75f7c576d
@@ -44,6 +44,7 @@ function SignUpPage({ searchParams }: Props) {
|
|||||||
|
|
||||||
<SignUpMethodsContainer
|
<SignUpMethodsContainer
|
||||||
providers={authConfig.providers}
|
providers={authConfig.providers}
|
||||||
|
displayTermsCheckbox={authConfig.displayTermsCheckbox}
|
||||||
inviteToken={inviteToken}
|
inviteToken={inviteToken}
|
||||||
paths={paths}
|
paths={paths}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -5,7 +5,16 @@ import { z } from 'zod';
|
|||||||
const providers: z.ZodType<Provider> = getProviders();
|
const providers: z.ZodType<Provider> = getProviders();
|
||||||
|
|
||||||
const AuthConfigSchema = z.object({
|
const AuthConfigSchema = z.object({
|
||||||
captchaTokenSiteKey: z.string().optional(),
|
captchaTokenSiteKey: z
|
||||||
|
.string({
|
||||||
|
description: 'The reCAPTCHA site key.',
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
displayTermsCheckbox: z
|
||||||
|
.boolean({
|
||||||
|
description: 'Whether to display the terms checkbox during sign-up.',
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
providers: z.object({
|
providers: z.object({
|
||||||
password: z.boolean({
|
password: z.boolean({
|
||||||
description: 'Enable password authentication.',
|
description: 'Enable password authentication.',
|
||||||
@@ -22,6 +31,10 @@ const authConfig = AuthConfigSchema.parse({
|
|||||||
// Copy the value from the Supabase Dashboard.
|
// Copy the value from the Supabase Dashboard.
|
||||||
captchaTokenSiteKey: process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY,
|
captchaTokenSiteKey: process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY,
|
||||||
|
|
||||||
|
// whether to display the terms checkbox during sign-up
|
||||||
|
displayTermsCheckbox:
|
||||||
|
process.env.NEXT_PUBLIC_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX === 'true',
|
||||||
|
|
||||||
// NB: Enable the providers below in the Supabase Console
|
// NB: Enable the providers below in the Supabase Console
|
||||||
// in your production project
|
// in your production project
|
||||||
providers: {
|
providers: {
|
||||||
|
|||||||
@@ -61,6 +61,9 @@
|
|||||||
"emailPlaceholder": "your@email.com",
|
"emailPlaceholder": "your@email.com",
|
||||||
"inviteAlertHeading": "You have been invited to join a team",
|
"inviteAlertHeading": "You have been invited to join a team",
|
||||||
"inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.",
|
"inviteAlertBody": "Please sign in or sign up to accept the invite and join the team.",
|
||||||
|
"acceptTermsAndConditions": "I accept the <TermsOfServiceLink /> and <PrivacyPolicyLink />",
|
||||||
|
"termsOfService": "Terms of Service",
|
||||||
|
"privacyPolicy": "Privacy Policy",
|
||||||
"errors": {
|
"errors": {
|
||||||
"Invalid login credentials": "The credentials entered are invalid",
|
"Invalid login credentials": "The credentials entered are invalid",
|
||||||
"User already registered": "This credential is already in use. Please try with another one.",
|
"User already registered": "This credential is already in use. Please try with another one.",
|
||||||
|
|||||||
@@ -23,16 +23,20 @@ import { Input } from '@kit/ui/input';
|
|||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
import { useCaptchaToken } from '../captcha/client';
|
import { useCaptchaToken } from '../captcha/client';
|
||||||
|
import { TermsAndConditionsFormField } from './terms-and-conditions-form-field';
|
||||||
|
|
||||||
export function MagicLinkAuthContainer({
|
export function MagicLinkAuthContainer({
|
||||||
inviteToken,
|
inviteToken,
|
||||||
redirectUrl,
|
redirectUrl,
|
||||||
shouldCreateUser,
|
shouldCreateUser,
|
||||||
defaultValues,
|
defaultValues,
|
||||||
|
displayTermsCheckbox,
|
||||||
}: {
|
}: {
|
||||||
inviteToken?: string;
|
inviteToken?: string;
|
||||||
redirectUrl: string;
|
redirectUrl: string;
|
||||||
shouldCreateUser: boolean;
|
shouldCreateUser: boolean;
|
||||||
|
displayTermsCheckbox?: boolean;
|
||||||
|
|
||||||
defaultValues?: {
|
defaultValues?: {
|
||||||
email: string;
|
email: string;
|
||||||
};
|
};
|
||||||
@@ -115,6 +119,10 @@ export function MagicLinkAuthContainer({
|
|||||||
name={'email'}
|
name={'email'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<If condition={displayTermsCheckbox}>
|
||||||
|
<TermsAndConditionsFormField />
|
||||||
|
</If>
|
||||||
|
|
||||||
<Button disabled={signInWithOtpMutation.isPending}>
|
<Button disabled={signInWithOtpMutation.isPending}>
|
||||||
<If
|
<If
|
||||||
condition={signInWithOtpMutation.isPending}
|
condition={signInWithOtpMutation.isPending}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { AuthErrorAlert } from './auth-error-alert';
|
|||||||
import { PasswordSignUpForm } from './password-sign-up-form';
|
import { PasswordSignUpForm } from './password-sign-up-form';
|
||||||
|
|
||||||
interface EmailPasswordSignUpContainerProps {
|
interface EmailPasswordSignUpContainerProps {
|
||||||
|
displayTermsCheckbox?: boolean;
|
||||||
defaultValues?: {
|
defaultValues?: {
|
||||||
email: string;
|
email: string;
|
||||||
};
|
};
|
||||||
@@ -26,6 +27,7 @@ export function EmailPasswordSignUpContainer({
|
|||||||
defaultValues,
|
defaultValues,
|
||||||
onSignUp,
|
onSignUp,
|
||||||
emailRedirectTo,
|
emailRedirectTo,
|
||||||
|
displayTermsCheckbox
|
||||||
}: EmailPasswordSignUpContainerProps) {
|
}: EmailPasswordSignUpContainerProps) {
|
||||||
const { captchaToken, resetCaptchaToken } = useCaptchaToken();
|
const { captchaToken, resetCaptchaToken } = useCaptchaToken();
|
||||||
|
|
||||||
@@ -81,6 +83,7 @@ export function EmailPasswordSignUpContainer({
|
|||||||
onSubmit={onSignupRequested}
|
onSubmit={onSignupRequested}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
|
displayTermsCheckbox={displayTermsCheckbox}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import { Input } from '@kit/ui/input';
|
|||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
import { PasswordSignUpSchema } from '../schemas/password-sign-up.schema';
|
import { PasswordSignUpSchema } from '../schemas/password-sign-up.schema';
|
||||||
|
import { TermsAndConditionsFormField } from './terms-and-conditions-form-field';
|
||||||
|
|
||||||
export function PasswordSignUpForm({
|
export function PasswordSignUpForm({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
|
displayTermsCheckbox,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
loading,
|
loading,
|
||||||
}: {
|
}: {
|
||||||
@@ -30,6 +32,8 @@ export function PasswordSignUpForm({
|
|||||||
email: string;
|
email: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
displayTermsCheckbox?: boolean;
|
||||||
|
|
||||||
onSubmit: (params: {
|
onSubmit: (params: {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
@@ -130,6 +134,10 @@ export function PasswordSignUpForm({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<If condition={displayTermsCheckbox}>
|
||||||
|
<TermsAndConditionsFormField />
|
||||||
|
</If>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
data-test={'auth-submit-button'}
|
data-test={'auth-submit-button'}
|
||||||
className={'w-full'}
|
className={'w-full'}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export function SignUpMethodsContainer(props: {
|
|||||||
oAuth: Provider[];
|
oAuth: Provider[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
displayTermsCheckbox?: boolean;
|
||||||
inviteToken?: string;
|
inviteToken?: string;
|
||||||
}) {
|
}) {
|
||||||
const redirectUrl = getCallbackUrl(props);
|
const redirectUrl = getCallbackUrl(props);
|
||||||
@@ -39,6 +40,7 @@ export function SignUpMethodsContainer(props: {
|
|||||||
<EmailPasswordSignUpContainer
|
<EmailPasswordSignUpContainer
|
||||||
emailRedirectTo={redirectUrl}
|
emailRedirectTo={redirectUrl}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
|
displayTermsCheckbox={props.displayTermsCheckbox}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ export function SignUpMethodsContainer(props: {
|
|||||||
redirectUrl={redirectUrl}
|
redirectUrl={redirectUrl}
|
||||||
shouldCreateUser={true}
|
shouldCreateUser={true}
|
||||||
defaultValues={defaultValues}
|
defaultValues={defaultValues}
|
||||||
|
displayTermsCheckbox={props.displayTermsCheckbox}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
import { Checkbox } from '@kit/ui/checkbox';
|
||||||
|
import { FormControl, FormField, FormItem, FormMessage } from '@kit/ui/form';
|
||||||
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
|
export function TermsAndConditionsFormField(
|
||||||
|
props: {
|
||||||
|
name?: string;
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
name={props.name ?? 'termsAccepted'}
|
||||||
|
render={({ field }) => {
|
||||||
|
return (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<label className={'flex items-start space-x-2 py-2'}>
|
||||||
|
<Checkbox required name={field.name} />
|
||||||
|
|
||||||
|
<div className={'text-xs'}>
|
||||||
|
<Trans
|
||||||
|
i18nKey={'auth:acceptTermsAndConditions'}
|
||||||
|
components={{
|
||||||
|
TermsOfServiceLink: (
|
||||||
|
<Link
|
||||||
|
target={'_blank'}
|
||||||
|
className={'underline'}
|
||||||
|
href={'/terms-of-service'}
|
||||||
|
>
|
||||||
|
<Trans i18nKey={'auth:termsOfService'} />
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
PrivacyPolicyLink: (
|
||||||
|
<Link
|
||||||
|
target={'_blank'}
|
||||||
|
className={'underline'}
|
||||||
|
href={'/privacy-policy'}
|
||||||
|
>
|
||||||
|
<Trans i18nKey={'auth:privacyPolicy'} />
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user