Replace Terms & Conditions with Sign Up Link on Sign In #4502 (#4617)

* Replace Terms & Conditions with Sign Up Link on Sign In #4502

* terms replaced with signup link

* begin fix (incomplete / do not merge)

* Revert

* Introduce welcome page

* Update Twenty website

---------

Co-authored-by: Mamatha Yarramaneni <mamathayarramaneni@Mamathas-Macbook.local>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
karthik
2024-03-22 17:40:01 -04:00
committed by GitHub
parent 3ea8589c0d
commit 0315f35979
17 changed files with 39 additions and 58 deletions

View File

@ -57,8 +57,7 @@ export const App = () => {
<DefaultLayout> <DefaultLayout>
<Routes> <Routes>
<Route path={AppPath.Verify} element={<VerifyEffect />} /> <Route path={AppPath.Verify} element={<VerifyEffect />} />
<Route path={AppPath.SignIn} element={<SignInUp />} /> <Route path={AppPath.SignInUp} element={<SignInUp />} />
<Route path={AppPath.SignUp} element={<SignInUp />} />
<Route path={AppPath.Invite} element={<SignInUp />} /> <Route path={AppPath.Invite} element={<SignInUp />} />
<Route path={AppPath.ResetPassword} element={<PasswordReset />} /> <Route path={AppPath.ResetPassword} element={<PasswordReset />} />
<Route path={AppPath.CreateWorkspace} element={<CreateWorkspace />} /> <Route path={AppPath.CreateWorkspace} element={<CreateWorkspace />} />

View File

@ -57,8 +57,7 @@ export const PageChangeEffect = () => {
useEffect(() => { useEffect(() => {
const isMatchingOngoingUserCreationRoute = const isMatchingOngoingUserCreationRoute =
isMatchingLocation(AppPath.SignUp) || isMatchingLocation(AppPath.SignInUp) ||
isMatchingLocation(AppPath.SignIn) ||
isMatchingLocation(AppPath.Invite) || isMatchingLocation(AppPath.Invite) ||
isMatchingLocation(AppPath.Verify); isMatchingLocation(AppPath.Verify);
@ -73,7 +72,7 @@ export const PageChangeEffect = () => {
enqueueSnackBar('workspace does not exist', { enqueueSnackBar('workspace does not exist', {
variant: 'error', variant: 'error',
}); });
navigate(AppPath.SignUp); navigate(AppPath.SignInUp);
}; };
if ( if (
@ -81,7 +80,7 @@ export const PageChangeEffect = () => {
!isMatchingOngoingUserCreationRoute && !isMatchingOngoingUserCreationRoute &&
!isMatchingLocation(AppPath.ResetPassword) !isMatchingLocation(AppPath.ResetPassword)
) { ) {
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
} else if ( } else if (
isDefined(onboardingStatus) && isDefined(onboardingStatus) &&
onboardingStatus === OnboardingStatus.Incomplete && onboardingStatus === OnboardingStatus.Incomplete &&
@ -141,8 +140,6 @@ export const PageChangeEffect = () => {
navigateToSignUp(); navigateToSignUp();
}, },
}); });
} else if (isMatchingLocation(AppPath.SignUp) && isSignUpDisabled) {
navigate(AppPath.SignIn);
} }
}, [ }, [
enqueueSnackBar, enqueueSnackBar,
@ -185,11 +182,7 @@ export const PageChangeEffect = () => {
break; break;
} }
case isMatchingLocation(AppPath.SignIn): { case isMatchingLocation(AppPath.SignInUp): {
setHotkeyScope(PageHotkeyScope.SignInUp);
break;
}
case isMatchingLocation(AppPath.SignUp): {
setHotkeyScope(PageHotkeyScope.SignInUp); setHotkeyScope(PageHotkeyScope.SignInUp);
break; break;
} }

View File

@ -22,7 +22,7 @@ jest.mock('react-router-dom', () => {
const Wrapper = ({ children }: { children: React.ReactNode }) => ( const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot> <RecoilRoot>
<MemoryRouter <MemoryRouter
initialEntries={['/sign-in', '/verify', '/opportunities']} initialEntries={['/welcome', '/verify', '/opportunities']}
initialIndex={2} initialIndex={2}
> >
{children} {children}
@ -44,7 +44,7 @@ describe('useApolloFactory', () => {
expect(res).toHaveProperty('query'); expect(res).toHaveProperty('query');
}); });
it('should navigate to /sign-in on unauthenticated error', async () => { it('should navigate to /welcome on unauthenticated error', async () => {
const errors = [ const errors = [
{ {
extensions: { extensions: {
@ -90,7 +90,7 @@ describe('useApolloFactory', () => {
expect((error as ApolloError).message).toBe('Error message not found.'); expect((error as ApolloError).message).toBe('Error message not found.');
expect(mockNavigate).toHaveBeenCalled(); expect(mockNavigate).toHaveBeenCalled();
expect(mockNavigate).toHaveBeenCalledWith('/sign-in'); expect(mockNavigate).toHaveBeenCalledWith('/welcome');
} }
}); });
}); });

View File

@ -41,12 +41,11 @@ export const useApolloFactory = () => {
setTokenPair(null); setTokenPair(null);
if ( if (
!isMatchingLocation(AppPath.Verify) && !isMatchingLocation(AppPath.Verify) &&
!isMatchingLocation(AppPath.SignIn) && !isMatchingLocation(AppPath.SignInUp) &&
!isMatchingLocation(AppPath.SignUp) &&
!isMatchingLocation(AppPath.Invite) && !isMatchingLocation(AppPath.Invite) &&
!isMatchingLocation(AppPath.ResetPassword) !isMatchingLocation(AppPath.ResetPassword)
) { ) {
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
} }
}, },
extraLinks: [], extraLinks: [],

View File

@ -94,10 +94,17 @@ export const SignInUpForm = () => {
return `Join ${workspace?.displayName ?? ''} team`; return `Join ${workspace?.displayName ?? ''} team`;
} }
if (
signInUpStep === SignInUpStep.Init ||
signInUpStep === SignInUpStep.Email
) {
return 'Welcome to Twenty';
}
return signInUpMode === SignInUpMode.SignIn return signInUpMode === SignInUpMode.SignIn
? 'Sign in to Twenty' ? 'Sign in to Twenty'
: 'Sign up to Twenty'; : 'Sign up to Twenty';
}, [signInUpMode, workspace?.displayName, isInviteMode]); }, [signInUpMode, workspace?.displayName, isInviteMode, signInUpStep]);
const theme = useTheme(); const theme = useTheme();
@ -230,14 +237,14 @@ export const SignInUpForm = () => {
/> />
</StyledForm> </StyledForm>
</StyledContentContainer> </StyledContentContainer>
{signInUpStep === SignInUpStep.Password ? ( {signInUpStep === SignInUpStep.Password && (
<ActionLink onClick={handleResetPassword(form.getValues('email'))}> <ActionLink onClick={handleResetPassword(form.getValues('email'))}>
Forgot your password? Forgot your password?
</ActionLink> </ActionLink>
) : ( )}
{signInUpStep === SignInUpStep.Init && (
<FooterNote> <FooterNote>
By using Twenty, you agree to the Terms of Service and Data Processing By using Twenty, you agree to the Terms of Service and Privacy Policy.
Agreement.
</FooterNote> </FooterNote>
)} )}
</> </>

View File

@ -39,7 +39,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
); );
const [signInUpMode, setSignInUpMode] = useState<SignInUpMode>(() => { const [signInUpMode, setSignInUpMode] = useState<SignInUpMode>(() => {
return isMatchingLocation(AppPath.SignIn) return isMatchingLocation(AppPath.SignInUp)
? SignInUpMode.SignIn ? SignInUpMode.SignIn
: SignInUpMode.SignUp; : SignInUpMode.SignUp;
}); });
@ -53,7 +53,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
const continueWithEmail = useCallback(() => { const continueWithEmail = useCallback(() => {
setSignInUpStep(SignInUpStep.Email); setSignInUpStep(SignInUpStep.Email);
setSignInUpMode( setSignInUpMode(
isMatchingLocation(AppPath.SignIn) isMatchingLocation(AppPath.SignInUp)
? SignInUpMode.SignIn ? SignInUpMode.SignIn
: SignInUpMode.SignUp, : SignInUpMode.SignUp,
); );

View File

@ -29,7 +29,7 @@ export const useSignInUpForm = () => {
}); });
useEffect(() => { useEffect(() => {
if (isSignInPrefilled) { if (isSignInPrefilled === true) {
form.setValue('email', 'tim@apple.dev'); form.setValue('email', 'tim@apple.dev');
form.setValue('password', 'Applecar2025'); form.setValue('password', 'Applecar2025');
} }

View File

@ -33,7 +33,7 @@ export const SettingsNavigationDrawerItems = () => {
const handleLogout = useCallback(() => { const handleLogout = useCallback(() => {
signOut(); signOut();
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
}, [signOut, navigate]); }, [signOut, navigate]);
const isCalendarEnabled = useIsFeatureEnabled('IS_CALENDAR_ENABLED'); const isCalendarEnabled = useIsFeatureEnabled('IS_CALENDAR_ENABLED');

View File

@ -22,7 +22,7 @@ export const DeleteAccount = () => {
const handleLogout = useCallback(() => { const handleLogout = useCallback(() => {
signOut(); signOut();
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
}, [signOut, navigate]); }, [signOut, navigate]);
const deleteAccount = async () => { const deleteAccount = async () => {

View File

@ -24,7 +24,7 @@ export const DeleteWorkspace = () => {
const handleLogout = useCallback(() => { const handleLogout = useCallback(() => {
signOut(); signOut();
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
}, [signOut, navigate]); }, [signOut, navigate]);
const deleteWorkspace = async () => { const deleteWorkspace = async () => {

View File

@ -1,8 +1,7 @@
export enum AppPath { export enum AppPath {
// Not logged-in // Not logged-in
Verify = '/verify', Verify = '/verify',
SignIn = '/sign-in', SignInUp = '/welcome',
SignUp = '/sign-up',
Invite = '/invite/:workspaceInviteHash', Invite = '/invite/:workspaceInviteHash',
ResetPassword = '/reset-password/:passwordResetToken', ResetPassword = '/reset-password/:passwordResetToken',

View File

@ -66,15 +66,6 @@ const StyledInputContainer = styled.div`
margin-bottom: ${({ theme }) => theme.spacing(3)}; margin-bottom: ${({ theme }) => theme.spacing(3)};
`; `;
const StyledFooterContainer = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.tertiary};
display: flex;
font-size: ${({ theme }) => theme.font.size.sm};
text-align: center;
max-width: 280px;
`;
export const PasswordReset = () => { export const PasswordReset = () => {
const { enqueueSnackBar } = useSnackBar(); const { enqueueSnackBar } = useSnackBar();
@ -107,7 +98,7 @@ export const PasswordReset = () => {
variant: 'error', variant: 'error',
}); });
if (!isLoggedIn) { if (!isLoggedIn) {
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
} else { } else {
navigate(AppPath.Index); navigate(AppPath.Index);
} }
@ -253,10 +244,6 @@ export const PasswordReset = () => {
</StyledForm> </StyledForm>
)} )}
</StyledContentContainer> </StyledContentContainer>
<StyledFooterContainer>
By using Twenty, you agree to the Terms of Service and Data Processing
Agreement.
</StyledFooterContainer>
</StyledMainContainer> </StyledMainContainer>
); );
}; };

View File

@ -20,7 +20,7 @@ export const VerifyEffect = () => {
useEffect(() => { useEffect(() => {
const getTokens = async () => { const getTokens = async () => {
if (!loginToken) { if (!loginToken) {
navigate(AppPath.SignIn); navigate(AppPath.SignInUp);
} else { } else {
await verify(loginToken); await verify(loginToken);

View File

@ -18,7 +18,7 @@ const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/SignInUp', title: 'Pages/Auth/SignInUp',
component: SignInUp, component: SignInUp,
decorators: [PageDecorator], decorators: [PageDecorator],
args: { routePath: AppPath.SignIn }, args: { routePath: AppPath.SignInUp },
parameters: { parameters: {
msw: { msw: {
handlers: [ handlers: [

View File

@ -3,8 +3,9 @@ import { getPageTitleFromPath } from '../title-utils';
describe('title-utils', () => { describe('title-utils', () => {
it('should return the correct title for a given path', () => { it('should return the correct title for a given path', () => {
expect(getPageTitleFromPath('/verify')).toBe('Verify'); expect(getPageTitleFromPath('/verify')).toBe('Verify');
expect(getPageTitleFromPath('/sign-in')).toBe('Sign In'); expect(getPageTitleFromPath('/welcome')).toBe(
expect(getPageTitleFromPath('/sign-up')).toBe('Sign Up'); 'Sign in or Create an account',
);
expect(getPageTitleFromPath('/invite/:workspaceInviteHash')).toBe('Invite'); expect(getPageTitleFromPath('/invite/:workspaceInviteHash')).toBe('Invite');
expect(getPageTitleFromPath('/create/workspace')).toBe('Create Workspace'); expect(getPageTitleFromPath('/create/workspace')).toBe('Create Workspace');
expect(getPageTitleFromPath('/create/profile')).toBe('Create Profile'); expect(getPageTitleFromPath('/create/profile')).toBe('Create Profile');

View File

@ -6,10 +6,8 @@ export const getPageTitleFromPath = (pathname: string): string => {
switch (pathname) { switch (pathname) {
case AppPath.Verify: case AppPath.Verify:
return 'Verify'; return 'Verify';
case AppPath.SignIn: case AppPath.SignInUp:
return 'Sign In'; return 'Sign in or Create an account';
case AppPath.SignUp:
return 'Sign Up';
case AppPath.Invite: case AppPath.Invite:
return 'Invite'; return 'Invite';
case AppPath.CreateWorkspace: case AppPath.CreateWorkspace:

View File

@ -7,10 +7,8 @@ import {
export const CallToAction = () => { export const CallToAction = () => {
return ( return (
<CallToActionContainer> <CallToActionContainer>
<LinkNextToCTA href="https://github.com/twentyhq/twenty"> <LinkNextToCTA href="https://app.twenty.com">Sign in</LinkNextToCTA>
Sign in <a href="https://app.twenty.com">
</LinkNextToCTA>
<a href="https://twenty.com/stripe-redirection">
<StyledButton>Get Started</StyledButton> <StyledButton>Get Started</StyledButton>
</a> </a>
</CallToActionContainer> </CallToActionContainer>