Migrate tab list to scope map (#3333)
* Migrate tab list to scope map * Return state to hook and let client subscribe to state * Run prettier --------- Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
@ -1,16 +1,15 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
|
||||
import { useTasks } from '@/activities/tasks/hooks/useTasks';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { IconPlus } from '@/ui/display/icon';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { activeTabIdScopedState } from '@/ui/layout/tab/states/activeTabIdScopedState';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { AddTaskButton } from './AddTaskButton';
|
||||
import { TaskList } from './TaskList';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledTaskGroupEmptyContainer = styled.div`
|
||||
align-items: center;
|
||||
@ -69,10 +68,8 @@ export const TaskGroups = ({
|
||||
|
||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||
|
||||
const [activeTabId] = useRecoilScopedState(
|
||||
activeTabIdScopedState,
|
||||
TasksRecoilScopeContext,
|
||||
);
|
||||
const { activeTabIdState } = useTabList('task-groups-tab-list');
|
||||
const activeTabId = useRecoilValue(activeTabIdState);
|
||||
|
||||
if (
|
||||
(activeTabId !== 'done' &&
|
||||
|
||||
@ -15,12 +15,11 @@ import {
|
||||
IconTimelineEvent,
|
||||
} from '@/ui/display/icon';
|
||||
import { TabList } from '@/ui/layout/tab/components/TabList';
|
||||
import { activeTabIdScopedState } from '@/ui/layout/tab/states/activeTabIdScopedState';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
|
||||
import { ShowPageRecoilScopeContext } from '../../states/ShowPageRecoilScopeContext';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledShowPageRightContainer = styled.div`
|
||||
display: flex;
|
||||
@ -40,6 +39,8 @@ const StyledTabListContainer = styled.div`
|
||||
height: 40px;
|
||||
`;
|
||||
|
||||
const TAB_LIST_COMPONENT_ID = 'show-page-right-tab-list';
|
||||
|
||||
type ShowPageRightContainerProps = {
|
||||
targetableObject?: ActivityTargetableObject;
|
||||
timeline?: boolean;
|
||||
@ -56,10 +57,9 @@ export const ShowPageRightContainer = ({
|
||||
emails,
|
||||
}: ShowPageRightContainerProps) => {
|
||||
const isMessagingEnabled = useIsFeatureEnabled('IS_MESSAGING_ENABLED');
|
||||
const [activeTabId] = useRecoilScopedState(
|
||||
activeTabIdScopedState,
|
||||
ShowPageRecoilScopeContext,
|
||||
);
|
||||
|
||||
const { activeTabIdState } = useTabList(TAB_LIST_COMPONENT_ID);
|
||||
const activeTabId = useRecoilValue(activeTabIdState);
|
||||
|
||||
if (!targetableObject) return <></>;
|
||||
|
||||
@ -105,7 +105,7 @@ export const ShowPageRightContainer = ({
|
||||
return (
|
||||
<StyledShowPageRightContainer>
|
||||
<StyledTabListContainer>
|
||||
<TabList context={ShowPageRecoilScopeContext} tabs={TASK_TABS} />
|
||||
<TabList tabListId={TAB_LIST_COMPONENT_ID} tabs={TASK_TABS} />
|
||||
</StyledTabListContainer>
|
||||
{activeTabId === 'timeline' && (
|
||||
<Timeline targetableObject={targetableObject} />
|
||||
|
||||
@ -2,11 +2,11 @@ import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { activeTabIdScopedState } from '../states/activeTabIdScopedState';
|
||||
|
||||
import { Tab } from './Tab';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { TabListScope } from '@/ui/layout/tab/scopes/TabListScope';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
type SingleTabProps = {
|
||||
title: string;
|
||||
@ -17,8 +17,8 @@ type SingleTabProps = {
|
||||
};
|
||||
|
||||
type TabListProps = {
|
||||
tabListId: string;
|
||||
tabs: SingleTabProps[];
|
||||
context: React.Context<string | null>;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -31,35 +31,36 @@ const StyledContainer = styled.div`
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
export const TabList = ({ tabs, context }: TabListProps) => {
|
||||
export const TabList = ({ tabs, tabListId }: TabListProps) => {
|
||||
const initialActiveTabId = tabs[0].id;
|
||||
|
||||
const [activeTabId, setActiveTabId] = useRecoilScopedState(
|
||||
activeTabIdScopedState,
|
||||
context,
|
||||
);
|
||||
const { activeTabIdState, setActiveTabId } = useTabList(tabListId);
|
||||
|
||||
const activeTabId = useRecoilValue(activeTabIdState);
|
||||
|
||||
React.useEffect(() => {
|
||||
setActiveTabId(initialActiveTabId);
|
||||
}, [initialActiveTabId, setActiveTabId]);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
{tabs
|
||||
.filter((tab) => !tab.hide)
|
||||
.map((tab) => (
|
||||
<Tab
|
||||
id={tab.id}
|
||||
key={tab.id}
|
||||
title={tab.title}
|
||||
Icon={tab.Icon}
|
||||
active={tab.id === activeTabId}
|
||||
onClick={() => {
|
||||
setActiveTabId(tab.id);
|
||||
}}
|
||||
disabled={tab.disabled}
|
||||
/>
|
||||
))}
|
||||
</StyledContainer>
|
||||
<TabListScope tabListScopeId={tabListId}>
|
||||
<StyledContainer>
|
||||
{tabs
|
||||
.filter((tab) => !tab.hide)
|
||||
.map((tab) => (
|
||||
<Tab
|
||||
id={tab.id}
|
||||
key={tab.id}
|
||||
title={tab.title}
|
||||
Icon={tab.Icon}
|
||||
active={tab.id === activeTabId}
|
||||
onClick={() => {
|
||||
setActiveTabId(tab.id);
|
||||
}}
|
||||
disabled={tab.disabled}
|
||||
/>
|
||||
))}
|
||||
</StyledContainer>
|
||||
</TabListScope>
|
||||
);
|
||||
};
|
||||
|
||||
@ -40,6 +40,7 @@ const meta: Meta<typeof TabList> = {
|
||||
title: 'UI/Layout/Tab/TabList',
|
||||
component: TabList,
|
||||
args: {
|
||||
tabListId: 'tab-list-id',
|
||||
tabs: tabs,
|
||||
},
|
||||
decorators: [
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
import { TabListScopeInternalContext } from '@/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext';
|
||||
import { activeTabIdStateScopeMap } from '@/ui/layout/tab/states/activeTabIdStateScopeMap';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { getState } from '@/ui/utilities/recoil-scope/utils/getState';
|
||||
|
||||
type useTabListStatesProps = {
|
||||
tabListScopeId?: string;
|
||||
};
|
||||
|
||||
export const useTabListStates = ({ tabListScopeId }: useTabListStatesProps) => {
|
||||
const scopeId = useAvailableScopeIdOrThrow(
|
||||
TabListScopeInternalContext,
|
||||
tabListScopeId,
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
activeTabIdState: getState(activeTabIdStateScopeMap, scopeId),
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
import { useTabListStates } from '@/ui/layout/tab/hooks/internal/useTabListStates';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
export const useTabList = (tabListId?: string) => {
|
||||
const { activeTabIdState } = useTabListStates({
|
||||
tabListScopeId: `${tabListId}-scope`,
|
||||
});
|
||||
|
||||
const setActiveTabId = useSetRecoilState(activeTabIdState);
|
||||
|
||||
return {
|
||||
activeTabIdState,
|
||||
setActiveTabId,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { TabListScopeInternalContext } from './scope-internal-context/TabListScopeInternalContext';
|
||||
|
||||
type TabListScopeProps = {
|
||||
children: ReactNode;
|
||||
tabListScopeId: string;
|
||||
};
|
||||
|
||||
export const TabListScope = ({
|
||||
children,
|
||||
tabListScopeId,
|
||||
}: TabListScopeProps) => {
|
||||
return (
|
||||
<TabListScopeInternalContext.Provider value={{ scopeId: tabListScopeId }}>
|
||||
{children}
|
||||
</TabListScopeInternalContext.Provider>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,7 @@
|
||||
import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey';
|
||||
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
|
||||
|
||||
type TabListScopeInternalContextProps = StateScopeMapKey;
|
||||
|
||||
export const TabListScopeInternalContext =
|
||||
createScopeInternalContext<TabListScopeInternalContextProps>();
|
||||
@ -1,6 +0,0 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
export const activeTabIdScopedState = atomFamily<string | null, string>({
|
||||
key: 'activeTabIdScopedState',
|
||||
default: null,
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||
|
||||
export const activeTabIdStateScopeMap = createStateScopeMap<string | null>({
|
||||
key: 'activeTabIdStateScopeMap',
|
||||
defaultValue: null,
|
||||
});
|
||||
@ -58,7 +58,7 @@ export const Tasks = () => {
|
||||
<TopBar
|
||||
leftComponent={
|
||||
<StyledTabListContainer>
|
||||
<TabList context={TasksRecoilScopeContext} tabs={TASK_TABS} />
|
||||
<TabList tabListId="tasks-tab-list" tabs={TASK_TABS} />
|
||||
</StyledTabListContainer>
|
||||
}
|
||||
rightComponent={
|
||||
|
||||
Reference in New Issue
Block a user