6446 improve information banner component to make it scale better (#6545)
Closes #6446
This commit is contained in:
@ -1,26 +0,0 @@
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { InformationBannerAccountToReconnect } from '@/information-banner/InformationBannerReconnectAccount';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export enum InformationBannerKeys {
|
||||
ACCOUNTS_TO_RECONNECT = 'ACCOUNTS_TO_RECONNECT',
|
||||
}
|
||||
|
||||
export const InformationBanner = () => {
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
|
||||
const userVars = currentUser?.userVars;
|
||||
|
||||
const firstAccountIdToReconnect =
|
||||
userVars?.[InformationBannerKeys.ACCOUNTS_TO_RECONNECT]?.[0];
|
||||
|
||||
return (
|
||||
<>
|
||||
{firstAccountIdToReconnect && (
|
||||
<InformationBannerAccountToReconnect
|
||||
accountIdToReconnect={firstAccountIdToReconnect}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,38 +0,0 @@
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { Banner, IconRefresh } from 'twenty-ui';
|
||||
|
||||
export const InformationBannerAccountToReconnect = ({
|
||||
accountIdToReconnect,
|
||||
}: {
|
||||
accountIdToReconnect: string;
|
||||
}) => {
|
||||
const accountToReconnect = useFindOneRecord<ConnectedAccount>({
|
||||
objectNameSingular: CoreObjectNameSingular.ConnectedAccount,
|
||||
objectRecordId: accountIdToReconnect,
|
||||
});
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
|
||||
if (!accountToReconnect?.record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Banner>
|
||||
Sync lost with mailbox {accountToReconnect?.record?.handle}. Please
|
||||
reconnect for updates:
|
||||
<Button
|
||||
variant="secondary"
|
||||
title="Reconnect"
|
||||
Icon={IconRefresh}
|
||||
size="small"
|
||||
inverted
|
||||
onClick={() => triggerGoogleApisOAuth()}
|
||||
/>
|
||||
</Banner>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import styled from '@emotion/styled';
|
||||
import { Banner, IconComponent } from 'twenty-ui';
|
||||
|
||||
const StyledBanner = styled(Banner)`
|
||||
position: absolute;
|
||||
`;
|
||||
|
||||
const StyledText = styled.div`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
export const InformationBanner = ({
|
||||
message,
|
||||
buttonTitle,
|
||||
buttonIcon,
|
||||
buttonOnClick,
|
||||
}: {
|
||||
message: string;
|
||||
buttonTitle: string;
|
||||
buttonIcon?: IconComponent;
|
||||
buttonOnClick: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<StyledBanner>
|
||||
<StyledText>{message}</StyledText>
|
||||
<Button
|
||||
variant="secondary"
|
||||
title={buttonTitle}
|
||||
Icon={buttonIcon}
|
||||
size="small"
|
||||
inverted
|
||||
onClick={buttonOnClick}
|
||||
/>
|
||||
</StyledBanner>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
import { InformationBannerReconnectAccountEmailAliases } from '@/information-banner/components/reconnect-account/InformationBannerReconnectAccountEmailAliases';
|
||||
import { InformationBannerReconnectAccountInsufficientPermissions } from '@/information-banner/components/reconnect-account/InformationBannerReconnectAccountInsufficientPermissions';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledInformationBannerWrapper = styled.div`
|
||||
height: 40px;
|
||||
position: relative;
|
||||
|
||||
&:empty {
|
||||
height: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const InformationBannerWrapper = () => {
|
||||
return (
|
||||
<StyledInformationBannerWrapper>
|
||||
<InformationBannerReconnectAccountInsufficientPermissions />
|
||||
<InformationBannerReconnectAccountEmailAliases />
|
||||
</StyledInformationBannerWrapper>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
||||
import { InformationBannerKeys } from '@/information-banner/enums/InformationBannerKeys.enum';
|
||||
import { useAccountToReconnect } from '@/information-banner/hooks/useAccountToReconnect';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { IconRefresh } from 'twenty-ui';
|
||||
|
||||
export const InformationBannerReconnectAccountEmailAliases = () => {
|
||||
const { accountToReconnect } = useAccountToReconnect(
|
||||
InformationBannerKeys.ACCOUNTS_TO_RECONNECT_EMAIL_ALIASES,
|
||||
);
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
|
||||
if (!accountToReconnect) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<InformationBanner
|
||||
message={`Please reconnect your mailbox ${accountToReconnect?.handle} to update your email aliases:`}
|
||||
buttonTitle="Reconnect"
|
||||
buttonIcon={IconRefresh}
|
||||
buttonOnClick={() => triggerGoogleApisOAuth()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
||||
import { InformationBannerKeys } from '@/information-banner/enums/InformationBannerKeys.enum';
|
||||
import { useAccountToReconnect } from '@/information-banner/hooks/useAccountToReconnect';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { IconRefresh } from 'twenty-ui';
|
||||
|
||||
export const InformationBannerReconnectAccountInsufficientPermissions = () => {
|
||||
const { accountToReconnect } = useAccountToReconnect(
|
||||
InformationBannerKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
|
||||
);
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
|
||||
if (!accountToReconnect) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<InformationBanner
|
||||
message={`Sync lost with mailbox ${accountToReconnect?.handle}. Please
|
||||
reconnect for updates:`}
|
||||
buttonTitle="Reconnect"
|
||||
buttonIcon={IconRefresh}
|
||||
buttonOnClick={() => triggerGoogleApisOAuth()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,4 @@
|
||||
export enum InformationBannerKeys {
|
||||
ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS = 'ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS',
|
||||
ACCOUNTS_TO_RECONNECT_EMAIL_ALIASES = 'ACCOUNTS_TO_RECONNECT_EMAIL_ALIASES',
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { InformationBannerKeys } from '@/information-banner/enums/InformationBannerKeys.enum';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useAccountToReconnect = (key: InformationBannerKeys) => {
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
|
||||
const userVars = currentUser?.userVars;
|
||||
|
||||
const firstAccountIdToReconnect = userVars?.[key]?.[0];
|
||||
|
||||
const accountToReconnect = useFindOneRecord<ConnectedAccount>({
|
||||
objectNameSingular: CoreObjectNameSingular.ConnectedAccount,
|
||||
objectRecordId: firstAccountIdToReconnect,
|
||||
skip: !firstAccountIdToReconnect,
|
||||
});
|
||||
|
||||
return {
|
||||
accountToReconnect: accountToReconnect?.record,
|
||||
};
|
||||
};
|
||||
@ -1,7 +1,6 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { InformationBanner } from '@/information-banner/InformationBanner';
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
@ -21,6 +20,7 @@ import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-in
|
||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
|
||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||
import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
@ -42,7 +42,7 @@ const StyledContainer = styled.div`
|
||||
`;
|
||||
|
||||
const StyledContainerWithPadding = styled.div<{ fullHeight?: boolean }>`
|
||||
min-height: ${({ fullHeight }) => (fullHeight ? '100%' : 'auto')};
|
||||
height: ${({ fullHeight }) => (fullHeight ? '100%' : 'auto')};
|
||||
padding-left: ${({ theme }) => theme.table.horizontalCellPadding};
|
||||
`;
|
||||
|
||||
@ -126,7 +126,7 @@ export const RecordIndexContainer = ({
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<InformationBanner />
|
||||
<InformationBannerWrapper />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<SpreadsheetImportProvider>
|
||||
<StyledContainerWithPadding>
|
||||
|
||||
@ -4,7 +4,7 @@ import { IconComponent } from 'twenty-ui';
|
||||
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
import { InformationBanner } from '@/information-banner/InformationBanner';
|
||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||
import { PageBody } from './PageBody';
|
||||
import { PageHeader } from './PageHeader';
|
||||
|
||||
@ -34,7 +34,7 @@ export const SubMenuTopBarContainer = ({
|
||||
<StyledContainer isMobile={isMobile} className={className}>
|
||||
{isMobile && <PageHeader title={title} Icon={Icon} />}
|
||||
<PageBody>
|
||||
<InformationBanner />
|
||||
<InformationBannerWrapper />
|
||||
{children}
|
||||
</PageBody>
|
||||
</StyledContainer>
|
||||
|
||||
Reference in New Issue
Block a user