Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create Settings/Accounts/Calendars page #4090

Merged
merged 3 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/twenty-front/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { RecordIndexPage } from '~/pages/object-record/RecordIndexPage';
import { RecordShowPage } from '~/pages/object-record/RecordShowPage';
import { Opportunities } from '~/pages/opportunities/Opportunities';
import { SettingsAccounts } from '~/pages/settings/accounts/SettingsAccounts';
import { SettingsAccountsCalendars } from '~/pages/settings/accounts/SettingsAccountsCalendars';
import { SettingsAccountsEmails } from '~/pages/settings/accounts/SettingsAccountsEmails';
import { SettingsAccountsEmailsInboxSettings } from '~/pages/settings/accounts/SettingsAccountsEmailsInboxSettings';
import { SettingsNewAccount } from '~/pages/settings/accounts/SettingsNewAccount';
Expand Down Expand Up @@ -95,6 +96,10 @@ export const App = () => {
path={SettingsPath.NewAccount}
element={<SettingsNewAccount />}
/>
<Route
path={SettingsPath.AccountsCalendars}
element={<SettingsAccountsCalendars />}
/>
<Route
path={SettingsPath.AccountsEmails}
element={<SettingsAccountsEmails />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import { useNavigate } from 'react-router-dom';
import styled from '@emotion/styled';

import { SettingsNavigationCard } from '@/settings/components/SettingsNavigationCard';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import { IconCalendarEvent, IconMailCog } from '@/ui/display/icon';
import { H2Title } from '@/ui/display/typography/components/H2Title';
import { Section } from '@/ui/layout/section/components/Section';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';

const StyledCardsContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(4)};
margin-top: ${({ theme }) => theme.spacing(6)};
`;

const StyledSettingsNavigationCard = styled(SettingsNavigationCard)`
color: ${({ theme }) => theme.font.color.extraLight};
`;

export const SettingsAccountsSettingsSection = () => {
const navigate = useNavigate();
const isCalendarEnabled = useIsFeatureEnabled('IS_CALENDAR_ENABLED');

return (
<Section>
Expand All @@ -29,18 +29,22 @@ export const SettingsAccountsSettingsSection = () => {
<SettingsNavigationCard
Icon={IconMailCog}
title="Emails"
onClick={() => navigate('/settings/accounts/emails')}
onClick={() =>
navigate(getSettingsPagePath(SettingsPath.AccountsEmails))
}
>
Set email visibility, manage your blocklist and more.
</SettingsNavigationCard>
<StyledSettingsNavigationCard
<SettingsNavigationCard
Icon={IconCalendarEvent}
title="Calendar"
disabled
hasSoonPill
soon={!isCalendarEnabled}
onClick={() =>
navigate(getSettingsPagePath(SettingsPath.AccountsCalendars))
}
>
Configure and customize your calendar preferences.
</StyledSettingsNavigationCard>
</SettingsNavigationCard>
</StyledCardsContainer>
</Section>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CardContent } from '@/ui/layout/card/components/CardContent';
type SettingsNavigationCardProps = {
children: ReactNode;
disabled?: boolean;
hasSoonPill?: boolean;
soon?: boolean;
Icon: IconComponent;
onClick?: () => void;
title: string;
Expand All @@ -22,7 +22,8 @@ const StyledCard = styled(Card)<{
disabled?: boolean;
onClick?: () => void;
}>`
color: ${({ theme }) => theme.font.color.tertiary};
color: ${({ disabled, theme }) =>
disabled ? theme.font.color.extraLight : theme.font.color.tertiary};
cursor: ${({ disabled, onClick }) =>
disabled ? 'not-allowed' : onClick ? 'pointer' : 'default'};
`;
Expand All @@ -40,8 +41,9 @@ const StyledHeader = styled.div`
gap: ${({ theme }) => theme.spacing(3)};
`;

const StyledTitle = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
const StyledTitle = styled.div<{ disabled?: boolean }>`
color: ${({ disabled, theme }) =>
disabled ? 'inherit' : theme.font.color.secondary};
display: flex;
flex: 1 0 auto;
font-weight: ${({ theme }) => theme.font.weight.medium};
Expand All @@ -59,8 +61,8 @@ const StyledDescription = styled.div`

export const SettingsNavigationCard = ({
children,
disabled,
hasSoonPill,
soon,
disabled = soon,
Icon,
onClick,
title,
Expand All @@ -69,13 +71,17 @@ export const SettingsNavigationCard = ({
const theme = useTheme();

return (
<StyledCard disabled={disabled} onClick={onClick} className={className}>
<StyledCard
disabled={disabled}
onClick={disabled ? undefined : onClick}
className={className}
>
<StyledCardContent>
<StyledHeader>
<Icon size={theme.icon.size.lg} stroke={theme.icon.stroke.sm} />
<StyledTitle className={className}>
<StyledTitle disabled={disabled}>
{title}
{hasSoonPill && <SoonPill />}
{soon && <SoonPill />}
</StyledTitle>
<StyledIconChevronRight size={theme.icon.size.sm} />
</StyledHeader>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useMatch, useResolvedPath } from 'react-router-dom';

import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import {
NavigationDrawerItem,
NavigationDrawerItemProps,
} from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';

type SettingsNavigationDrawerItemProps = Pick<
NavigationDrawerItemProps,
'Icon' | 'label' | 'level' | 'soon'
> & {
matchSubPages?: boolean;
path: SettingsPath;
};

export const SettingsNavigationDrawerItem = ({
Icon,
label,
level,
matchSubPages = false,
path,
soon,
}: SettingsNavigationDrawerItemProps) => {
const href = getSettingsPagePath(path);
const isActive = !!useMatch({
path: useResolvedPath(href).pathname,
end: !matchSubPages,
});

return (
<NavigationDrawerItem
level={level}
label={label}
to={href}
Icon={Icon}
active={isActive}
soon={soon}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useCallback } from 'react';
import { useMatch, useNavigate, useResolvedPath } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import { useAuth } from '@/auth/hooks/useAuth';
import { SettingsNavigationDrawerItem } from '@/settings/components/SettingsNavigationDrawerItem';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
import {
IconApps,
IconAt,
Expand Down Expand Up @@ -31,123 +33,77 @@ export const SettingsNavigationDrawerItems = () => {
navigate(AppPath.SignIn);
}, [signOut, navigate]);

const isCalendarEnabled = useIsFeatureEnabled('IS_CALENDAR_ENABLED');
const isMessagingEnabled = useIsFeatureEnabled('IS_MESSAGING_ENABLED');
const isIntegrationsItemActive = !!useMatch({
path: useResolvedPath('/settings/integrations').pathname,
end: true,
});

const isAccountsItemActive = !!useMatch({
path: useResolvedPath('/settings/accounts').pathname,
end: true,
});
const isAccountsEmailsItemActive = !!useMatch({
path: useResolvedPath('/settings/accounts/emails').pathname,
end: true,
});

return (
<>
<NavigationDrawerSection>
<NavigationDrawerSectionTitle label="User" />
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Profile"
to="/settings/profile"
path={SettingsPath.ProfilePage}
Icon={IconUserCircle}
active={
!!useMatch({
path: useResolvedPath('/settings/profile').pathname,
end: true,
})
}
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Appearance"
to="/settings/profile/appearance"
path={SettingsPath.Appearance}
Icon={IconColorSwatch}
active={
!!useMatch({
path: useResolvedPath('/settings/profile/appearance').pathname,
end: true,
})
}
/>

{isMessagingEnabled && (
<NavigationDrawerItemGroup>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Accounts"
to="/settings/accounts"
path={SettingsPath.Accounts}
Icon={IconAt}
active={isAccountsItemActive}
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
level={2}
label="Emails"
to="/settings/accounts/emails"
path={SettingsPath.AccountsEmails}
Icon={IconMail}
active={isAccountsEmailsItemActive}
matchSubPages
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
level={2}
label="Calendars"
path={SettingsPath.AccountsCalendars}
Icon={IconCalendarEvent}
soon
matchSubPages
soon={!isCalendarEnabled}
/>
</NavigationDrawerItemGroup>
)}
</NavigationDrawerSection>

<NavigationDrawerSection>
<NavigationDrawerSectionTitle label="Workspace" />
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="General"
to="/settings/workspace"
path={SettingsPath.Workspace}
Icon={IconSettings}
active={
!!useMatch({
path: useResolvedPath('/settings/workspace').pathname,
end: true,
})
}
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Members"
to="/settings/workspace-members"
path={SettingsPath.WorkspaceMembersPage}
Icon={IconUsers}
active={
!!useMatch({
path: useResolvedPath('/settings/workspace-members').pathname,
end: true,
})
}
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Data model"
to="/settings/objects"
path={SettingsPath.Objects}
Icon={IconHierarchy2}
active={
!!useMatch({
path: useResolvedPath('/settings/objects').pathname,
end: false,
})
}
matchSubPages
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Developers"
to="/settings/developers"
path={SettingsPath.Developers}
Icon={IconRobot}
active={
!!useMatch({
path: useResolvedPath('/settings/developers').pathname,
end: true,
})
}
/>
<NavigationDrawerItem
<SettingsNavigationDrawerItem
label="Integrations"
to="/settings/integrations"
path={SettingsPath.Integrations}
Icon={IconApps}
active={isIntegrationsItemActive}
/>
</NavigationDrawerSection>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { SettingsPath } from '@/types/SettingsPath';

export const getSettingsPagePath = <Path extends SettingsPath>(path: Path) =>
`/settings/${path}` as const;
3 changes: 2 additions & 1 deletion packages/twenty-front/src/modules/types/SettingsPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export enum SettingsPath {
Appearance = 'profile/appearance',
Accounts = 'accounts',
NewAccount = 'accounts/new',
AccountsCalendars = 'accounts/calendars',
AccountsEmails = 'accounts/emails',
AccountsEmailsInboxSettings = 'accounts/emails/:accountUuid',
Objects = 'objects',
Expand All @@ -14,7 +15,7 @@ export enum SettingsPath {
NewObject = 'objects/new',
WorkspaceMembersPage = 'workspace-members',
Workspace = 'workspace',
Developers = '',
Developers = 'developers',
DevelopersNewApiKey = 'api-keys/new',
DevelopersApiKeyDetail = 'api-keys/:apiKeyId',
Integrations = 'integrations',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigation
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';

type NavigationDrawerItemProps = {
export type NavigationDrawerItemProps = {
className?: string;
label: string;
level?: 1 | 2;
Expand Down
Loading
Loading