diff --git a/web/sdk/client/components/auth-oidc-button/auth-oidc-button.tsx b/web/sdk/client/components/auth-oidc-button/auth-oidc-button.tsx
index 94ef6463b..b84534f41 100644
--- a/web/sdk/client/components/auth-oidc-button/auth-oidc-button.tsx
+++ b/web/sdk/client/components/auth-oidc-button/auth-oidc-button.tsx
@@ -2,6 +2,7 @@ import { Button } from '@raystack/apsara';
import { ComponentProps } from 'react';
import GoogleLogo from '~/client/assets/logos/google-logo.svg';
import { capitalize } from '~/utils';
+import { DisabledTooltip } from '../disabled-tooltip';
import styles from './auth-oidc-button.module.css';
const oidcLogoMap = new Map([['google', GoogleLogo]]);
@@ -11,32 +12,36 @@ export type AuthOIDCButtonProps = Omit<
'variant' | 'color' | 'className' | 'leadingIcon'
> & {
provider: string;
+ disabledMessage?: string;
};
export const AuthOIDCButton = ({
onClick,
provider,
disabled,
+ disabledMessage,
children = `Continue with ${capitalize(provider)}`,
...props
}: AuthOIDCButtonProps) => (
-
- ) : null
- }
- >
- {children}
-
+
+
+ ) : null
+ }
+ >
+ {children}
+
+
);
diff --git a/web/sdk/client/components/disabled-tooltip/disabled-tooltip.module.css b/web/sdk/client/components/disabled-tooltip/disabled-tooltip.module.css
new file mode 100644
index 000000000..8a53d8bd6
--- /dev/null
+++ b/web/sdk/client/components/disabled-tooltip/disabled-tooltip.module.css
@@ -0,0 +1,4 @@
+.trigger {
+ display: flex;
+ width: 100%;
+}
diff --git a/web/sdk/client/components/disabled-tooltip/disabled-tooltip.tsx b/web/sdk/client/components/disabled-tooltip/disabled-tooltip.tsx
new file mode 100644
index 000000000..6124ecab6
--- /dev/null
+++ b/web/sdk/client/components/disabled-tooltip/disabled-tooltip.tsx
@@ -0,0 +1,35 @@
+import { Tooltip } from '@raystack/apsara';
+import { ReactNode } from 'react';
+import styles from './disabled-tooltip.module.css';
+
+export type DisabledTooltipProps = {
+ disabled?: boolean;
+ message?: string;
+ children: ReactNode;
+};
+
+export const DisabledTooltip = ({
+ disabled = false,
+ message,
+ children
+}: DisabledTooltipProps) => {
+ const active = disabled && !!message;
+
+ if (!active) return children;
+
+ return (
+
+ }>
+ {children}
+
+
+ {message}
+
+
+ );
+};
diff --git a/web/sdk/client/components/disabled-tooltip/index.ts b/web/sdk/client/components/disabled-tooltip/index.ts
new file mode 100644
index 000000000..a87737b81
--- /dev/null
+++ b/web/sdk/client/components/disabled-tooltip/index.ts
@@ -0,0 +1,2 @@
+export { DisabledTooltip } from './disabled-tooltip';
+export type { DisabledTooltipProps } from './disabled-tooltip';
diff --git a/web/sdk/client/views/auth/magic-link/magic-link-view.tsx b/web/sdk/client/views/auth/magic-link/magic-link-view.tsx
index 0eba5cfaf..e2cf8ec7f 100644
--- a/web/sdk/client/views/auth/magic-link/magic-link-view.tsx
+++ b/web/sdk/client/views/auth/magic-link/magic-link-view.tsx
@@ -12,6 +12,7 @@ import {
type AuthContainerProps
} from '~/client/components/auth-container';
import { AuthHeader } from '~/client/components/auth-header';
+import { DisabledTooltip } from '~/client/components/disabled-tooltip';
import { describeAuthError } from '~/client/utils/auth-error';
import { MAIL_OTP_STRATEGY } from '~/client/utils/constants';
import styles from './magic-link-view.module.css';
@@ -25,6 +26,7 @@ export type MagicLinkViewProps = ComponentPropsWithRef<'div'> &
intent?: FlowIntent;
acceptedDocumentIds?: string[];
disabled?: boolean;
+ disabledMessage?: string;
onActivate?: () => void;
};
@@ -51,6 +53,7 @@ export const MagicLinkView = ({
intent = FlowIntent.UNSPECIFIED,
acceptedDocumentIds,
disabled = false,
+ disabledMessage,
onActivate,
...props
}: MagicLinkViewProps) => {
@@ -102,19 +105,21 @@ export const MagicLinkView = ({
const email = watch('email', '');
const formContent = !visible ? (
-
+
+
+
) : (
-
+
+
+
);
diff --git a/web/sdk/client/views/auth/sign-in/sign-in-view.tsx b/web/sdk/client/views/auth/sign-in/sign-in-view.tsx
index 50ab49015..935452782 100644
--- a/web/sdk/client/views/auth/sign-in/sign-in-view.tsx
+++ b/web/sdk/client/views/auth/sign-in/sign-in-view.tsx
@@ -24,6 +24,8 @@ export type SignInViewProps = ComponentPropsWithRef<'div'> &
title?: string;
excludes?: string[];
footer?: boolean;
+ /** Send no flow intent, so the server falls back to create-or-get. */
+ disableIntent?: boolean;
error?: AuthRejection;
};
@@ -32,6 +34,7 @@ export const SignInView = ({
title = 'Login to Raystack',
excludes = [],
footer = true,
+ disableIntent = false,
error,
...props
}: SignInViewProps) => {
@@ -52,6 +55,8 @@ export const SignInView = ({
FrontierServiceQueries.authenticate
);
+ const intent = disableIntent ? FlowIntent.UNSPECIFIED : FlowIntent.LOGIN;
+
const clearError = useCallback(() => setAuthError(null), []);
const clickHandler = useCallback(
@@ -61,7 +66,7 @@ export const SignInView = ({
const response = await authenticate({
strategyName: name,
callbackUrl: config.callbackUrl,
- flowIntent: FlowIntent.LOGIN
+ flowIntent: intent
});
if (response.endpoint) {
window.location.href = response.endpoint;
@@ -73,7 +78,7 @@ export const SignInView = ({
});
}
},
- [authenticate, config, clearError]
+ [authenticate, config, intent, clearError]
);
const isUnknownError =
@@ -91,7 +96,7 @@ export const SignInView = ({
) : (
diff --git a/web/sdk/client/views/auth/sign-up/sign-up-view.tsx b/web/sdk/client/views/auth/sign-up/sign-up-view.tsx
index cbef43369..11e410620 100644
--- a/web/sdk/client/views/auth/sign-up/sign-up-view.tsx
+++ b/web/sdk/client/views/auth/sign-up/sign-up-view.tsx
@@ -27,6 +27,7 @@ import styles from './sign-up-view.module.css';
const CONSENT_UNAVAILABLE_MESSAGE =
'The documents required to sign up could not be loaded. Please refresh the page.';
+const CONSENT_REQUIRED_TOOLTIP = 'You must agree to continue';
export type SignUpViewProps = ComponentPropsWithRef<'div'> &
AuthContainerProps & {
@@ -34,6 +35,10 @@ export type SignUpViewProps = ComponentPropsWithRef<'div'> &
title?: string;
excludes?: string[];
consentLabel?: ConsentLabel;
+ /** Send no flow intent, so the server falls back to create-or-get. */
+ disableIntent?: boolean;
+ /** Tooltip shown on the disabled sign-up buttons until consent is given. */
+ disabledContentMessage?: string;
error?: AuthRejection;
};
@@ -42,6 +47,8 @@ export const SignUpView = ({
title = 'Create your account',
excludes = [],
consentLabel,
+ disableIntent = false,
+ disabledContentMessage = CONSENT_REQUIRED_TOOLTIP,
error,
...props
}: SignUpViewProps) => {
@@ -84,6 +91,8 @@ export const SignUpView = ({
const blocked =
consentPending || consentFailed || (documents.length > 0 && !consented);
+ const intent = disableIntent ? FlowIntent.UNSPECIFIED : FlowIntent.SIGNUP;
+
const clearError = useCallback(() => setAuthError(null), []);
const clickHandler = useCallback(
@@ -93,7 +102,7 @@ export const SignUpView = ({
const response = await authenticate({
strategyName: name,
callbackUrl: config.callbackUrl,
- flowIntent: FlowIntent.SIGNUP,
+ flowIntent: intent,
acceptedDocumentIds
});
if (response.endpoint) {
@@ -106,7 +115,7 @@ export const SignUpView = ({
});
}
},
- [authenticate, config, acceptedDocumentIds, clearError]
+ [authenticate, config, intent, acceptedDocumentIds, clearError]
);
const isUnknownError =
@@ -128,9 +137,10 @@ export const SignUpView = ({
) : (
@@ -144,6 +154,7 @@ export const SignUpView = ({
onClick={() => clickHandler(s.name)}
provider={s.name}
disabled={blocked}
+ disabledMessage={disabledContentMessage}
data-test-id="frontier-sdk-signup-page-oidc-btn"
/>