From a8da0e2bc81be1e7b488cf3ad54c5aad393bde51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:40:35 +0200 Subject: [PATCH] 7336 create contextstore (#7374) Closes #7336 Create 3 states: - `contextStoreCurrentObjectMetadataIdState`: is set when we change object metadata - `contextStoreCurrentViewIdState`: is set when we change view - `contextStoreTargetedRecordIdsState`: is set when we select records inside a table or a board or when a show page is opened. Is reset when we change view. --- ...ontextStoreCurrentObjectMetadataIdState.ts | 8 ++++ .../states/contextStoreCurrentViewIdState.ts | 6 +++ .../contextStoreTargetedRecordIdsState.ts | 6 +++ .../RecordIndexBoardDataLoaderEffect.tsx | 25 +++++++++++ .../RecordIndexTableContainerEffect.tsx | 27 +++++++++++- .../components/QueryParamsViewIdEffect.tsx | 13 ++++++ .../src/modules/views/hooks/useChangeView.ts | 12 +----- .../modules/views/hooks/useSetViewInUrl.ts | 15 +++++++ .../pages/object-record/RecordShowPage.tsx | 2 + .../RecordShowPageContextStoreEffect.tsx | 43 +++++++++++++++++++ 10 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts create mode 100644 packages/twenty-front/src/modules/views/hooks/useSetViewInUrl.ts create mode 100644 packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts new file mode 100644 index 0000000000..3227e53807 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts @@ -0,0 +1,8 @@ +import { createState } from 'twenty-ui'; + +export const contextStoreCurrentObjectMetadataIdState = createState< + string | null +>({ + key: 'contextStoreCurrentObjectMetadataIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts new file mode 100644 index 0000000000..41af1cc135 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const contextStoreCurrentViewIdState = createState({ + key: 'contextStoreCurrentViewIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts new file mode 100644 index 0000000000..df0c345117 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordIdsState.ts @@ -0,0 +1,6 @@ +import { createState } from 'twenty-ui'; + +export const contextStoreTargetedRecordIdsState = createState({ + key: 'contextStoreTargetedRecordIdsState', + defaultValue: [], +}); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx index ba3abec91e..c4ad79ed41 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx @@ -2,6 +2,8 @@ import { useCallback, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar'; @@ -129,10 +131,33 @@ export const RecordIndexBoardDataLoaderEffect = ({ callback: resetRecordSelection, }); + const setContextStoreTargetedRecordIds = useSetRecoilState( + contextStoreTargetedRecordIdsState, + ); + + const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( + contextStoreCurrentObjectMetadataIdState, + ); + useEffect(() => { setActionBarEntries?.(); setContextMenuEntries?.(); }, [setActionBarEntries, setContextMenuEntries]); + useEffect(() => { + setContextStoreTargetedRecordIds(selectedRecordIds); + setContextStoreCurrentObjectMetadataItem(objectMetadataItem?.id); + + return () => { + setContextStoreTargetedRecordIds([]); + setContextStoreCurrentObjectMetadataItem(null); + }; + }, [ + objectMetadataItem?.id, + selectedRecordIds, + setContextStoreCurrentObjectMetadataItem, + setContextStoreTargetedRecordIds, + ]); + return <>; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index 428537f694..ce8bb6572d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -1,6 +1,8 @@ import { useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { contextStoreTargetedRecordIdsState } from '@/context-store/states/contextStoreTargetedRecordIdsState'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useRecordActionBar } from '@/object-record/record-action-bar/hooks/useRecordActionBar'; @@ -34,6 +36,14 @@ export const RecordIndexTableContainerEffect = ({ recordTableId, }); + const setContextStoreTargetedRecordIds = useSetRecoilState( + contextStoreTargetedRecordIdsState, + ); + + const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( + contextStoreCurrentObjectMetadataIdState, + ); + const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); @@ -111,5 +121,20 @@ export const RecordIndexTableContainerEffect = ({ ); }, [setRecordCountInCurrentView, setOnEntityCountChange]); + useEffect(() => { + setContextStoreTargetedRecordIds(selectedRowIds); + setContextStoreCurrentObjectMetadataItem(objectMetadataItem?.id); + + return () => { + setContextStoreTargetedRecordIds([]); + setContextStoreCurrentObjectMetadataItem(null); + }; + }, [ + objectMetadataItem?.id, + selectedRowIds, + setContextStoreCurrentObjectMetadataItem, + setContextStoreTargetedRecordIds, + ]); + return <>; }; diff --git a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx index 2ee24d43fd..f306f29bd7 100644 --- a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx @@ -1,3 +1,4 @@ +import { contextStoreCurrentViewIdState } from '@/context-store/states/contextStoreCurrentViewIdState'; import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem'; import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; @@ -7,6 +8,7 @@ import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; import { isUndefined } from '@sniptt/guards'; import { useEffect } from 'react'; +import { useSetRecoilState } from 'recoil'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDefined } from '~/utils/isDefined'; @@ -37,6 +39,9 @@ export const QueryParamsViewIdEffect = () => { objectMetadataItemId?.id, lastVisitedObjectMetadataItemId, ); + const setContextStoreCurrentViewId = useSetRecoilState( + contextStoreCurrentViewIdState, + ); // // TODO: scope view bar per view id if possible // const { resetCurrentView } = useResetCurrentView(); @@ -59,6 +64,7 @@ export const QueryParamsViewIdEffect = () => { }); } setCurrentViewId(lastVisitedViewId); + setContextStoreCurrentViewId(lastVisitedViewId); return; } @@ -73,6 +79,7 @@ export const QueryParamsViewIdEffect = () => { }); } setCurrentViewId(viewIdQueryParam); + setContextStoreCurrentViewId(viewIdQueryParam); return; } @@ -87,8 +94,13 @@ export const QueryParamsViewIdEffect = () => { }); } setCurrentViewId(indexView.id); + setContextStoreCurrentViewId(indexView.id); return; } + + return () => { + setContextStoreCurrentViewId(null); + }; }, [ currentViewId, getFiltersFromQueryParams, @@ -96,6 +108,7 @@ export const QueryParamsViewIdEffect = () => { lastVisitedViewId, objectMetadataItemId?.id, objectNamePlural, + setContextStoreCurrentViewId, setCurrentViewId, setLastVisitedObjectMetadataItem, setLastVisitedView, diff --git a/packages/twenty-front/src/modules/views/hooks/useChangeView.ts b/packages/twenty-front/src/modules/views/hooks/useChangeView.ts index 669de5157b..9ed9aeeff4 100644 --- a/packages/twenty-front/src/modules/views/hooks/useChangeView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useChangeView.ts @@ -1,19 +1,11 @@ import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates'; -import { useSearchParams } from 'react-router-dom'; +import { useSetViewInUrl } from '@/views/hooks/useSetViewInUrl'; export const useChangeView = (viewBarComponentId?: string) => { const { resetUnsavedViewStates } = useResetUnsavedViewStates(viewBarComponentId); - const [, setSearchParams] = useSearchParams(); - - const setViewInUrl = (viewId: string) => { - setSearchParams(() => { - const searchParams = new URLSearchParams(); - searchParams.set('view', viewId); - return searchParams; - }); - }; + const { setViewInUrl } = useSetViewInUrl(); const changeView = async (viewId: string) => { setViewInUrl(viewId); diff --git a/packages/twenty-front/src/modules/views/hooks/useSetViewInUrl.ts b/packages/twenty-front/src/modules/views/hooks/useSetViewInUrl.ts new file mode 100644 index 0000000000..01e0397ffd --- /dev/null +++ b/packages/twenty-front/src/modules/views/hooks/useSetViewInUrl.ts @@ -0,0 +1,15 @@ +import { useSearchParams } from 'react-router-dom'; + +export const useSetViewInUrl = () => { + const [, setSearchParams] = useSearchParams(); + + const setViewInUrl = (viewId: string) => { + setSearchParams(() => { + const searchParams = new URLSearchParams(); + searchParams.set('view', viewId); + return searchParams; + }); + }; + + return { setViewInUrl }; +}; diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index 09a3d14b91..0ecb2cb569 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -12,6 +12,7 @@ import { PageTitle } from '@/ui/utilities/page-title/PageTitle'; import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader'; import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader'; import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader'; +import { RecordShowPageContextStoreEffect } from '~/pages/object-record/RecordShowPageContextStoreEffect'; import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader'; export const RecordShowPage = () => { @@ -39,6 +40,7 @@ export const RecordShowPage = () => { return ( + { + const setContextStoreTargetedRecordIds = useSetRecoilState( + contextStoreTargetedRecordIdsState, + ); + + const setContextStoreCurrentObjectMetadataId = useSetRecoilState( + contextStoreCurrentObjectMetadataIdState, + ); + + const { objectNameSingular } = useParams(); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: objectNameSingular ?? '', + }); + + useEffect(() => { + setContextStoreTargetedRecordIds([recordId]); + setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id); + + return () => { + setContextStoreTargetedRecordIds([]); + setContextStoreCurrentObjectMetadataId(null); + }; + }, [ + recordId, + setContextStoreTargetedRecordIds, + setContextStoreCurrentObjectMetadataId, + objectMetadataItem?.id, + ]); + + return null; +};