5899 display a banner to alert users which need to reconnect their account (#6301)
Closes #5899 <img width="1280" alt="Index - banner" src="https://github.com/twentyhq/twenty/assets/71827178/313cf20d-eb34-496a-8c7c-7589fbd55954"> --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -4,8 +4,8 @@ import { CalendarChannelVisibility } from '~/generated/graphql';
|
||||
// TODO: use backend CalendarEvent type when ready
|
||||
export type CalendarEvent = {
|
||||
conferenceLink?: {
|
||||
label: string;
|
||||
url: string;
|
||||
primaryLinkLabel: string;
|
||||
primaryLinkUrl: string;
|
||||
};
|
||||
description?: string;
|
||||
endsAt?: string;
|
||||
|
||||
@ -4,7 +4,12 @@ import { User } from '~/generated/graphql';
|
||||
|
||||
export type CurrentUser = Pick<
|
||||
User,
|
||||
'id' | 'email' | 'supportUserHash' | 'canImpersonate' | 'onboardingStatus'
|
||||
| 'id'
|
||||
| 'email'
|
||||
| 'supportUserHash'
|
||||
| 'canImpersonate'
|
||||
| 'onboardingStatus'
|
||||
| 'userVars'
|
||||
>;
|
||||
|
||||
export const currentUserState = createState<CurrentUser | null>({
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
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}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,38 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
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';
|
||||
@ -125,6 +126,7 @@ export const RecordIndexContainer = ({
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<InformationBanner />
|
||||
<RecordFieldValueSelectorContextProvider>
|
||||
<SpreadsheetImportProvider>
|
||||
<StyledContainerWithPadding>
|
||||
|
||||
@ -51,8 +51,8 @@ export const SettingsAccountsCalendarChannelsGeneral = () => {
|
||||
startsAt: exampleStartDate.toISOString(),
|
||||
conferenceSolution: '',
|
||||
conferenceLink: {
|
||||
label: '',
|
||||
url: '',
|
||||
primaryLinkLabel: '',
|
||||
primaryLinkUrl: '',
|
||||
},
|
||||
description: '',
|
||||
isCanceled: false,
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledBanner = styled.div`
|
||||
align-items: center;
|
||||
backdrop-filter: blur(5px);
|
||||
background: ${({ theme }) => theme.color.blue};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
height: 40px;
|
||||
justify-content: center;
|
||||
padding: ${({ theme }) => theme.spacing(2) + ' ' + theme.spacing(3)};
|
||||
width: 100%;
|
||||
color: ${({ theme }) => theme.font.color.inverted};
|
||||
font-family: Inter;
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-style: normal;
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
line-height: 150%;
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
|
||||
export { StyledBanner as Banner };
|
||||
@ -1,34 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { ComponentDecorator, IconRefresh } from 'twenty-ui';
|
||||
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
|
||||
import { Banner } from '../Banner';
|
||||
|
||||
const meta: Meta<typeof Banner> = {
|
||||
title: 'UI/Layout/Banner/Banner',
|
||||
component: Banner,
|
||||
decorators: [ComponentDecorator],
|
||||
render: (args) => (
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
<Banner {...args}>
|
||||
Sync lost with mailbox hello@twenty.com. Please reconnect for updates:
|
||||
<Button
|
||||
variant="secondary"
|
||||
title="Reconnect"
|
||||
Icon={IconRefresh}
|
||||
size="small"
|
||||
inverted
|
||||
/>
|
||||
</Banner>
|
||||
),
|
||||
argTypes: {
|
||||
as: { control: false },
|
||||
theme: { control: false },
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Banner>;
|
||||
|
||||
export const Default: Story = {};
|
||||
@ -1,9 +1,10 @@
|
||||
import { JSX } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { JSX } from 'react';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
import { InformationBanner } from '@/information-banner/InformationBanner';
|
||||
import { PageBody } from './PageBody';
|
||||
import { PageHeader } from './PageHeader';
|
||||
|
||||
@ -32,7 +33,10 @@ export const SubMenuTopBarContainer = ({
|
||||
return (
|
||||
<StyledContainer isMobile={isMobile} className={className}>
|
||||
{isMobile && <PageHeader title={title} Icon={Icon} />}
|
||||
<PageBody>{children}</PageBody>
|
||||
<PageBody>
|
||||
<InformationBanner />
|
||||
{children}
|
||||
</PageBody>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
|
||||
@ -49,5 +49,6 @@ export const USER_QUERY_FRAGMENT = gql`
|
||||
domainName
|
||||
}
|
||||
}
|
||||
userVars
|
||||
}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user