Simplify last visited (#10259)
In this PR, I'm simplifying the lastVisitedView / Object logic: - removing fallback logic as it's not useful - splitting hooks into smaller hooks (to avoir re-renders) - removing componentState on those states that are global
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
@ -16,8 +16,9 @@ export const useDefaultHomePagePath = () => {
|
||||
const { activeObjectMetadataItems, alphaSortedActiveObjectMetadataItems } =
|
||||
useFilteredObjectMetadataItems();
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const { lastVisitedObjectMetadataItemId } =
|
||||
useLastVisitedObjectMetadataItem();
|
||||
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
||||
lastVisitedObjectMetadataItemIdState,
|
||||
);
|
||||
|
||||
const getActiveObjectMetadataItemMatchingId = useCallback(
|
||||
(objectMetadataId: string) => {
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { lastVisitedObjectMetadataItemIdStateSelector } from '@/navigation/states/selectors/lastVisitedObjectMetadataItemIdStateSelector';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||
|
||||
export const useLastVisitedObjectMetadataItem = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const scopeId = currentWorkspace?.id ?? '';
|
||||
|
||||
const lastVisitedObjectMetadataItemIdState = extractComponentState(
|
||||
lastVisitedObjectMetadataItemIdStateSelector,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
const [lastVisitedObjectMetadataItemId, setLastVisitedObjectMetadataItemId] =
|
||||
useRecoilState(lastVisitedObjectMetadataItemIdState);
|
||||
|
||||
const {
|
||||
findActiveObjectMetadataItemByNamePlural,
|
||||
alphaSortedActiveObjectMetadataItems,
|
||||
} = useFilteredObjectMetadataItems();
|
||||
|
||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
|
||||
const setFallbackForLastVisitedObjectMetadataItem = (
|
||||
objectMetadataItemId: string,
|
||||
) => {
|
||||
const isDeactivateDefault = isDeeplyEqual(
|
||||
lastVisitedObjectMetadataItemId,
|
||||
objectMetadataItemId,
|
||||
);
|
||||
|
||||
const [newFallbackObjectMetadataItem] =
|
||||
alphaSortedActiveObjectMetadataItems.filter(
|
||||
(item) => item.id !== objectMetadataItemId,
|
||||
);
|
||||
|
||||
if (isDeactivateDefault) {
|
||||
setLastVisitedObjectMetadataItemId(newFallbackObjectMetadataItem.id);
|
||||
setNavigationMemorizedUrl(
|
||||
getAppPath(AppPath.RecordIndexPage, {
|
||||
objectNamePlural: newFallbackObjectMetadataItem.namePlural,
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const setLastVisitedObjectMetadataItem = (objectNamePlural: string) => {
|
||||
const fallbackObjectMetadataItem =
|
||||
findActiveObjectMetadataItemByNamePlural(objectNamePlural);
|
||||
|
||||
if (isDefined(fallbackObjectMetadataItem)) {
|
||||
setLastVisitedObjectMetadataItemId(fallbackObjectMetadataItem.id);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
lastVisitedObjectMetadataItemId,
|
||||
setLastVisitedObjectMetadataItem,
|
||||
setFallbackForLastVisitedObjectMetadataItem,
|
||||
};
|
||||
};
|
||||
@ -1,54 +1,15 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { lastVisitedViewPerObjectMetadataItemStateSelector } from '@/navigation/states/selectors/lastVisitedViewPerObjectMetadataItemStateSelector';
|
||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useLastVisitedView = () => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const scopeId = currentWorkspace?.id ?? '';
|
||||
|
||||
const lastVisitedViewPerObjectMetadataItemState = extractComponentState(
|
||||
lastVisitedViewPerObjectMetadataItemStateSelector,
|
||||
scopeId,
|
||||
const lastVisitedViewPerObjectMetadataItem = useRecoilValue(
|
||||
lastVisitedViewPerObjectMetadataItemState,
|
||||
);
|
||||
|
||||
const [
|
||||
lastVisitedViewPerObjectMetadataItem,
|
||||
setLastVisitedViewPerObjectMetadataItem,
|
||||
] = useRecoilState(lastVisitedViewPerObjectMetadataItemState);
|
||||
|
||||
const { findActiveObjectMetadataItemByNamePlural } =
|
||||
useFilteredObjectMetadataItems();
|
||||
|
||||
const setFallbackForLastVisitedView = (objectMetadataItemId: string) => {
|
||||
/* ...{} allows us to pass value as undefined to remove that particular key
|
||||
even though param type is of type Record<string,string> */
|
||||
|
||||
setLastVisitedViewPerObjectMetadataItem({
|
||||
...{},
|
||||
[objectMetadataItemId]: undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const setLastVisitedView = ({
|
||||
objectNamePlural,
|
||||
viewId,
|
||||
}: {
|
||||
objectNamePlural: string;
|
||||
viewId: string;
|
||||
}) => {
|
||||
const objectMetadataItem =
|
||||
findActiveObjectMetadataItemByNamePlural(objectNamePlural);
|
||||
|
||||
if (isDefined(objectMetadataItem)) {
|
||||
setLastVisitedViewPerObjectMetadataItem({
|
||||
[objectMetadataItem.id]: viewId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getLastVisitedViewIdFromObjectNamePlural = (
|
||||
objectNamePlural: string,
|
||||
) => {
|
||||
@ -65,9 +26,7 @@ export const useLastVisitedView = () => {
|
||||
return lastVisitedViewPerObjectMetadataItem?.[objectMetadataItemId];
|
||||
};
|
||||
return {
|
||||
setLastVisitedView,
|
||||
getLastVisitedViewIdFromObjectNamePlural,
|
||||
getLastVisitedViewIdFromObjectMetadataItemId,
|
||||
setFallbackForLastVisitedView,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
export const useOpenSettingsMenu = () => {
|
||||
const [, setIsNavigationDrawerExpanded] = useRecoilState(
|
||||
const setIsNavigationDrawerExpanded = useSetRecoilState(
|
||||
isNavigationDrawerExpandedState,
|
||||
);
|
||||
const [, setCurrentMobileNavigationDrawer] = useRecoilState(
|
||||
const setCurrentMobileNavigationDrawer = useSetRecoilState(
|
||||
currentMobileNavigationDrawerState,
|
||||
);
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useSetLastVisitedObjectMetadataId = () => {
|
||||
const setLastVisitedObjectMetadataId = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
({ objectMetadataItemId }: { objectMetadataItemId: string }) => {
|
||||
const objectMetadataItems = snapshot
|
||||
.getLoadable(objectMetadataItemsState)
|
||||
.getValue();
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.id === objectMetadataItemId,
|
||||
);
|
||||
|
||||
const lastVisitedObjectMetadataItemId = snapshot
|
||||
.getLoadable(lastVisitedObjectMetadataItemIdState)
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
isDefined(objectMetadataItem) &&
|
||||
lastVisitedObjectMetadataItemId !== objectMetadataItemId
|
||||
) {
|
||||
set(lastVisitedObjectMetadataItemIdState, objectMetadataItemId);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
setLastVisitedObjectMetadataId,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,63 @@
|
||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useLazyPrefetchedData } from '@/prefetch/hooks/useLazyPrefetchData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { View } from '@/views/types/View';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
const { records: views, findManyRecords } = useLazyPrefetchedData<View>(
|
||||
PrefetchKey.AllViews,
|
||||
);
|
||||
|
||||
const setLastVisitedViewForObjectMetadataNamePlural = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
async ({
|
||||
objectNamePlural,
|
||||
viewId,
|
||||
}: {
|
||||
objectNamePlural: string;
|
||||
viewId: string;
|
||||
}) => {
|
||||
await findManyRecords();
|
||||
|
||||
const view = views.find((view: View) => view.id === viewId);
|
||||
|
||||
const objectMetadataItems = snapshot
|
||||
.getLoadable(objectMetadataItemsState)
|
||||
.getValue();
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.namePlural === objectNamePlural,
|
||||
);
|
||||
|
||||
if (!isDefined(objectMetadataItem) || !isDefined(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.objectMetadataId !== objectMetadataItem.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastVisitedViewPerObjectMetadataItem = snapshot
|
||||
.getLoadable(lastVisitedViewPerObjectMetadataItemState)
|
||||
.getValue();
|
||||
|
||||
const lastVisitedViewId =
|
||||
lastVisitedViewPerObjectMetadataItem?.[objectMetadataItem?.id];
|
||||
|
||||
if (isDefined(objectMetadataItem) && lastVisitedViewId !== viewId) {
|
||||
set(lastVisitedViewPerObjectMetadataItemState, {
|
||||
...lastVisitedViewPerObjectMetadataItem,
|
||||
[objectMetadataItem.id]: viewId,
|
||||
});
|
||||
}
|
||||
},
|
||||
[findManyRecords, views],
|
||||
);
|
||||
|
||||
return {
|
||||
setLastVisitedViewForObjectMetadataNamePlural,
|
||||
};
|
||||
};
|
||||
@ -1,10 +1,7 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { createState } from 'twenty-ui';
|
||||
import { localStorageEffect } from '~/utils/recoil-effects';
|
||||
|
||||
export const lastVisitedObjectMetadataItemIdState = createComponentState<Record<
|
||||
string,
|
||||
string
|
||||
> | null>({
|
||||
export const lastVisitedObjectMetadataItemIdState = createState<string | null>({
|
||||
key: 'lastVisitedObjectMetadataItemIdState',
|
||||
defaultValue: null,
|
||||
effects: [localStorageEffect()],
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { createState } from 'twenty-ui';
|
||||
import { localStorageEffect } from '~/utils/recoil-effects';
|
||||
|
||||
export const lastVisitedViewPerObjectMetadataItemState =
|
||||
createComponentState<Record<string, string> | null>({
|
||||
key: 'lastVisitedViewPerObjectMetadataItemState',
|
||||
defaultValue: null,
|
||||
effects: [localStorageEffect()],
|
||||
});
|
||||
export const lastVisitedViewPerObjectMetadataItemState = createState<Record<
|
||||
string,
|
||||
string
|
||||
> | null>({
|
||||
key: 'lastVisitedViewPerObjectMetadataItemState',
|
||||
defaultValue: null,
|
||||
effects: [localStorageEffect()],
|
||||
});
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
|
||||
|
||||
export const lastVisitedObjectMetadataItemIdStateSelector =
|
||||
createComponentSelector<string | null>({
|
||||
key: 'lastVisitedObjectMetadataItemIdStateSelector',
|
||||
get:
|
||||
({ scopeId }: { scopeId: string }) =>
|
||||
({ get }) => {
|
||||
const state = get(lastVisitedObjectMetadataItemIdState({ scopeId }));
|
||||
return state?.['last_visited_object']
|
||||
? state['last_visited_object']
|
||||
: null;
|
||||
},
|
||||
set:
|
||||
({ scopeId }: { scopeId: string }) =>
|
||||
({ set }, newValue) => {
|
||||
set(lastVisitedObjectMetadataItemIdState({ scopeId }), {
|
||||
...(typeof newValue === 'string' && {
|
||||
last_visited_object: newValue,
|
||||
}),
|
||||
});
|
||||
},
|
||||
});
|
||||
@ -1,34 +0,0 @@
|
||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const lastVisitedViewPerObjectMetadataItemStateSelector =
|
||||
createComponentSelector<Record<string, string> | null>({
|
||||
key: 'lastVisitedViewPerObjectMetadataItemStateSelector',
|
||||
get:
|
||||
({ scopeId }: { scopeId: string }) =>
|
||||
({ get }) => {
|
||||
const state = get(
|
||||
lastVisitedViewPerObjectMetadataItemState({ scopeId }),
|
||||
);
|
||||
|
||||
if (isDefined(state?.['last_visited_object'])) {
|
||||
const { last_visited_object: _last_visited_object, ...rest } = state;
|
||||
return rest;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
set:
|
||||
({ scopeId }: { scopeId: string }) =>
|
||||
({ set, get }, newValue) => {
|
||||
const currentLastVisitedViewPerObjectMetadataItems = get(
|
||||
lastVisitedViewPerObjectMetadataItemStateSelector({ scopeId }),
|
||||
);
|
||||
|
||||
set(lastVisitedViewPerObjectMetadataItemState({ scopeId }), {
|
||||
...currentLastVisitedViewPerObjectMetadataItems,
|
||||
...newValue,
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user