Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 24 additions & 19 deletions web/sdk/client/components/auth-oidc-button/auth-oidc-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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]]);
Expand All @@ -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) => (
<Button
variant="outline"
color="neutral"
className={styles.button}
onClick={onClick}
disabled={disabled}
data-test-id="frontier-sdk-oidc-logo-btn"
{...props}
leadingIcon={
oidcLogoMap.has(provider) ? (
<img
src={oidcLogoMap.get(provider) as unknown as string}
alt={provider + '-logo'}
/>
) : null
}
>
{children}
</Button>
<DisabledTooltip disabled={disabled} message={disabledMessage}>
<Button
variant="outline"
color="neutral"
className={styles.button}
onClick={onClick}
disabled={disabled}
data-test-id="frontier-sdk-oidc-logo-btn"
{...props}
leadingIcon={
oidcLogoMap.has(provider) ? (
<img
src={oidcLogoMap.get(provider) as unknown as string}
alt={provider + '-logo'}
/>
) : null
}
>
{children}
</Button>
</DisabledTooltip>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.trigger {
display: flex;
width: 100%;
}
35 changes: 35 additions & 0 deletions web/sdk/client/components/disabled-tooltip/disabled-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Tooltip>
<Tooltip.Trigger render={<span className={styles.trigger} />}>
Comment thread
rohanchkrabrty marked this conversation as resolved.
{children}
</Tooltip.Trigger>
<Tooltip.Content
side="right"
align="start"
sideOffset={-40}
alignOffset={-10}
Comment thread
rohanchkrabrty marked this conversation as resolved.
>
{message}
</Tooltip.Content>
</Tooltip>
);
};
2 changes: 2 additions & 0 deletions web/sdk/client/components/disabled-tooltip/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { DisabledTooltip } from './disabled-tooltip';
export type { DisabledTooltipProps } from './disabled-tooltip';
54 changes: 30 additions & 24 deletions web/sdk/client/views/auth/magic-link/magic-link-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -25,6 +26,7 @@ export type MagicLinkViewProps = ComponentPropsWithRef<'div'> &
intent?: FlowIntent;
acceptedDocumentIds?: string[];
disabled?: boolean;
disabledMessage?: string;
onActivate?: () => void;
};

Expand All @@ -51,6 +53,7 @@ export const MagicLinkView = ({
intent = FlowIntent.UNSPECIFIED,
acceptedDocumentIds,
disabled = false,
disabledMessage,
onActivate,
...props
}: MagicLinkViewProps) => {
Expand Down Expand Up @@ -102,19 +105,21 @@ export const MagicLinkView = ({
const email = watch('email', '');

const formContent = !visible ? (
<Button
variant="outline"
color="neutral"
className={styles.button}
onClick={() => {
setVisible(true);
onActivate?.();
}}
disabled={disabled}
data-test-id="frontier-sdk-mail-otp-login-btn"
>
Continue with Email
</Button>
<DisabledTooltip disabled={disabled} message={disabledMessage}>
<Button
variant="outline"
color="neutral"
className={styles.button}
onClick={() => {
setVisible(true);
onActivate?.();
}}
disabled={disabled}
data-test-id="frontier-sdk-mail-otp-login-btn"
>
Continue with Email
</Button>
</DisabledTooltip>
) : (
<form
noValidate
Expand All @@ -127,19 +132,20 @@ export const MagicLinkView = ({
{...register('email')}
size="large"
placeholder="name@example.com"
disabled={disabled}
/>
</Field>
<Button
className={styles.button}
disabled={!email || disabled}
type="submit"
loading={isPending}
loaderText="Loading..."
data-test-id="frontier-sdk-mail-otp-login-submit-btn"
>
Continue with Email
</Button>
<DisabledTooltip disabled={disabled} message={disabledMessage}>
<Button
className={styles.button}
disabled={!email || disabled}
type="submit"
loading={isPending}
loaderText="Loading..."
data-test-id="frontier-sdk-mail-otp-login-submit-btn"
>
Continue with Email
</Button>
</DisabledTooltip>
</form>
);

Expand Down
11 changes: 8 additions & 3 deletions web/sdk/client/views/auth/sign-in/sign-in-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -32,6 +34,7 @@ export const SignInView = ({
title = 'Login to Raystack',
excludes = [],
footer = true,
disableIntent = false,
error,
...props
}: SignInViewProps) => {
Expand All @@ -52,6 +55,8 @@ export const SignInView = ({
FrontierServiceQueries.authenticate
);

const intent = disableIntent ? FlowIntent.UNSPECIFIED : FlowIntent.LOGIN;

const clearError = useCallback(() => setAuthError(null), []);

const clickHandler = useCallback(
Expand All @@ -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;
Expand All @@ -73,7 +78,7 @@ export const SignInView = ({
});
}
},
[authenticate, config, clearError]
[authenticate, config, intent, clearError]
);

const isUnknownError =
Expand All @@ -91,7 +96,7 @@ export const SignInView = ({
<MagicLinkView
key={s.name}
inline
intent={FlowIntent.LOGIN}
intent={intent}
onActivate={clearError}
/>
) : (
Expand Down
17 changes: 14 additions & 3 deletions web/sdk/client/views/auth/sign-up/sign-up-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ 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 & {
logo?: ReactNode;
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;
};

Expand All @@ -42,6 +47,8 @@ export const SignUpView = ({
title = 'Create your account',
excludes = [],
consentLabel,
disableIntent = false,
disabledContentMessage = CONSENT_REQUIRED_TOOLTIP,
error,
...props
}: SignUpViewProps) => {
Expand Down Expand Up @@ -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(
Expand All @@ -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) {
Expand All @@ -106,7 +115,7 @@ export const SignUpView = ({
});
}
},
[authenticate, config, acceptedDocumentIds, clearError]
[authenticate, config, intent, acceptedDocumentIds, clearError]
);

const isUnknownError =
Expand All @@ -128,9 +137,10 @@ export const SignUpView = ({
<MagicLinkView
key={s.name}
inline
intent={FlowIntent.SIGNUP}
intent={intent}
acceptedDocumentIds={acceptedDocumentIds}
disabled={blocked}
disabledMessage={disabledContentMessage}
onActivate={clearError}
/>
) : (
Expand All @@ -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"
/>
</Field>
Expand Down
Loading