Revert "[web] auth: add sign up reminder card (#1582)"
This reverts commit 28da8b950a.
This commit is contained in:
parent
3cdfa2f16a
commit
5697dfd7ee
|
|
@ -1,5 +1,4 @@
|
|||
import AuthGoogleOneTap from '~/components/auth/AuthGoogleOneTap';
|
||||
import AuthOneClickSignup from '~/components/auth/AuthOneClickSignUp';
|
||||
|
||||
type Props = Readonly<{
|
||||
children: React.ReactNode;
|
||||
|
|
@ -15,7 +14,6 @@ export default function InterviewsLayout({ children }: Props) {
|
|||
return (
|
||||
<>
|
||||
{children}
|
||||
<AuthOneClickSignup />
|
||||
<AuthGoogleOneTap showOnMobileOnly={true} />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import AuthOneClickSignup from '~/components/auth/AuthOneClickSignUp';
|
||||
import BlogSidebarContainer from '~/components/blog/layout/BlogSidebarContainer';
|
||||
import { GlobalBannerInterviews } from '~/components/global/banners/GlobalBannerInterviews';
|
||||
import InterviewsFooter from '~/components/interviews/common/InterviewsFooter';
|
||||
|
|
@ -18,7 +17,6 @@ export default function BlogLayout({ children }: Props) {
|
|||
return (
|
||||
<>
|
||||
<GlobalBannerInterviews />
|
||||
<AuthOneClickSignup />
|
||||
<div className="flex flex-col">
|
||||
<InterviewsNavbar />
|
||||
<div className="flex">
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useSessionContext } from '@supabase/auth-helpers-react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useSessionStorage } from 'usehooks-ts';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
|
||||
import { useToast } from '~/components/global/toasts/useToast';
|
||||
|
||||
import { useI18nPathname } from '~/next-i18nostic/src';
|
||||
|
||||
import AuthOneClickSignupCard from './AuthOneClickSignupCard';
|
||||
|
||||
const SIGN_UP_TOAST_DELAY = 15_000;
|
||||
const TOAST_DURATION = 60 * 60 * 1000; // 1 hour
|
||||
|
||||
export default function AuthOneClickSignup() {
|
||||
const isMobile = useMediaQuery('(max-width: 640px)');
|
||||
const { pathname } = useI18nPathname();
|
||||
const lastToastId = useRef<string | null>(null);
|
||||
const { dismissToast, showToast } = useToast();
|
||||
|
||||
const { isLoading: isUserLoading, session } = useSessionContext();
|
||||
const [dismissedSignUpPrompt, setDismissedSignUpPrompt] =
|
||||
useSessionStorage<boolean>('gfe:auth:sign-up-prompt', false);
|
||||
|
||||
// Don't show it on homepage
|
||||
const isHomepage = pathname === '/' || pathname === '/projects';
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setDismissedSignUpPrompt(true);
|
||||
}, [setDismissedSignUpPrompt]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
session ||
|
||||
isUserLoading ||
|
||||
dismissedSignUpPrompt ||
|
||||
isHomepage ||
|
||||
isMobile
|
||||
) {
|
||||
if (lastToastId.current) {
|
||||
dismissToast(lastToastId.current);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Show popup after delay
|
||||
const timer = setTimeout(() => {
|
||||
const { id } = showToast({
|
||||
animateFrom: 'bottom',
|
||||
customComponent: () => <AuthOneClickSignupCard onClose={handleClose} />,
|
||||
duration: TOAST_DURATION,
|
||||
side: 'end',
|
||||
variant: 'custom',
|
||||
});
|
||||
|
||||
lastToastId.current = id;
|
||||
}, SIGN_UP_TOAST_DELAY);
|
||||
|
||||
return () => {
|
||||
if (lastToastId.current) {
|
||||
dismissToast(lastToastId.current);
|
||||
}
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [
|
||||
session,
|
||||
isUserLoading,
|
||||
dismissedSignUpPrompt,
|
||||
isHomepage,
|
||||
showToast,
|
||||
handleClose,
|
||||
dismissToast,
|
||||
isMobile,
|
||||
]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
import clsx from 'clsx';
|
||||
import { useId } from 'react';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import { RiCloseLine, RiGithubFill, RiMailLine } from 'react-icons/ri';
|
||||
|
||||
import { useAuthSignInUp } from '~/hooks/user/useAuthFns';
|
||||
|
||||
import { useToast } from '~/components/global/toasts/useToast';
|
||||
import { useIntl } from '~/components/intl';
|
||||
import Button from '~/components/ui/Button';
|
||||
import Text from '~/components/ui/Text';
|
||||
import {
|
||||
themeTextFaintColor,
|
||||
themeTextInvertColor,
|
||||
} from '~/components/ui/theme';
|
||||
|
||||
import { useI18nPathname } from '~/next-i18nostic/src';
|
||||
import { mergeURLWithCurrentParamsHash } from '~/utils/merge-url-params-hash';
|
||||
|
||||
import { useOAuthSignIn } from './useOAuthSignIn';
|
||||
|
||||
type Props = Readonly<{
|
||||
onClose?: () => void;
|
||||
}>;
|
||||
|
||||
export default function AuthOneClickSignupCard({ onClose }: Props) {
|
||||
const intl = useIntl();
|
||||
const descriptionId = useId();
|
||||
const titleId = useId();
|
||||
const { pathname } = useI18nPathname();
|
||||
const { signInUpHref } = useAuthSignInUp();
|
||||
const { showToast } = useToast();
|
||||
|
||||
const { loading, signInWithProvider } = useOAuthSignIn({
|
||||
next: mergeURLWithCurrentParamsHash(pathname ?? ''),
|
||||
onError: (errorMessage) => {
|
||||
showToast({
|
||||
title:
|
||||
errorMessage ||
|
||||
intl.formatMessage({
|
||||
defaultMessage: 'Something went wrong',
|
||||
description: 'Error message',
|
||||
id: 'sbXDK4',
|
||||
}),
|
||||
variant: 'danger',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
aria-describedby={descriptionId}
|
||||
aria-labelledby={titleId}
|
||||
aria-modal="true"
|
||||
className={clsx(
|
||||
'w-full max-w-[294px]',
|
||||
'rounded-lg',
|
||||
'bg-neutral-800 dark:bg-white',
|
||||
'border border-neutral-700 dark:border-neutral-200',
|
||||
'px-4 pb-3 pt-4',
|
||||
)}
|
||||
role="dialog">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<Text color="invert" id={titleId} size="body1" weight="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: 'Join GreatFrontEnd in 1 click',
|
||||
description: 'Auth card title',
|
||||
id: 'Lsk0wX',
|
||||
})}
|
||||
</Text>
|
||||
<Button
|
||||
className="group/button transition-all"
|
||||
icon={RiCloseLine}
|
||||
iconClassName={clsx(
|
||||
themeTextInvertColor,
|
||||
'group-hover/button:text-neutral-900 dark:group-hover/button:text-white',
|
||||
)}
|
||||
isLabelHidden={true}
|
||||
label="Close"
|
||||
size="xs"
|
||||
variant="tertiary"
|
||||
onClick={onClose}
|
||||
/>
|
||||
</div>
|
||||
<Text
|
||||
className="mb-4 mt-3 block"
|
||||
color="invert"
|
||||
id={descriptionId}
|
||||
size="body3">
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
'The place for front end engineers. Upskill, ace interviews, get inspired.',
|
||||
description: 'Auth card description',
|
||||
id: 'n1m6Nx',
|
||||
})}
|
||||
</Text>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<Button
|
||||
display="block"
|
||||
icon={FcGoogle}
|
||||
isDisabled={loading}
|
||||
isLoading={loading}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: 'Sign up with',
|
||||
description: 'Auth card button label',
|
||||
id: 'z9Ymn4',
|
||||
})}
|
||||
variant="secondary"
|
||||
onClick={() => signInWithProvider('google')}
|
||||
/>
|
||||
<Button
|
||||
className="group/button transition-all"
|
||||
icon={RiGithubFill}
|
||||
iconClassName={clsx(
|
||||
themeTextInvertColor,
|
||||
'group-hover/button:text-neutral-900 dark:group-hover/button:text-white',
|
||||
)}
|
||||
isLabelHidden={true}
|
||||
isLoading={loading}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: 'Sign up with Github',
|
||||
description: 'Auth card button label',
|
||||
id: 'iwMZfR',
|
||||
})}
|
||||
variant="tertiary"
|
||||
onClick={() => signInWithProvider('github')}
|
||||
/>
|
||||
<Text className={themeTextFaintColor} color="inherit" size="body2">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: 'or',
|
||||
description: 'Label for or',
|
||||
id: 'ZEPn1r',
|
||||
})}
|
||||
</Text>
|
||||
<Button
|
||||
className="group/button transition-all"
|
||||
href={signInUpHref({
|
||||
query: {
|
||||
view: 'email',
|
||||
},
|
||||
})}
|
||||
icon={RiMailLine}
|
||||
iconClassName={clsx(
|
||||
themeTextInvertColor,
|
||||
'group-hover/button:text-neutral-900 dark:group-hover/button:text-white',
|
||||
)}
|
||||
isDisabled={loading}
|
||||
isLabelHidden={true}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: 'Sign up with email',
|
||||
description: 'Auth card button label',
|
||||
id: 'sr38Pg',
|
||||
})}
|
||||
variant="tertiary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -220,6 +220,7 @@ export default function SupabaseAuth({
|
|||
layout={socialLayout}
|
||||
next={next}
|
||||
providers={providers}
|
||||
supabaseClient={supabaseClient}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import type { Provider } from '@supabase/supabase-js';
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
import { RiGithubFill, RiGoogleFill } from 'react-icons/ri';
|
||||
import url from 'url';
|
||||
|
||||
import { useIntl } from '~/components/intl';
|
||||
import Button from '~/components/ui/Button';
|
||||
|
||||
import logEvent from '~/logging/logEvent';
|
||||
import type { SupabaseClientGFE } from '~/supabase/SupabaseServerGFE';
|
||||
|
||||
import Alert from '../ui/Alert';
|
||||
import { useOAuthSignIn } from './useOAuthSignIn';
|
||||
|
||||
export type SupabaseProviderGFE = 'github' | 'google';
|
||||
|
||||
|
|
@ -41,17 +43,49 @@ export type SocialAuthProps = {
|
|||
layout?: 'horizontal' | 'vertical';
|
||||
next: string;
|
||||
providers?: Array<SupabaseProviderGFE>;
|
||||
supabaseClient: SupabaseClientGFE;
|
||||
};
|
||||
|
||||
export default function SupabaseAuthSocial({
|
||||
layout,
|
||||
next,
|
||||
providers,
|
||||
supabaseClient,
|
||||
}: SocialAuthProps) {
|
||||
const intl = useIntl();
|
||||
const { errorMessage, loading, signInWithProvider } = useOAuthSignIn({
|
||||
next,
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
async function handleProviderSignIn(provider: SupabaseProviderGFE) {
|
||||
setLoading(true);
|
||||
|
||||
const redirectTo =
|
||||
window.location.origin +
|
||||
url.format({
|
||||
pathname: '/auth/login-redirect',
|
||||
query: {
|
||||
next,
|
||||
},
|
||||
});
|
||||
|
||||
const { error } = await supabaseClient.auth.signInWithOAuth({
|
||||
options: { redirectTo },
|
||||
provider,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
setErrorMessage(error.message);
|
||||
logEvent('auth.sign_in.fail', {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
namespace: 'auth',
|
||||
stack: error.stack,
|
||||
type: provider,
|
||||
});
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
if (!providers || providers.length === 0) {
|
||||
return null;
|
||||
|
|
@ -97,7 +131,7 @@ export default function SupabaseAuthSocial({
|
|||
label,
|
||||
namespace: 'auth',
|
||||
});
|
||||
signInWithProvider(provider);
|
||||
handleProviderSignIn(provider);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
import { useState } from 'react';
|
||||
import url from 'url';
|
||||
|
||||
import logEvent from '~/logging/logEvent';
|
||||
import { i18nHref, useI18n } from '~/next-i18nostic/src';
|
||||
import { useSupabaseClientGFE } from '~/supabase/SupabaseClientGFE';
|
||||
|
||||
import type { SupabaseProviderGFE } from './SupabaseAuthSocial';
|
||||
|
||||
export function useOAuthSignIn(opts?: {
|
||||
next?: string;
|
||||
onError?: (errorMessage: string) => void;
|
||||
}) {
|
||||
const supabaseClient = useSupabaseClientGFE();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const { locale } = useI18n();
|
||||
|
||||
async function signInWithProvider(provider: SupabaseProviderGFE) {
|
||||
setLoading(true);
|
||||
|
||||
const redirectTo =
|
||||
window.location.origin +
|
||||
url.format(
|
||||
i18nHref(
|
||||
{
|
||||
pathname: '/auth/login-redirect',
|
||||
query: {
|
||||
next: opts?.next || window.location.pathname,
|
||||
},
|
||||
},
|
||||
locale,
|
||||
),
|
||||
);
|
||||
|
||||
const { error } = await supabaseClient.auth.signInWithOAuth({
|
||||
options: { redirectTo },
|
||||
provider,
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
|
||||
if (error) {
|
||||
setErrorMessage(error.message);
|
||||
opts?.onError?.(error.message);
|
||||
|
||||
logEvent('auth.sign_in.fail', {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
namespace: 'auth',
|
||||
stack: error.stack,
|
||||
type: provider,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
errorMessage,
|
||||
loading,
|
||||
signInWithProvider,
|
||||
};
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
import { useEffect } from 'react';
|
||||
|
||||
import AuthGoogleOneTap from '~/components/auth/AuthGoogleOneTap';
|
||||
import AuthOneClickSignup from '~/components/auth/AuthOneClickSignUp';
|
||||
import { ProductThemeScript } from '~/components/global/product-theme/ProductThemeScript';
|
||||
import { useProductMenuUnseenIndicator } from '~/components/global/product-theme/useProductMenuUnseenIndicator';
|
||||
|
||||
|
|
@ -26,7 +25,6 @@ export default function ProjectsRootLayout({ children }: Props) {
|
|||
<>
|
||||
<ProductThemeScript theme="projects" />
|
||||
<AuthGoogleOneTap showOnMobileOnly={true} />
|
||||
<AuthOneClickSignup />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -193,14 +193,10 @@ export const ToastImpl = React.forwardRef<
|
|||
'data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)]',
|
||||
'data-[swipe=move]:transition-none',
|
||||
'data-[state=open]:animate-in',
|
||||
props.animateFrom === 'left'
|
||||
? 'data-[state=open]:sm:slide-in-from-left-full'
|
||||
: 'data-[state=open]:sm:slide-in-from-bottom-full',
|
||||
'data-[state=open]:sm:slide-in-from-left-full',
|
||||
'data-[state=closed]:animate-out',
|
||||
'data-[state=closed]:fade-out-80',
|
||||
props.animateFrom === 'left'
|
||||
? 'data-[state=closed]:slide-out-to-left-full'
|
||||
: 'data-[state=closed]:slide-out-to-bottom-full',
|
||||
'data-[state=closed]:slide-out-to-left-full',
|
||||
'flex',
|
||||
props.side === 'start' && 'self-start',
|
||||
props.side === 'end' && 'self-end justify-end',
|
||||
|
|
@ -210,7 +206,7 @@ export const ToastImpl = React.forwardRef<
|
|||
const { customComponent: Component, ...remainingProps } = props;
|
||||
|
||||
return (
|
||||
<li ref={ref} {...remainingProps} className={commonClass}>
|
||||
<li ref={ref} className={commonClass} {...remainingProps}>
|
||||
<Component />
|
||||
</li>
|
||||
);
|
||||
|
|
@ -315,7 +311,7 @@ type BaseToastProps = Omit<
|
|||
React.ComponentPropsWithoutRef<typeof ToastPrimitive.Root>,
|
||||
'children' | 'title'
|
||||
> &
|
||||
Readonly<{ animateFrom?: 'bottom' | 'left'; side?: 'end' | 'start' }>;
|
||||
Readonly<{ side?: 'end' | 'start' }>;
|
||||
|
||||
export type DefaultToastProps = BaseToastProps & DefaultProps;
|
||||
|
||||
|
|
@ -328,24 +324,11 @@ const Toast = React.forwardRef<
|
|||
ToastProps
|
||||
>((props, ref) => {
|
||||
if (props.variant === 'custom') {
|
||||
const {
|
||||
animateFrom = 'left',
|
||||
className,
|
||||
customComponent,
|
||||
side,
|
||||
variant,
|
||||
...remainingProps
|
||||
} = props;
|
||||
const { customComponent, variant, ...remainingProps } = props;
|
||||
|
||||
return (
|
||||
<ToastPrimitive.Root ref={ref} asChild={true} {...remainingProps}>
|
||||
<ToastImpl
|
||||
animateFrom={animateFrom}
|
||||
className={className}
|
||||
customComponent={customComponent}
|
||||
side={side}
|
||||
variant={variant}
|
||||
/>
|
||||
<ToastImpl customComponent={customComponent} variant={variant} />
|
||||
</ToastPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
|
@ -353,7 +336,6 @@ const Toast = React.forwardRef<
|
|||
const {
|
||||
addOnIcon,
|
||||
addOnLabel,
|
||||
animateFrom = 'left',
|
||||
className,
|
||||
description,
|
||||
icon,
|
||||
|
|
@ -370,7 +352,6 @@ const Toast = React.forwardRef<
|
|||
<ToastImpl
|
||||
addOnIcon={addOnIcon}
|
||||
addOnLabel={addOnLabel}
|
||||
animateFrom={animateFrom}
|
||||
className={className}
|
||||
description={description}
|
||||
icon={icon}
|
||||
|
|
|
|||
Loading…
Reference in New Issue