diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx
index c82076fa7..e877882d7 100644
--- a/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx
+++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/EmailVerificationSent.tsx
@@ -3,32 +3,83 @@ import styled from '@emotion/styled';
import { SubTitle } from '@/auth/components/SubTitle';
import { Title } from '@/auth/components/Title';
import { useHandleResendEmailVerificationToken } from '@/auth/sign-in-up/hooks/useHandleResendEmailVerificationToken';
-import { useTheme } from '@emotion/react';
-import { IconMail } from 'twenty-ui/display';
-import { Loader } from 'twenty-ui/feedback';
+import {
+ SignInUpStep,
+ signInUpStepState,
+} from '@/auth/states/signInUpStepState';
+import { OnboardingModalCircularIcon } from '@/onboarding/components/OnboardingModalCircularIcon';
+import { t } from '@lingui/core/macro';
+import { useSetRecoilState } from 'recoil';
+import {
+ IconGmail,
+ IconMail,
+ IconMailX,
+ IconMicrosoft,
+} from 'twenty-ui/display';
import { MainButton } from 'twenty-ui/input';
-import { RGBA } from 'twenty-ui/theme';
import { AnimatedEaseIn } from 'twenty-ui/utilities';
-const StyledMailContainer = styled.div`
- align-items: center;
+const StyledContainer = styled.div`
display: flex;
- justify-content: center;
- border: 2px solid ${(props) => props.color};
- border-radius: ${({ theme }) => theme.border.radius.rounded};
- box-shadow: ${(props) =>
- props.color && `-4px 4px 0 -2px ${RGBA(props.color, 1)}`};
- height: 36px;
- width: 36px;
- margin-bottom: ${({ theme }) => theme.spacing(4)};
+ flex-direction: column;
+ align-items: center;
+ gap: ${({ theme }) => theme.spacing(8)};
+ width: 100%;
+`;
+
+const StyledTextContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
`;
const StyledEmail = styled.span`
font-weight: ${({ theme }) => theme.font.weight.medium};
`;
-const StyledButtonContainer = styled.div`
- margin-top: ${({ theme }) => theme.spacing(8)};
+const StyledButtonsContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: ${({ theme }) => theme.spacing(3)};
+ width: 100%;
+ max-width: 240px;
+`;
+
+const StyledBottomLinks = styled.div`
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ gap: ${({ theme }) => theme.spacing(2)};
+ justify-content: center;
+`;
+
+const StyledLinkButton = styled.button`
+ background: none;
+ border: none;
+ font-family: ${({ theme }) => theme.font.family};
+ font-size: ${({ theme }) => theme.font.size.xs};
+ font-weight: ${({ theme }) => theme.font.weight.regular};
+ line-height: 140%;
+ color: ${({ theme }) => theme.font.color.tertiary};
+ cursor: pointer;
+
+ &:hover {
+ color: ${({ theme }) => theme.font.color.secondary};
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+`;
+
+const StyledDot = styled.div`
+ background: ${({ theme }) => theme.font.color.light};
+ border-radius: 50%;
+ height: 2px;
+ width: 2px;
`;
export const EmailVerificationSent = ({
@@ -38,46 +89,101 @@ export const EmailVerificationSent = ({
email: string | null;
isError?: boolean;
}) => {
- const theme = useTheme();
- const color =
- theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10;
+ const setSignInUpStep = useSetRecoilState(signInUpStepState);
const { handleResendEmailVerificationToken, loading: isLoading } =
useHandleResendEmailVerificationToken();
- return (
+ const handleOpenGmail = () => {
+ const gmailUrl = email
+ ? `https://mail.google.com/mail/u/${email}/`
+ : 'https://mail.google.com/';
+ window.open(gmailUrl, '_blank');
+ };
+
+ const handleOpenOutlook = () => {
+ const outlookUrl = email
+ ? `https://outlook.live.com/mail/${email}/`
+ : 'https://outlook.live.com/';
+ window.open(outlookUrl, '_blank');
+ };
+
+ const handleChangeEmail = () => {
+ setSignInUpStep(SignInUpStep.Email);
+ };
+
+ const title = isError ? t`Email Verification Failed` : t`Check your Emails`;
+ const subtitle = isError
+ ? t`We encountered an issue verifying`
+ : t`A verification email has been sent to`;
+
+ const Icon = isError ? IconMailX : IconMail;
+
+ const mainButtons = isError ? (
<>
-
-
-
-
-
-
- {isError ? 'Email Verification Failed' : 'Confirm Your Email Address'}
-
-
- {isError ? (
- <>
- Oops! We encountered an issue verifying{' '}
- {email}. Please request a new
- verification email and try again.
- >
- ) : (
- <>
- A verification email has been sent to{' '}
- {email}. Please check your inbox and
- click the link in the email to activate your account.
- >
- )}
-
-
- (isLoading ? : undefined)}
- width={200}
- />
-
+
+
+ >
+ ) : (
+ <>
+
+
>
);
+
+ return (
+
+
+
+
+
+
+
+ {title}
+
+
+ {subtitle} {email}
+
+
+
+ {mainButtons}
+
+ {!isError && (
+
+
+ {isLoading ? t`Sending...` : t`Resend email`}
+
+
+
+ {t`Change email`}
+
+
+ )}
+
+ );
};
diff --git a/packages/twenty-front/src/modules/onboarding/components/OnboardingModalCircularIcon.tsx b/packages/twenty-front/src/modules/onboarding/components/OnboardingModalCircularIcon.tsx
new file mode 100644
index 000000000..c3673f676
--- /dev/null
+++ b/packages/twenty-front/src/modules/onboarding/components/OnboardingModalCircularIcon.tsx
@@ -0,0 +1,33 @@
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import { IconComponent } from 'twenty-ui/display';
+import { RGBA } from 'twenty-ui/theme';
+
+const StyledCheckContainer = styled.div<{ color: string }>`
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ border: 2px solid ${({ color }) => color};
+ border-radius: ${({ theme }) => theme.border.radius.rounded};
+ box-shadow: ${({ color }) => color && `-4px 4px 0 -2px ${RGBA(color, 1)}`};
+ height: 36px;
+ width: 36px;
+`;
+
+type OnboardingModalCircularIconProps = {
+ Icon: IconComponent;
+};
+
+export const OnboardingModalCircularIcon = ({
+ Icon,
+}: OnboardingModalCircularIconProps) => {
+ const theme = useTheme();
+ const color =
+ theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10;
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx
index fed4cc434..4b4e604aa 100644
--- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx
@@ -37,7 +37,7 @@ const StyledModalDiv = styled(motion.div)<{
z-index: ${RootStackingContextZIndices.RootModal}; // should be higher than Backdrop's z-index
width: ${({ isMobile, size, theme }) => {
- if (isMobile) return theme.modal.size.fullscreen;
+ if (isMobile) return theme.modal.size.fullscreen.width;
switch (size) {
case 'small':
return theme.modal.size.sm.width;
diff --git a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx
index 099ec1d8b..4847e2563 100644
--- a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx
+++ b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx
@@ -1,85 +1,86 @@
import { SubTitle } from '@/auth/components/SubTitle';
import { Title } from '@/auth/components/Title';
import { currentUserState } from '@/auth/states/currentUserState';
+import { OnboardingModalCircularIcon } from '@/onboarding/components/OnboardingModalCircularIcon';
import { AppPath } from '@/types/AppPath';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
-import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
+import { useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconCheck } from 'twenty-ui/display';
+import { Loader } from 'twenty-ui/feedback';
import { MainButton } from 'twenty-ui/input';
-import { RGBA } from 'twenty-ui/theme';
import { AnimatedEaseIn } from 'twenty-ui/utilities';
import { useGetCurrentUserLazyQuery } from '~/generated/graphql';
import { useNavigateApp } from '~/hooks/useNavigateApp';
-const StyledCheckContainer = styled.div`
- align-items: center;
- display: flex;
- justify-content: center;
- border: 2px solid ${(props) => props.color};
- border-radius: ${({ theme }) => theme.border.radius.rounded};
- box-shadow: ${(props) =>
- props.color && `-4px 4px 0 -2px ${RGBA(props.color, 1)}`};
- height: 36px;
- width: 36px;
- margin-bottom: ${({ theme }) => theme.spacing(4)};
+const StyledModalContent = styled(Modal.Content)`
+ gap: ${({ theme }) => theme.spacing(8)};
`;
-const StyledButtonContainer = styled.div`
- margin-top: ${({ theme }) => theme.spacing(8)};
+const StyledTitleContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
`;
export const PaymentSuccess = () => {
- const theme = useTheme();
const navigate = useNavigateApp();
const subscriptionStatus = useSubscriptionStatus();
const [getCurrentUser] = useGetCurrentUserLazyQuery();
const setCurrentUser = useSetRecoilState(currentUserState);
- const color =
- theme.name === 'light' ? theme.grayScale.gray90 : theme.grayScale.gray10;
-
+ const [isLoading, setIsLoading] = useState(false);
const navigateWithSubscriptionCheck = async () => {
- if (isDefined(subscriptionStatus)) {
- navigate(AppPath.CreateWorkspace);
- return;
+ if (isLoading) return;
+
+ setIsLoading(true);
+
+ try {
+ if (isDefined(subscriptionStatus)) {
+ navigate(AppPath.CreateWorkspace);
+ return;
+ }
+
+ const result = await getCurrentUser({ fetchPolicy: 'network-only' });
+ const currentUser = result.data?.currentUser;
+ const refreshedSubscriptionStatus =
+ currentUser?.currentWorkspace?.currentBillingSubscription?.status;
+
+ if (isDefined(currentUser) && isDefined(refreshedSubscriptionStatus)) {
+ setCurrentUser(currentUser);
+ navigate(AppPath.CreateWorkspace);
+ return;
+ }
+
+ throw new Error(
+ "We're waiting for a confirmation from our payment provider (Stripe).\n" +
+ 'Please try again in a few seconds, sorry.',
+ );
+ } catch (error) {
+ setIsLoading(false);
+ throw error;
}
-
- const result = await getCurrentUser({ fetchPolicy: 'network-only' });
- const currentUser = result.data?.currentUser;
- const refreshedSubscriptionStatus =
- currentUser?.currentWorkspace?.currentBillingSubscription?.status;
-
- if (isDefined(currentUser) && isDefined(refreshedSubscriptionStatus)) {
- setCurrentUser(currentUser);
- navigate(AppPath.CreateWorkspace);
- return;
- }
-
- throw new Error(
- "We're waiting for a confirmation from our payment provider (Stripe).\n" +
- 'Please try again in a few seconds, sorry.',
- );
};
return (
-
+
-
-
-
+
- All set!
- Your account has been activated.
-
-
-
-
+
+ All set!
+ Your account has been activated.
+
+ (isLoading ? : null)}
+ disabled={isLoading}
+ />
+
);
};
diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
index 600ae4887..00c4e65f5 100644
--- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
+++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts
@@ -4,18 +4,18 @@ export {
IconAlertCircle,
IconAlertTriangle,
IconApi,
- IconAppWindow,
IconApps,
+ IconAppWindow,
IconArchive,
IconArchiveOff,
IconArrowBackUp,
IconArrowDown,
IconArrowLeft,
IconArrowRight,
- IconArrowUp,
- IconArrowUpRight,
IconArrowsDiagonal,
IconArrowsVertical,
+ IconArrowUp,
+ IconArrowUpRight,
IconAt,
IconBaselineDensitySmall,
IconBell,
@@ -47,8 +47,8 @@ export {
IconChevronDown,
IconChevronLeft,
IconChevronRight,
- IconChevronUp,
IconChevronsRight,
+ IconChevronUp,
IconCircleDot,
IconCircleOff,
IconCirclePlus,
@@ -202,6 +202,7 @@ export {
IconLogout,
IconMail,
IconMailCog,
+ IconMailX,
IconMap,
IconMaximize,
IconMessage,
diff --git a/packages/twenty-ui/src/display/index.ts b/packages/twenty-ui/src/display/index.ts
index 907f1eac1..6318cf854 100644
--- a/packages/twenty-ui/src/display/index.ts
+++ b/packages/twenty-ui/src/display/index.ts
@@ -65,18 +65,18 @@ export {
IconAlertCircle,
IconAlertTriangle,
IconApi,
- IconAppWindow,
IconApps,
+ IconAppWindow,
IconArchive,
IconArchiveOff,
IconArrowBackUp,
IconArrowDown,
IconArrowLeft,
IconArrowRight,
- IconArrowUp,
- IconArrowUpRight,
IconArrowsDiagonal,
IconArrowsVertical,
+ IconArrowUp,
+ IconArrowUpRight,
IconAt,
IconBaselineDensitySmall,
IconBell,
@@ -108,8 +108,8 @@ export {
IconChevronDown,
IconChevronLeft,
IconChevronRight,
- IconChevronUp,
IconChevronsRight,
+ IconChevronUp,
IconCircleDot,
IconCircleOff,
IconCirclePlus,
@@ -263,6 +263,7 @@ export {
IconLogout,
IconMail,
IconMailCog,
+ IconMailX,
IconMap,
IconMaximize,
IconMessage,
diff --git a/packages/twenty-ui/src/theme/constants/Modal.ts b/packages/twenty-ui/src/theme/constants/Modal.ts
index 7b50624ca..823e5568c 100644
--- a/packages/twenty-ui/src/theme/constants/Modal.ts
+++ b/packages/twenty-ui/src/theme/constants/Modal.ts
@@ -16,6 +16,7 @@ export const MODAL: {
height: '800px',
},
fullscreen: {
+ width: '100dvw',
height: '100dvh',
},
},