refactor(auth): add workspaces selection (#12098)
This commit is contained in:
@ -2,7 +2,6 @@ import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/consta
|
||||
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { Workspaces, workspacesState } from '@/auth/states/workspaces';
|
||||
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
@ -37,9 +36,14 @@ import {
|
||||
MenuItemSelectAvatar,
|
||||
UndecoratedLink,
|
||||
} from 'twenty-ui/navigation';
|
||||
import { useSignUpInNewWorkspaceMutation } from '~/generated/graphql';
|
||||
import {
|
||||
useSignUpInNewWorkspaceMutation,
|
||||
AvailableWorkspace,
|
||||
} from '~/generated/graphql';
|
||||
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
import { countAvailableWorkspaces } from '@/auth/utils/availableWorkspacesUtils';
|
||||
|
||||
const StyledDescription = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
@ -50,7 +54,9 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const { t } = useLingui();
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
const workspaces = useRecoilValue(workspacesState);
|
||||
const availableWorkspaces = useRecoilValue(availableWorkspacesState);
|
||||
const availableWorkspacesCount =
|
||||
countAvailableWorkspaces(availableWorkspaces);
|
||||
const { buildWorkspaceUrl } = useBuildWorkspaceUrl();
|
||||
const { closeDropdown } = useDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
const { signOut } = useAuth();
|
||||
@ -63,8 +69,10 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
multiWorkspaceDropdownState,
|
||||
);
|
||||
|
||||
const handleChange = async (workspace: Workspaces[0]) => {
|
||||
redirectToWorkspaceDomain(getWorkspaceUrl(workspace.workspaceUrls));
|
||||
const handleChange = async (availableWorkspace: AvailableWorkspace) => {
|
||||
redirectToWorkspaceDomain(
|
||||
getWorkspaceUrl(availableWorkspace.workspaceUrls),
|
||||
);
|
||||
};
|
||||
|
||||
const createWorkspace = () => {
|
||||
@ -127,36 +135,41 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
>
|
||||
{currentWorkspace?.displayName}
|
||||
</DropdownMenuHeader>
|
||||
{workspaces.length > 1 && (
|
||||
{availableWorkspacesCount > 1 && (
|
||||
<>
|
||||
<DropdownMenuItemsContainer>
|
||||
{workspaces
|
||||
{[
|
||||
...availableWorkspaces.availableWorkspacesForSignIn,
|
||||
...availableWorkspaces.availableWorkspacesForSignUp,
|
||||
]
|
||||
.filter(({ id }) => id !== currentWorkspace?.id)
|
||||
.slice(0, 3)
|
||||
.map((workspace) => (
|
||||
.map((availableWorkspace) => (
|
||||
<UndecoratedLink
|
||||
key={workspace.id}
|
||||
key={availableWorkspace.id}
|
||||
to={buildWorkspaceUrl(
|
||||
getWorkspaceUrl(workspace.workspaceUrls),
|
||||
getWorkspaceUrl(availableWorkspace.workspaceUrls),
|
||||
)}
|
||||
onClick={(event) => {
|
||||
event?.preventDefault();
|
||||
handleChange(workspace);
|
||||
handleChange(availableWorkspace);
|
||||
}}
|
||||
>
|
||||
<MenuItemSelectAvatar
|
||||
text={workspace.displayName ?? '(No name)'}
|
||||
text={availableWorkspace.displayName ?? '(No name)'}
|
||||
avatar={
|
||||
<Avatar
|
||||
placeholder={workspace.displayName || ''}
|
||||
avatarUrl={workspace.logo ?? DEFAULT_WORKSPACE_LOGO}
|
||||
placeholder={availableWorkspace.displayName || ''}
|
||||
avatarUrl={
|
||||
availableWorkspace.logo ?? DEFAULT_WORKSPACE_LOGO
|
||||
}
|
||||
/>
|
||||
}
|
||||
selected={false}
|
||||
/>
|
||||
</UndecoratedLink>
|
||||
))}
|
||||
{workspaces.length > 4 && (
|
||||
{availableWorkspacesCount > 4 && (
|
||||
<MenuItem
|
||||
LeftIcon={IconSwitchHorizontal}
|
||||
text={t`Other workspaces`}
|
||||
|
||||
@ -1,32 +1,23 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { Workspaces, workspacesState } from '@/auth/states/workspaces';
|
||||
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceLogo';
|
||||
import { multiWorkspaceDropdownState } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownState';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useState } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { Avatar, IconChevronLeft } from 'twenty-ui/display';
|
||||
import { MenuItemSelectAvatar, UndecoratedLink } from 'twenty-ui/navigation';
|
||||
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
|
||||
import { IconChevronLeft } from 'twenty-ui/display';
|
||||
|
||||
import { WorkspacesForSignIn } from './components/WorkspacesForSignIn';
|
||||
import { WorkspacesForSignUp } from './components/WorkspacesForSignUp';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
|
||||
export const MultiWorkspaceDropdownWorkspacesListComponents = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const workspaces = useRecoilValue(workspacesState);
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
const { buildWorkspaceUrl } = useBuildWorkspaceUrl();
|
||||
const { t } = useLingui();
|
||||
|
||||
const handleChange = async (workspace: Workspaces[0]) => {
|
||||
await redirectToWorkspaceDomain(getWorkspaceUrl(workspace.workspaceUrls));
|
||||
};
|
||||
const availableWorkspaces = useRecoilValue(availableWorkspacesState);
|
||||
|
||||
const setMultiWorkspaceDropdownState = useSetRecoilState(
|
||||
multiWorkspaceDropdownState,
|
||||
);
|
||||
@ -52,37 +43,10 @@ export const MultiWorkspaceDropdownWorkspacesListComponents = () => {
|
||||
}}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer>
|
||||
{workspaces
|
||||
.filter(
|
||||
(workspace) =>
|
||||
workspace.id !== currentWorkspace?.id &&
|
||||
workspace.displayName
|
||||
?.toLowerCase()
|
||||
.includes(searchValue.toLowerCase()),
|
||||
)
|
||||
.map((workspace) => (
|
||||
<UndecoratedLink
|
||||
key={workspace.id}
|
||||
to={buildWorkspaceUrl(getWorkspaceUrl(workspace.workspaceUrls))}
|
||||
onClick={(event) => {
|
||||
event?.preventDefault();
|
||||
handleChange(workspace);
|
||||
}}
|
||||
>
|
||||
<MenuItemSelectAvatar
|
||||
text={workspace.displayName ?? '(No name)'}
|
||||
avatar={
|
||||
<Avatar
|
||||
placeholder={workspace.displayName || ''}
|
||||
avatarUrl={workspace.logo ?? DEFAULT_WORKSPACE_LOGO}
|
||||
/>
|
||||
}
|
||||
selected={currentWorkspace?.id === workspace.id}
|
||||
/>
|
||||
</UndecoratedLink>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
<WorkspacesForSignIn searchValue={searchValue} />
|
||||
{availableWorkspaces.availableWorkspacesForSignUp.length > 0 && (
|
||||
<WorkspacesForSignUp searchValue={searchValue} />
|
||||
)}
|
||||
</DropdownContent>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
import { Avatar } from 'twenty-ui/display';
|
||||
import { MenuItemSelectAvatar, UndecoratedLink } from 'twenty-ui/navigation';
|
||||
import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceLogo';
|
||||
import { AvailableWorkspace } from '~/generated/graphql';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
|
||||
import { getAvailableWorkspacePathAndSearchParams } from '@/auth/utils/availableWorkspacesUtils';
|
||||
import React from 'react';
|
||||
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
||||
|
||||
export const AvailableWorkspaceItem = ({
|
||||
availableWorkspace,
|
||||
isSelected,
|
||||
}: {
|
||||
availableWorkspace: AvailableWorkspace;
|
||||
isSelected: boolean;
|
||||
}) => {
|
||||
const { buildWorkspaceUrl } = useBuildWorkspaceUrl();
|
||||
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
|
||||
const { pathname, searchParams } =
|
||||
getAvailableWorkspacePathAndSearchParams(availableWorkspace);
|
||||
|
||||
const handleChange = async () => {
|
||||
await redirectToWorkspaceDomain(
|
||||
getWorkspaceUrl(availableWorkspace.workspaceUrls),
|
||||
pathname,
|
||||
searchParams,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<UndecoratedLink
|
||||
key={availableWorkspace.id}
|
||||
to={buildWorkspaceUrl(
|
||||
getWorkspaceUrl(availableWorkspace.workspaceUrls),
|
||||
pathname,
|
||||
searchParams,
|
||||
)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
handleChange();
|
||||
}}
|
||||
>
|
||||
<MenuItemSelectAvatar
|
||||
text={availableWorkspace.displayName ?? '(No name)'}
|
||||
avatar={
|
||||
<Avatar
|
||||
placeholder={availableWorkspace.displayName || ''}
|
||||
avatarUrl={availableWorkspace.logo ?? DEFAULT_WORKSPACE_LOGO}
|
||||
/>
|
||||
}
|
||||
selected={isSelected}
|
||||
/>
|
||||
</UndecoratedLink>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { StyledDropdownMenuSubheader } from '@/ui/layout/dropdown/components/StyledDropdownMenuSubheader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useFilteredAvailableWorkspaces } from '@/ui/navigation/navigation-drawer/hooks/useFilteredAvailableWorkspaces';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
import { AvailableWorkspaceItem } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/AvailableWorkspaceItem';
|
||||
|
||||
export const WorkspacesForSignIn = ({
|
||||
searchValue,
|
||||
}: {
|
||||
searchValue: string;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const availableWorkspaces = useRecoilValue(availableWorkspacesState);
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const { searchAvailableWorkspaces } = useFilteredAvailableWorkspaces();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledDropdownMenuSubheader>{t`Member of`}</StyledDropdownMenuSubheader>
|
||||
<DropdownMenuItemsContainer>
|
||||
{searchAvailableWorkspaces(
|
||||
searchValue,
|
||||
availableWorkspaces.availableWorkspacesForSignIn,
|
||||
).map((availableWorkspace) => (
|
||||
<AvailableWorkspaceItem
|
||||
key={availableWorkspace.id}
|
||||
availableWorkspace={availableWorkspace}
|
||||
isSelected={currentWorkspace?.id === availableWorkspace.id}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { StyledDropdownMenuSubheader } from '@/ui/layout/dropdown/components/StyledDropdownMenuSubheader';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useFilteredAvailableWorkspaces } from '@/ui/navigation/navigation-drawer/hooks/useFilteredAvailableWorkspaces';
|
||||
import { AvailableWorkspaceItem } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/internal/components/AvailableWorkspaceItem';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const WorkspacesForSignUp = ({
|
||||
searchValue,
|
||||
}: {
|
||||
searchValue: string;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const availableWorkspaces = useRecoilValue(availableWorkspacesState);
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const { searchAvailableWorkspaces } = useFilteredAvailableWorkspaces();
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledDropdownMenuSubheader>{t`Invitations`}</StyledDropdownMenuSubheader>
|
||||
<DropdownMenuItemsContainer scrollable={false}>
|
||||
{searchAvailableWorkspaces(
|
||||
searchValue,
|
||||
availableWorkspaces.availableWorkspacesForSignUp,
|
||||
).map((availableWorkspace) => (
|
||||
<AvailableWorkspaceItem
|
||||
key={availableWorkspace.id}
|
||||
availableWorkspace={availableWorkspace}
|
||||
isSelected={currentWorkspace?.id === availableWorkspace.id}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { AvailableWorkspace } from '~/generated/graphql';
|
||||
|
||||
export const useFilteredAvailableWorkspaces = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const searchAvailableWorkspaces = (
|
||||
searchValue: string,
|
||||
availableWorkspaces: Array<AvailableWorkspace>,
|
||||
) => {
|
||||
return availableWorkspaces.filter(
|
||||
(availableWorkspace) =>
|
||||
currentWorkspace?.id &&
|
||||
availableWorkspace.id !== currentWorkspace.id &&
|
||||
availableWorkspace.displayName
|
||||
?.toLowerCase()
|
||||
.includes(searchValue.toLowerCase()),
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
searchAvailableWorkspaces,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user