Update Connected Accounts Design (#13332)
/closes #13328 --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1,40 +1,65 @@
|
|||||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||||
import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard';
|
import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard';
|
||||||
|
import { SettingsConnectedAccountsTableHeader } from '@/settings/accounts/components/SettingsConnectedAccountsTableHeader';
|
||||||
|
import { SettingsConnectedAccountsTableRow } from '@/settings/components/SettingsConnectedAccountsTableRow';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { Table } from '@/ui/layout/table/components/Table';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { SettingsAccountsConnectedAccountsRowRightContainer } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { IconPlus } from 'twenty-ui/display';
|
||||||
|
|
||||||
import { SettingsConnectedAccountIcon } from '@/settings/accounts/components/SettingsConnectedAccountIcon';
|
import { Button } from 'twenty-ui/input';
|
||||||
|
import { Section } from 'twenty-ui/layout';
|
||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
import { SettingsListCard } from '../../components/SettingsListCard';
|
|
||||||
|
const StyledTableRows = styled.div`
|
||||||
|
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledAddAccountSection = styled(Section)`
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
export const SettingsAccountsConnectedAccountsListCard = ({
|
export const SettingsAccountsConnectedAccountsListCard = ({
|
||||||
accounts,
|
accounts,
|
||||||
loading,
|
|
||||||
}: {
|
}: {
|
||||||
accounts: ConnectedAccount[];
|
accounts: ConnectedAccount[];
|
||||||
loading?: boolean;
|
|
||||||
}) => {
|
}) => {
|
||||||
const navigate = useNavigateSettings();
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
const navigateSettings = useNavigateSettings();
|
||||||
|
|
||||||
if (!accounts.length) {
|
if (!accounts.length) {
|
||||||
return <SettingsAccountsListEmptyStateCard />;
|
return <SettingsAccountsListEmptyStateCard />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsListCard
|
<Section>
|
||||||
items={accounts}
|
<Table>
|
||||||
getItemLabel={(account) => account.handle}
|
<SettingsConnectedAccountsTableHeader />
|
||||||
isLoading={loading}
|
<StyledTableRows>
|
||||||
RowIconFn={(row) => SettingsConnectedAccountIcon({ account: row })}
|
{accounts.map((account) => (
|
||||||
RowRightComponent={({ item: account }) => (
|
<SettingsConnectedAccountsTableRow
|
||||||
<SettingsAccountsConnectedAccountsRowRightContainer account={account} />
|
key={account.id}
|
||||||
)}
|
account={account}
|
||||||
hasFooter={true}
|
/>
|
||||||
footerButtonLabel={t`Add account`}
|
))}
|
||||||
onFooterButtonClick={() => navigate(SettingsPath.NewAccount)}
|
</StyledTableRows>
|
||||||
/>
|
</Table>
|
||||||
|
<StyledAddAccountSection>
|
||||||
|
<Button
|
||||||
|
Icon={IconPlus}
|
||||||
|
title={t`Add account`}
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
onClick={() => navigateSettings(SettingsPath.NewAccount)}
|
||||||
|
/>
|
||||||
|
</StyledAddAccountSection>
|
||||||
|
</Section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { Status } from 'twenty-ui/display';
|
|||||||
const StyledRowRightContainer = styled.div`
|
const StyledRowRightContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SettingsAccountsConnectedAccountsRowRightContainer = ({
|
export const SettingsAccountsConnectedAccountsRowRightContainer = ({
|
||||||
|
|||||||
@ -3,40 +3,30 @@ import { isGoogleMessagingEnabledState } from '@/client-config/states/isGoogleMe
|
|||||||
import { isMicrosoftCalendarEnabledState } from '@/client-config/states/isMicrosoftCalendarEnabledState';
|
import { isMicrosoftCalendarEnabledState } from '@/client-config/states/isMicrosoftCalendarEnabledState';
|
||||||
import { isMicrosoftMessagingEnabledState } from '@/client-config/states/isMicrosoftMessagingEnabledState';
|
import { isMicrosoftMessagingEnabledState } from '@/client-config/states/isMicrosoftMessagingEnabledState';
|
||||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||||
|
import { SettingsCard } from '@/settings/components/SettingsCard';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
||||||
import { IconAt, IconGoogle, IconMicrosoft } from 'twenty-ui/display';
|
import { IconAt, IconGoogle, IconMicrosoft } from 'twenty-ui/display';
|
||||||
import { Button } from 'twenty-ui/input';
|
import { UndecoratedLink } from 'twenty-ui/navigation';
|
||||||
import { Card, CardContent, CardHeader } from 'twenty-ui/layout';
|
|
||||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
const StyledHeader = styled(CardHeader)`
|
const StyledCardsContainer = styled.div`
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
height: ${({ theme }) => theme.spacing(6)};
|
flex-direction: column;
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledBody = styled(CardContent)`
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type SettingsAccountsListEmptyStateCardProps = {
|
export const SettingsAccountsListEmptyStateCard = () => {
|
||||||
label?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SettingsAccountsListEmptyStateCard = ({
|
|
||||||
label,
|
|
||||||
}: SettingsAccountsListEmptyStateCardProps) => {
|
|
||||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||||
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const isGoogleMessagingEnabled = useRecoilValue(
|
const isGoogleMessagingEnabled = useRecoilValue(
|
||||||
isGoogleMessagingEnabledState,
|
isGoogleMessagingEnabledState,
|
||||||
@ -56,36 +46,33 @@ export const SettingsAccountsListEmptyStateCard = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<StyledCardsContainer>
|
||||||
<StyledHeader>{label || t`No connected account`}</StyledHeader>
|
{(isGoogleMessagingEnabled || isGoogleCalendarEnabled) && (
|
||||||
<StyledBody>
|
<SettingsCard
|
||||||
{(isGoogleMessagingEnabled || isGoogleCalendarEnabled) && (
|
Icon={<IconGoogle size={theme.icon.size.md} />}
|
||||||
<Button
|
title={t`Connect with Google`}
|
||||||
Icon={IconGoogle}
|
onClick={() => triggerApisOAuth(ConnectedAccountProvider.GOOGLE)}
|
||||||
title={t`Connect with Google`}
|
/>
|
||||||
variant="secondary"
|
)}
|
||||||
onClick={() => triggerApisOAuth(ConnectedAccountProvider.GOOGLE)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(isMicrosoftMessagingEnabled || isMicrosoftCalendarEnabled) && (
|
{(isMicrosoftMessagingEnabled || isMicrosoftCalendarEnabled) && (
|
||||||
<Button
|
<SettingsCard
|
||||||
Icon={IconMicrosoft}
|
Icon={<IconMicrosoft size={theme.icon.size.md} />}
|
||||||
title={t`Connect with Microsoft`}
|
title={t`Connect with Microsoft`}
|
||||||
variant="secondary"
|
onClick={() => triggerApisOAuth(ConnectedAccountProvider.MICROSOFT)}
|
||||||
onClick={() => triggerApisOAuth(ConnectedAccountProvider.MICROSOFT)}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{isImapSmtpCaldavFeatureFlagEnabled && (
|
{isImapSmtpCaldavFeatureFlagEnabled && (
|
||||||
<Button
|
<UndecoratedLink
|
||||||
Icon={IconAt}
|
to={getSettingsPath(SettingsPath.NewImapSmtpCaldavConnection)}
|
||||||
|
>
|
||||||
|
<SettingsCard
|
||||||
|
Icon={<IconAt size={theme.icon.size.md} />}
|
||||||
title={t`Connect Email Account`}
|
title={t`Connect Email Account`}
|
||||||
variant="secondary"
|
|
||||||
to={getSettingsPath(SettingsPath.NewImapSmtpCaldavConnection)}
|
|
||||||
/>
|
/>
|
||||||
)}
|
</UndecoratedLink>
|
||||||
</StyledBody>
|
)}
|
||||||
</Card>
|
</StyledCardsContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,11 +12,11 @@ import { useModal } from '@/ui/layout/modal/hooks/useModal';
|
|||||||
import { Trans, useLingui } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
import { ConnectedAccountProvider } from 'twenty-shared/types';
|
||||||
import {
|
import {
|
||||||
|
IconAt,
|
||||||
IconCalendarEvent,
|
IconCalendarEvent,
|
||||||
IconDotsVertical,
|
IconDotsVertical,
|
||||||
IconMail,
|
IconMail,
|
||||||
IconRefresh,
|
IconRefresh,
|
||||||
IconSettings,
|
|
||||||
IconTrash,
|
IconTrash,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { LightIconButton } from 'twenty-ui/input';
|
import { LightIconButton } from 'twenty-ui/input';
|
||||||
@ -63,7 +63,7 @@ export const SettingsAccountsRowDropdownMenu = ({
|
|||||||
ConnectedAccountProvider.IMAP_SMTP_CALDAV && (
|
ConnectedAccountProvider.IMAP_SMTP_CALDAV && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={t`Connection settings`}
|
text={t`Connection settings`}
|
||||||
LeftIcon={IconSettings}
|
LeftIcon={IconAt}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(SettingsPath.EditImapSmtpCaldavConnection, {
|
navigate(SettingsPath.EditImapSmtpCaldavConnection, {
|
||||||
connectedAccountId: account.id,
|
connectedAccountId: account.id,
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { Table } from '@/ui/layout/table/components/Table';
|
||||||
|
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||||
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { Trans } from '@lingui/react/macro';
|
||||||
|
|
||||||
|
const StyledTableHeader = styled(TableHeader)`
|
||||||
|
padding-right: ${({ theme }) => theme.spacing(14)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsConnectedAccountsTableHeader = () => {
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<TableRow gridAutoColumns="332px 1fr">
|
||||||
|
<StyledTableHeader>
|
||||||
|
<Trans>Account</Trans>
|
||||||
|
</StyledTableHeader>
|
||||||
|
<StyledTableHeader align={'right'}>
|
||||||
|
<Trans>Status</Trans>
|
||||||
|
</StyledTableHeader>
|
||||||
|
</TableRow>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -10,7 +10,7 @@ export const SettingsNewAccountSection = () => {
|
|||||||
title={t`New account`}
|
title={t`New account`}
|
||||||
description={t`Connect a new account to your workspace`}
|
description={t`Connect a new account to your workspace`}
|
||||||
/>
|
/>
|
||||||
<SettingsAccountsListEmptyStateCard label={t`Choose your provider`} />
|
<SettingsAccountsListEmptyStateCard />
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||||
|
import { SettingsAccountsConnectedAccountsRowRightContainer } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer';
|
||||||
|
import { SettingsConnectedAccountIcon } from '@/settings/accounts/components/SettingsConnectedAccountIcon';
|
||||||
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledNameCell = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTableRow = styled(TableRow)`
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
type SettingsConnectedAccountsTableRowProps = {
|
||||||
|
account: ConnectedAccount;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SettingsConnectedAccountsTableRow = ({
|
||||||
|
account,
|
||||||
|
}: SettingsConnectedAccountsTableRowProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const IconComponent = SettingsConnectedAccountIcon({ account });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledTableRow key={account.id} gridAutoColumns="332px 1fr">
|
||||||
|
<TableCell>
|
||||||
|
<StyledNameCell>
|
||||||
|
<IconComponent
|
||||||
|
size={theme.icon.size.md}
|
||||||
|
stroke={theme.icon.stroke.sm}
|
||||||
|
/>
|
||||||
|
{account.handle}
|
||||||
|
</StyledNameCell>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell align={'right'}>
|
||||||
|
<SettingsAccountsConnectedAccountsRowRightContainer account={account} />
|
||||||
|
</TableCell>
|
||||||
|
</StyledTableRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -56,10 +56,7 @@ export const SettingsAccounts = () => {
|
|||||||
title={t`Connected accounts`}
|
title={t`Connected accounts`}
|
||||||
description={t`Manage your internet accounts.`}
|
description={t`Manage your internet accounts.`}
|
||||||
/>
|
/>
|
||||||
<SettingsAccountsConnectedAccountsListCard
|
<SettingsAccountsConnectedAccountsListCard accounts={accounts} />
|
||||||
accounts={accounts}
|
|
||||||
loading={loading}
|
|
||||||
/>
|
|
||||||
</Section>
|
</Section>
|
||||||
<SettingsAccountsBlocklistSection />
|
<SettingsAccountsBlocklistSection />
|
||||||
<SettingsAccountsSettingsSection />
|
<SettingsAccountsSettingsSection />
|
||||||
|
|||||||
Reference in New Issue
Block a user