Various fixes (#11448)

# Scrollbar fix

Fixes https://github.com/twentyhq/twenty/issues/11403

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/b13fe0f2-8c61-4ea8-9ea1-e61e571a90da"
/>

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
Charles Bochet
2025-04-09 01:03:43 +02:00
committed by GitHub
parent ab63214efa
commit b6e344e7be
41 changed files with 265 additions and 470 deletions

View File

@ -4,8 +4,6 @@ import React from 'react';
const StyledInputErrorHelper = styled.div`
color: ${({ theme }) => theme.color.red};
font-size: ${({ theme }) => theme.font.size.xs};
position: absolute;
margin-top: ${({ theme }) => theme.spacing(0.25)};
`;
export const InputErrorHelper = ({

View File

@ -1,11 +1,10 @@
import { renderHook } from '@testing-library/react';
import { RecoilRoot, useSetRecoilState } from 'recoil';
import { RecoilRoot } from 'recoil';
import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
import { AppPath } from '@/types/AppPath';
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
@ -39,14 +38,9 @@ const setupMockIsMatchingLocation = (pathname: string) => {
});
};
const getResult = (isDefaultLayoutAuthModalVisible = true) =>
const getResult = () =>
renderHook(
() => {
const setIsDefaultLayoutAuthModalVisible = useSetRecoilState(
isDefaultLayoutAuthModalVisibleState,
);
setIsDefaultLayoutAuthModalVisible(isDefaultLayoutAuthModalVisible);
return useShowAuthModal();
},
{
@ -112,15 +106,15 @@ const testCases = [
{ loc: AppPath.ResetPassword, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: true },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.CreateWorkspace, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: true },
{ loc: AppPath.CreateProfile, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
@ -157,14 +151,14 @@ const testCases = [
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Unpaid, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.PastDue, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.PlanRequired, isLogged: false, subscriptionStatus: undefined, onboardingStatus: undefined, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: true },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
{ loc: AppPath.PlanRequired, isLogged: true, subscriptionStatus: SubscriptionStatus.Active, onboardingStatus: OnboardingStatus.COMPLETED, res: true },
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: undefined, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: true },
{ loc: AppPath.PlanRequiredSuccess, isLogged: true, subscriptionStatus: SubscriptionStatus.Canceled, onboardingStatus: OnboardingStatus.COMPLETED, res: false },
@ -290,7 +284,7 @@ const testCases = [
describe('useShowAuthModal', () => {
testCases.forEach((testCase) => {
it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.onboardingStatus} should return ${testCase.res}`, () => {
it(`testCase for location ${testCase.loc} with onboardingStatus ${testCase.onboardingStatus} and subscriptionStatus ${testCase.subscriptionStatus} should return ${testCase.res}`, () => {
setupMockOnboardingStatus(testCase.onboardingStatus);
setupMockSubscriptionStatus(testCase.subscriptionStatus);
setupMockIsMatchingLocation(testCase.loc);
@ -305,21 +299,21 @@ describe('useShowAuthModal', () => {
});
describe('test with token validation loading', () => {
it(`with appPath ${AppPath.Invite} and isDefaultLayoutAuthModalVisible=false`, () => {
it(`with appPath ${AppPath.Invite} `, () => {
setupMockOnboardingStatus(OnboardingStatus.COMPLETED);
setupMockSubscriptionStatus(SubscriptionStatus.Active);
setupMockIsMatchingLocation(AppPath.Invite);
setupMockIsLogged(true);
const { result } = getResult(false);
expect(result.current).toBeFalsy();
const { result } = getResult();
expect(result.current).toBeTruthy();
});
it(`with appPath ${AppPath.ResetPassword} and isDefaultLayoutAuthModalVisible=false`, () => {
it(`with appPath ${AppPath.ResetPassword} `, () => {
setupMockOnboardingStatus(OnboardingStatus.COMPLETED);
setupMockSubscriptionStatus(SubscriptionStatus.Active);
setupMockIsMatchingLocation(AppPath.ResetPassword);
setupMockIsLogged(true);
const { result } = getResult(false);
expect(result.current).toBeFalsy();
const { result } = getResult();
expect(result.current).toBeTruthy();
});
});

View File

@ -1,40 +1,27 @@
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
import { AppPath } from '@/types/AppPath';
import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
import { isDefined } from 'twenty-shared/utils';
import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql';
import { OnboardingStatus } from '~/generated/graphql';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
export const useShowAuthModal = () => {
const { isMatchingLocation } = useIsMatchingLocation();
const isLoggedIn = useIsLogged();
const onboardingStatus = useOnboardingStatus();
const subscriptionStatus = useSubscriptionStatus();
const isDefaultLayoutAuthModalVisible = useRecoilValue(
isDefaultLayoutAuthModalVisibleState,
);
return useMemo(() => {
if (
isMatchingLocation(AppPath.Verify) ||
isMatchingLocation(AppPath.VerifyEmail)
) {
return true;
}
if (
isMatchingLocation(AppPath.Invite) ||
isMatchingLocation(AppPath.ResetPassword) ||
isMatchingLocation(AppPath.VerifyEmail) ||
isMatchingLocation(AppPath.SignInUp)
isMatchingLocation(AppPath.Verify) ||
isMatchingLocation(AppPath.SignInUp) ||
isMatchingLocation(AppPath.CreateWorkspace) ||
isMatchingLocation(AppPath.PlanRequired)
) {
return isDefaultLayoutAuthModalVisible;
return true;
}
if (
@ -48,20 +35,6 @@ export const useShowAuthModal = () => {
return true;
}
if (isMatchingLocation(AppPath.PlanRequired)) {
return (
(onboardingStatus === OnboardingStatus.COMPLETED &&
!isDefined(subscriptionStatus)) ||
subscriptionStatus === SubscriptionStatus.Canceled
);
}
return false;
}, [
isLoggedIn,
isDefaultLayoutAuthModalVisible,
isMatchingLocation,
onboardingStatus,
subscriptionStatus,
]);
}, [isLoggedIn, isMatchingLocation, onboardingStatus]);
};

View File

@ -257,3 +257,4 @@ export const Modal = ({
Modal.Header = ModalHeader;
Modal.Content = ModalContent;
Modal.Footer = ModalFooter;
Modal.Backdrop = StyledBackDrop;

View File

@ -26,7 +26,7 @@ const StyledLayout = styled.div`
flex-direction: column;
height: 100dvh;
position: relative;
scrollbar-color: ${({ theme }) => theme.border.color.medium};
scrollbar-color: ${({ theme }) => theme.border.color.medium} transparent;
scrollbar-width: 4px;
width: 100%;
@ -105,7 +105,9 @@ export const DefaultLayout = () => {
)}
{showAuthModal ? (
<>
<SignInBackgroundMockPage />
<StyledMainContainer>
<SignInBackgroundMockPage />
</StyledMainContainer>
<AnimatePresence mode="wait">
<LayoutGroup>
<AuthModal isOpenAnimated={animateModal}>

View File

@ -1,5 +0,0 @@
import { createState } from 'twenty-ui/utilities';
export const isDefaultLayoutAuthModalVisibleState = createState<boolean>({
key: 'isDefaultLayoutAuthModalVisibleState',
defaultValue: true,
});

View File

@ -9,10 +9,10 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta
const StyledScrollWrapper = styled.div`
&.scroll-wrapper-x-enabled {
overflow-x: scroll;
overflow-x: overlay;
}
&.scroll-wrapper-y-enabled {
overflow-y: scroll;
overflow-y: overlay;
}
overflow-x: hidden;
overflow-y: hidden;