From f6c635aac3e3fe44753fdb679b68fa19fe4f66b2 Mon Sep 17 00:00:00 2001 From: Giancarlo Buomprisco Date: Tue, 2 Dec 2025 21:40:56 +0800 Subject: [PATCH] chore: bump version to 2.21.6 in package.json and enhance captcha integration across auth components (#418) - Updated application version from 2.21.4 to 2.21.6 in package.json. - Added "verifyingCaptcha" message to auth.json for improved user feedback during captcha verification. - Enhanced captcha handling in various authentication components, including MagicLinkAuthContainer, PasswordResetRequestContainer, and SignUpContainer, to reflect loading states and improve user experience. --- apps/web/public/locales/en/auth.json | 1 + package.json | 2 +- .../auth/src/captcha/client/use-captcha.tsx | 7 +++- .../components/magic-link-auth-container.tsx | 17 +++++++--- .../password-reset-request-container.tsx | 13 +++++-- .../components/password-sign-in-container.tsx | 2 ++ .../src/components/password-sign-in-form.tsx | 8 +++++ .../components/password-sign-up-container.tsx | 2 ++ .../src/components/password-sign-up-form.tsx | 34 +++++++++++-------- .../src/components/resend-auth-link-form.tsx | 12 ++++++- 10 files changed, 74 insertions(+), 24 deletions(-) diff --git a/apps/web/public/locales/en/auth.json b/apps/web/public/locales/en/auth.json index 9e80d4b40..9c35819b5 100644 --- a/apps/web/public/locales/en/auth.json +++ b/apps/web/public/locales/en/auth.json @@ -10,6 +10,7 @@ "signOut": "Sign out", "signingIn": "Signing in...", "signingUp": "Signing up...", + "verifyingCaptcha": "Verifying...", "doNotHaveAccountYet": "Do not have an account yet?", "alreadyHaveAnAccount": "Already have an account?", "signUpToAcceptInvite": "Please sign in/up to accept the invite", diff --git a/package.json b/package.json index da15be97c..2ceeca43d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-supabase-saas-kit-turbo", - "version": "2.21.4", + "version": "2.21.6", "private": true, "sideEffects": false, "engines": { diff --git a/packages/features/auth/src/captcha/client/use-captcha.tsx b/packages/features/auth/src/captcha/client/use-captcha.tsx index c571dbe7d..7b97d6f8e 100644 --- a/packages/features/auth/src/captcha/client/use-captcha.tsx +++ b/packages/features/auth/src/captcha/client/use-captcha.tsx @@ -67,15 +67,20 @@ export function useCaptcha( [siteKey, nonce, handleTokenChange, handleInstanceChange], ); + // Ready when captcha is not configured (no siteKey) or token is available + const isReady = !siteKey || token !== ''; + return useMemo( () => ({ /** The current captcha token */ token, + /** Whether the captcha is ready (not configured or token available) */ + isReady, /** Reset the captcha (clears token and resets widget) */ reset, /** The captcha field component to render */ field, }), - [token, reset, field], + [token, isReady, reset, field], ); } diff --git a/packages/features/auth/src/components/magic-link-auth-container.tsx b/packages/features/auth/src/components/magic-link-auth-container.tsx index c0d613588..e82bba939 100644 --- a/packages/features/auth/src/components/magic-link-auth-container.tsx +++ b/packages/features/auth/src/components/magic-link-auth-container.tsx @@ -49,6 +49,8 @@ export function MagicLinkAuthContainer({ const appEvents = useAppEvents(); const { recordAuthMethod } = useLastAuthMethod(); + const captchaLoading = !captcha.isReady; + const form = useForm({ resolver: zodResolver( z.object({ @@ -131,13 +133,18 @@ export function MagicLinkAuthContainer({ - diff --git a/packages/features/auth/src/components/password-reset-request-container.tsx b/packages/features/auth/src/components/password-reset-request-container.tsx index 0708adc71..b90f878d9 100644 --- a/packages/features/auth/src/components/password-reset-request-container.tsx +++ b/packages/features/auth/src/components/password-reset-request-container.tsx @@ -34,6 +34,7 @@ export function PasswordResetRequestContainer(params: { const { t } = useTranslation('auth'); const resetPasswordMutation = useRequestResetPassword(); const captcha = useCaptcha({ siteKey: params.captchaSiteKey }); + const captchaLoading = !captcha.isReady; const error = resetPasswordMutation.error; const success = resetPasswordMutation.data; @@ -101,8 +102,16 @@ export function PasswordResetRequestContainer(params: { )} /> - {captcha.field} diff --git a/packages/features/auth/src/components/password-sign-in-container.tsx b/packages/features/auth/src/components/password-sign-in-container.tsx index d13676ec7..4ca46ba66 100644 --- a/packages/features/auth/src/components/password-sign-in-container.tsx +++ b/packages/features/auth/src/components/password-sign-in-container.tsx @@ -24,6 +24,7 @@ export function PasswordSignInContainer({ const { recordAuthMethod } = useLastAuthMethod(); const isLoading = signInMutation.isPending; const isRedirecting = signInMutation.isSuccess; + const captchaLoading = !captcha.isReady; const onSubmit = useCallback( async (credentials: z.infer) => { @@ -59,6 +60,7 @@ export function PasswordSignInContainer({ onSubmit={onSubmit} loading={isLoading} redirecting={isRedirecting} + captchaLoading={captchaLoading} /> {captcha.field} diff --git a/packages/features/auth/src/components/password-sign-in-form.tsx b/packages/features/auth/src/components/password-sign-in-form.tsx index 4276f58c5..15506bc89 100644 --- a/packages/features/auth/src/components/password-sign-in-form.tsx +++ b/packages/features/auth/src/components/password-sign-in-form.tsx @@ -29,10 +29,12 @@ import { PasswordInput } from './password-input'; export function PasswordSignInForm({ onSubmit, + captchaLoading = false, loading = false, redirecting = false, }: { onSubmit: (params: z.infer) => unknown; + captchaLoading: boolean; loading: boolean; redirecting: boolean; }) { @@ -126,6 +128,12 @@ export function PasswordSignInForm({ + + + + + + diff --git a/packages/features/auth/src/components/password-sign-up-container.tsx b/packages/features/auth/src/components/password-sign-up-container.tsx index 3b0aecd6a..a0c93564a 100644 --- a/packages/features/auth/src/components/password-sign-up-container.tsx +++ b/packages/features/auth/src/components/password-sign-up-container.tsx @@ -29,6 +29,7 @@ export function EmailPasswordSignUpContainer({ captchaSiteKey, }: EmailPasswordSignUpContainerProps) { const captcha = useCaptcha({ siteKey: captchaSiteKey }); + const captchaLoading = !captcha.isReady; const { signUp: onSignupRequested, @@ -57,6 +58,7 @@ export function EmailPasswordSignUpContainer({ loading={loading} defaultValues={defaultValues} displayTermsCheckbox={displayTermsCheckbox} + captchaLoading={captchaLoading} /> {captcha.field} diff --git a/packages/features/auth/src/components/password-sign-up-form.tsx b/packages/features/auth/src/components/password-sign-up-form.tsx index 38ecb1819..069e2ecef 100644 --- a/packages/features/auth/src/components/password-sign-up-form.tsx +++ b/packages/features/auth/src/components/password-sign-up-form.tsx @@ -33,7 +33,9 @@ interface PasswordSignUpFormProps { password: string; repeatPassword: string; }) => unknown; + loading: boolean; + captchaLoading: boolean; } export function PasswordSignUpForm({ @@ -41,6 +43,7 @@ export function PasswordSignUpForm({ displayTermsCheckbox, onSubmit, loading, + captchaLoading, }: PasswordSignUpFormProps) { const form = useForm({ resolver: zodResolver(PasswordSignUpSchema), @@ -116,24 +119,27 @@ export function PasswordSignUpForm({ data-test={'auth-submit-button'} className={'w-full'} type="submit" - disabled={loading} + disabled={loading || captchaLoading} > - - + + + - - - } - > + + + + <> + + + + + diff --git a/packages/features/auth/src/components/resend-auth-link-form.tsx b/packages/features/auth/src/components/resend-auth-link-form.tsx index 957d9578c..c45b3153a 100644 --- a/packages/features/auth/src/components/resend-auth-link-form.tsx +++ b/packages/features/auth/src/components/resend-auth-link-form.tsx @@ -15,6 +15,7 @@ import { FormItem, FormMessage, } from '@kit/ui/form'; +import { If } from '@kit/ui/if'; import { Trans } from '@kit/ui/trans'; import { useCaptcha } from '../captcha/client'; @@ -26,6 +27,7 @@ export function ResendAuthLinkForm(props: { }) { const captcha = useCaptcha({ siteKey: props.captchaSiteKey }); const resendLink = useResendLink(captcha.token); + const captchaLoading = !captcha.isReady; const form = useForm({ resolver: zodResolver(z.object({ email: z.string().email() })), @@ -83,7 +85,15 @@ export function ResendAuthLinkForm(props: { }} /> -