Feat/activity optimistic activities (#4009)
* Fix naming * Fixed cache.evict bug for relation target deletion * Fixed cascade delete activity targets * Working version * Fix * fix * WIP * Fixed optimistic effect target inline cell * Removed openCreateActivityDrawer v1 * Ok for timeline * Removed console.log * Fix update record optimistic effect * Refactored activity queries into useActivities for everything * Fixed bugs * Cleaned * Fix lint --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,7 +1,11 @@
|
||||
import { useEffect } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useActivities } from '@/activities/hooks/useActivities';
|
||||
import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup';
|
||||
import { useTimelineActivities } from '@/activities/timeline/hooks/useTimelineActivities';
|
||||
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY';
|
||||
import { timelineTargetableObjectState } from '@/activities/timeline/states/timelineTargetableObjectState';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
|
||||
import {
|
||||
@ -11,6 +15,7 @@ import {
|
||||
AnimatedPlaceholderEmptyTitle,
|
||||
} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { TimelineItemsContainer } from './TimelineItemsContainer';
|
||||
|
||||
@ -31,11 +36,22 @@ export const Timeline = ({
|
||||
}: {
|
||||
targetableObject: ActivityTargetableObject;
|
||||
}) => {
|
||||
const { activities, initialized } = useTimelineActivities({
|
||||
targetableObject,
|
||||
const { activities, initialized, noActivities } = useActivities({
|
||||
targetableObjects: [targetableObject],
|
||||
activitiesFilters: {},
|
||||
activitiesOrderByVariables: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
|
||||
skip: !isDefined(targetableObject),
|
||||
});
|
||||
|
||||
const showEmptyState = initialized && activities.length === 0;
|
||||
const setTimelineTargetableObject = useSetRecoilState(
|
||||
timelineTargetableObjectState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setTimelineTargetableObject(targetableObject);
|
||||
}, [targetableObject, setTimelineTargetableObject]);
|
||||
|
||||
const showEmptyState = noActivities;
|
||||
|
||||
const showLoadingState = !initialized;
|
||||
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { Tooltip } from 'react-tooltip';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { IconCheckbox, IconNotes } from '@/ui/display/icon';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { Avatar } from '@/users/components/Avatar';
|
||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
import {
|
||||
beautifyExactDateTime,
|
||||
beautifyPastDateRelativeToNow,
|
||||
@ -135,19 +136,7 @@ const StyledTimelineItemContainer = styled.div<{ isGap?: boolean }>`
|
||||
`;
|
||||
|
||||
type TimelineActivityProps = {
|
||||
activity: Pick<
|
||||
Activity,
|
||||
| 'id'
|
||||
| 'title'
|
||||
| 'body'
|
||||
| 'createdAt'
|
||||
| 'completedAt'
|
||||
| 'type'
|
||||
| 'comments'
|
||||
| 'dueAt'
|
||||
> & { author?: Pick<WorkspaceMember, 'name' | 'avatarUrl'> } & {
|
||||
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
};
|
||||
activity: Activity;
|
||||
isLastActivity?: boolean;
|
||||
};
|
||||
|
||||
@ -160,6 +149,8 @@ export const TimelineActivity = ({
|
||||
const openActivityRightDrawer = useOpenActivityRightDrawer();
|
||||
const theme = useTheme();
|
||||
|
||||
const activityFromStore = useRecoilValue(recordStoreFamilyState(activity.id));
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledTimelineItemContainer>
|
||||
@ -191,11 +182,13 @@ export const TimelineActivity = ({
|
||||
</StyledIconContainer>
|
||||
{(activity.type === 'Note' || activity.type === 'Task') && (
|
||||
<StyledActivityTitle
|
||||
onClick={() => openActivityRightDrawer(activity.id)}
|
||||
onClick={() => openActivityRightDrawer(activity)}
|
||||
>
|
||||
“
|
||||
<StyledActivityLink title={activity.title ?? '(No Title)'}>
|
||||
{activity.title ?? '(No Title)'}
|
||||
<StyledActivityLink
|
||||
title={activityFromStore?.title ?? '(No Title)'}
|
||||
>
|
||||
{activityFromStore?.title ?? '(No Title)'}
|
||||
</StyledActivityLink>
|
||||
“
|
||||
</StyledActivityTitle>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { Button, ButtonGroup } from 'tsup.ui.index';
|
||||
|
||||
import { useOpenCreateActivityDrawerV2 } from '@/activities/hooks/useOpenCreateActivityDrawerV2';
|
||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import {
|
||||
IconCheckbox,
|
||||
@ -19,7 +19,7 @@ export const TimelineCreateButtonGroup = ({
|
||||
const { getActiveTabIdState } = useTabList(TAB_LIST_COMPONENT_ID);
|
||||
const setActiveTabId = useSetRecoilState(getActiveTabIdState());
|
||||
|
||||
const openCreateActivity = useOpenCreateActivityDrawerV2();
|
||||
const openCreateActivity = useOpenCreateActivityDrawer();
|
||||
|
||||
return (
|
||||
<ButtonGroup variant={'secondary'}>
|
||||
@ -30,7 +30,6 @@ export const TimelineCreateButtonGroup = ({
|
||||
openCreateActivity({
|
||||
type: 'Note',
|
||||
targetableObjects: [targetableObject],
|
||||
timelineTargetableObject: targetableObject,
|
||||
})
|
||||
}
|
||||
/>
|
||||
@ -41,7 +40,6 @@ export const TimelineCreateButtonGroup = ({
|
||||
openCreateActivity({
|
||||
type: 'Task',
|
||||
targetableObjects: [targetableObject],
|
||||
timelineTargetableObject: targetableObject,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
import { OrderByField } from '@/object-metadata/types/OrderByField';
|
||||
|
||||
export const FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY: OrderByField = {
|
||||
createdAt: 'DescNullsFirst',
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
import { useInjectIntoActivitiesQuery } from '@/activities/hooks/useInjectIntoActivitiesQuery';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
|
||||
export const useInjectIntoTimelineActivitiesQueries = () => {
|
||||
const { injectActivitiesQueries } = useInjectIntoActivitiesQuery();
|
||||
|
||||
const injectIntoTimelineActivitiesQueries = ({
|
||||
activityToInject,
|
||||
activityTargetsToInject,
|
||||
timelineTargetableObject,
|
||||
}: {
|
||||
activityToInject: Activity;
|
||||
activityTargetsToInject: ActivityTarget[];
|
||||
timelineTargetableObject: ActivityTargetableObject;
|
||||
}) => {
|
||||
injectActivitiesQueries({
|
||||
activitiesFilters: {},
|
||||
activitiesOrderByVariables: {
|
||||
createdAt: 'DescNullsFirst',
|
||||
},
|
||||
activityTargetsToInject,
|
||||
activityToInject,
|
||||
targetableObjects: [timelineTargetableObject],
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
injectIntoTimelineActivitiesQueries,
|
||||
};
|
||||
};
|
||||
@ -1,124 +0,0 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { makeTimelineActivitiesQueryVariables } from '@/activities/timeline/utils/makeTimelineActivitiesQueryVariables';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getTargetObjectFilterFieldName';
|
||||
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useReadFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useReadFindManyRecordsQueryInCache';
|
||||
import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache';
|
||||
|
||||
export const useInjectIntoTimelineActivitiesQueryAfterDrawerMount = () => {
|
||||
const { objectMetadataItem: objectMetadataItemActivity } =
|
||||
useObjectMetadataItemOnly({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const {
|
||||
upsertFindManyRecordsQueryInCache: overwriteFindManyActivitiesInCache,
|
||||
} = useUpsertFindManyRecordsQueryInCache({
|
||||
objectMetadataItem: objectMetadataItemActivity,
|
||||
});
|
||||
|
||||
const { objectMetadataItem: objectMetadataItemActivityTarget } =
|
||||
useObjectMetadataItemOnly({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const {
|
||||
readFindManyRecordsQueryInCache: readFindManyActivityTargetsQueryInCache,
|
||||
} = useReadFindManyRecordsQueryInCache({
|
||||
objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
});
|
||||
|
||||
const {
|
||||
readFindManyRecordsQueryInCache: readFindManyActivitiesQueryInCache,
|
||||
} = useReadFindManyRecordsQueryInCache({
|
||||
objectMetadataItem: objectMetadataItemActivity,
|
||||
});
|
||||
|
||||
const {
|
||||
upsertFindManyRecordsQueryInCache:
|
||||
overwriteFindManyActivityTargetsQueryInCache,
|
||||
} = useUpsertFindManyRecordsQueryInCache({
|
||||
objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
});
|
||||
|
||||
const injectIntoTimelineActivitiesQueryAfterDrawerMount = ({
|
||||
activityToInject,
|
||||
activityTargetsToInject,
|
||||
timelineTargetableObject,
|
||||
}: {
|
||||
activityToInject: Activity;
|
||||
activityTargetsToInject: ActivityTarget[];
|
||||
timelineTargetableObject: ActivityTargetableObject;
|
||||
}) => {
|
||||
const newActivity = {
|
||||
...activityToInject,
|
||||
__typename: 'Activity',
|
||||
};
|
||||
|
||||
const targetObjectFieldName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: timelineTargetableObject.targetObjectNameSingular,
|
||||
});
|
||||
|
||||
const activitiyTargetsForTargetableObjectQueryVariables = {
|
||||
filter: {
|
||||
[targetObjectFieldName]: {
|
||||
eq: timelineTargetableObject.id,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const existingActivityTargetsForTargetableObject =
|
||||
readFindManyActivityTargetsQueryInCache({
|
||||
queryVariables: activitiyTargetsForTargetableObjectQueryVariables,
|
||||
});
|
||||
|
||||
const newActivityTargetsForTargetableObject = [
|
||||
...existingActivityTargetsForTargetableObject,
|
||||
...activityTargetsToInject,
|
||||
];
|
||||
|
||||
const existingActivityIds = existingActivityTargetsForTargetableObject
|
||||
?.map((activityTarget) => activityTarget.activityId)
|
||||
.filter(isNonEmptyString);
|
||||
|
||||
const timelineActivitiesQueryVariablesBeforeDrawerMount =
|
||||
makeTimelineActivitiesQueryVariables({
|
||||
activityIds: existingActivityIds,
|
||||
});
|
||||
|
||||
const existingActivities = readFindManyActivitiesQueryInCache({
|
||||
queryVariables: timelineActivitiesQueryVariablesBeforeDrawerMount,
|
||||
});
|
||||
|
||||
const activityIdsAfterDrawerMount = [
|
||||
...existingActivityIds,
|
||||
newActivity.id,
|
||||
];
|
||||
|
||||
const timelineActivitiesQueryVariablesAfterDrawerMount =
|
||||
makeTimelineActivitiesQueryVariables({
|
||||
activityIds: activityIdsAfterDrawerMount,
|
||||
});
|
||||
|
||||
overwriteFindManyActivityTargetsQueryInCache({
|
||||
objectRecordsToOverwrite: newActivityTargetsForTargetableObject,
|
||||
queryVariables: activitiyTargetsForTargetableObjectQueryVariables,
|
||||
});
|
||||
|
||||
const newActivities = [newActivity, ...existingActivities];
|
||||
|
||||
overwriteFindManyActivitiesInCache({
|
||||
objectRecordsToOverwrite: newActivities,
|
||||
queryVariables: timelineActivitiesQueryVariablesAfterDrawerMount,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
injectIntoTimelineActivitiesQueryAfterDrawerMount,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,138 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useRemoveFromActivitiesQueries } from '@/activities/hooks/useRemoveFromActivitiesQueries';
|
||||
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY';
|
||||
import { timelineTargetableObjectState } from '@/activities/timeline/states/timelineTargetableObjectState';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
|
||||
export const useRemoveFromTimelineActivitiesQueries = () => {
|
||||
const timelineTargetableObject = useRecoilValue(
|
||||
timelineTargetableObjectState,
|
||||
);
|
||||
|
||||
// const { objectMetadataItem: objectMetadataItemActivity } =
|
||||
// useObjectMetadataItemOnly({
|
||||
// objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
// });
|
||||
|
||||
// const {
|
||||
// upsertFindManyRecordsQueryInCache: overwriteFindManyActivitiesInCache,
|
||||
// } = useUpsertFindManyRecordsQueryInCache({
|
||||
// objectMetadataItem: objectMetadataItemActivity,
|
||||
// });
|
||||
|
||||
// const { objectMetadataItem: objectMetadataItemActivityTarget } =
|
||||
// useObjectMetadataItemOnly({
|
||||
// objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
// });
|
||||
|
||||
// const {
|
||||
// readFindManyRecordsQueryInCache: readFindManyActivityTargetsQueryInCache,
|
||||
// } = useReadFindManyRecordsQueryInCache({
|
||||
// objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
// });
|
||||
|
||||
// const {
|
||||
// readFindManyRecordsQueryInCache: readFindManyActivitiesQueryInCache,
|
||||
// } = useReadFindManyRecordsQueryInCache({
|
||||
// objectMetadataItem: objectMetadataItemActivity,
|
||||
// });
|
||||
|
||||
// const {
|
||||
// upsertFindManyRecordsQueryInCache:
|
||||
// overwriteFindManyActivityTargetsQueryInCache,
|
||||
// } = useUpsertFindManyRecordsQueryInCache({
|
||||
// objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
// });
|
||||
|
||||
const { removeFromActivitiesQueries } = useRemoveFromActivitiesQueries();
|
||||
|
||||
const removeFromTimelineActivitiesQueries = ({
|
||||
activityIdToRemove,
|
||||
activityTargetsToRemove,
|
||||
}: {
|
||||
activityIdToRemove: string;
|
||||
activityTargetsToRemove: ActivityTarget[];
|
||||
}) => {
|
||||
if (!timelineTargetableObject) {
|
||||
throw new Error('Timeline targetable object is not defined');
|
||||
}
|
||||
|
||||
removeFromActivitiesQueries({
|
||||
activityIdToRemove,
|
||||
activityTargetsToRemove,
|
||||
targetableObjects: [timelineTargetableObject],
|
||||
activitiesFilters: {},
|
||||
activitiesOrderByVariables: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
|
||||
});
|
||||
|
||||
// const targetObjectFieldName = getActivityTargetObjectFieldIdName({
|
||||
// nameSingular: timelineTargetableObject.targetObjectNameSingular,
|
||||
// });
|
||||
|
||||
// const activitiyTargetsForTargetableObjectQueryVariables = {
|
||||
// filter: {
|
||||
// [targetObjectFieldName]: {
|
||||
// eq: timelineTargetableObject.id,
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
// const existingActivityTargetsForTargetableObject =
|
||||
// readFindManyActivityTargetsQueryInCache({
|
||||
// queryVariables: activitiyTargetsForTargetableObjectQueryVariables,
|
||||
// });
|
||||
|
||||
// const newActivityTargetsForTargetableObject = isNonEmptyArray(
|
||||
// activityTargetsToRemove,
|
||||
// )
|
||||
// ? existingActivityTargetsForTargetableObject.filter(
|
||||
// (existingActivityTarget) =>
|
||||
// activityTargetsToRemove.some(
|
||||
// (activityTargetToRemove) =>
|
||||
// activityTargetToRemove.id !== existingActivityTarget.id,
|
||||
// ),
|
||||
// )
|
||||
// : existingActivityTargetsForTargetableObject;
|
||||
|
||||
// overwriteFindManyActivityTargetsQueryInCache({
|
||||
// objectRecordsToOverwrite: newActivityTargetsForTargetableObject,
|
||||
// queryVariables: activitiyTargetsForTargetableObjectQueryVariables,
|
||||
// });
|
||||
|
||||
// const existingActivityIds = existingActivityTargetsForTargetableObject
|
||||
// ?.map((activityTarget) => activityTarget.activityId)
|
||||
// .filter(isNonEmptyString);
|
||||
|
||||
// const timelineActivitiesQueryVariablesBeforeDrawerMount =
|
||||
// makeTimelineActivitiesQueryVariables({
|
||||
// activityIds: existingActivityIds,
|
||||
// });
|
||||
|
||||
// const existingActivities = readFindManyActivitiesQueryInCache({
|
||||
// queryVariables: timelineActivitiesQueryVariablesBeforeDrawerMount,
|
||||
// });
|
||||
|
||||
// const activityIdsAfterRemoval = existingActivityIds.filter(
|
||||
// (existingActivityId) => existingActivityId !== activityIdToRemove,
|
||||
// );
|
||||
|
||||
// const timelineActivitiesQueryVariablesAfterRemoval =
|
||||
// makeTimelineActivitiesQueryVariables({
|
||||
// activityIds: activityIdsAfterRemoval,
|
||||
// });
|
||||
|
||||
// const newActivities = existingActivities
|
||||
// .filter((existingActivity) => existingActivity.id !== activityIdToRemove)
|
||||
// .toSorted(sortObjectRecordByDateField('createdAt', 'DescNullsFirst'));
|
||||
|
||||
// overwriteFindManyActivitiesInCache({
|
||||
// objectRecordsToOverwrite: newActivities,
|
||||
// queryVariables: timelineActivitiesQueryVariablesAfterRemoval,
|
||||
// });
|
||||
};
|
||||
|
||||
return {
|
||||
removeFromTimelineActivitiesQueries,
|
||||
};
|
||||
};
|
||||
@ -1,18 +1,37 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRecoilCallback, useRecoilState } from 'recoil';
|
||||
|
||||
import { useActivityTargetsForTargetableObject } from '@/activities/hooks/useActivityTargetsForTargetableObject';
|
||||
import { timelineTargetableObjectState } from '@/activities/timeline/states/timelineTargetableObjectState';
|
||||
import { makeTimelineActivitiesQueryVariables } from '@/activities/timeline/utils/makeTimelineActivitiesQueryVariables';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { useActivityConnectionUtils } from '@/activities/utils/useActivityConnectionUtils';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { sortByAscString } from '~/utils/array/sortByAscString';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useTimelineActivities = ({
|
||||
targetableObject,
|
||||
}: {
|
||||
targetableObject: ActivityTargetableObject;
|
||||
}) => {
|
||||
const { makeActivityWithoutConnection } = useActivityConnectionUtils();
|
||||
|
||||
const [, setTimelineTargetableObject] = useRecoilState(
|
||||
timelineTargetableObjectState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(targetableObject)) {
|
||||
setTimelineTargetableObject(targetableObject);
|
||||
}
|
||||
}, [targetableObject, setTimelineTargetableObject]);
|
||||
|
||||
const {
|
||||
activityTargets,
|
||||
loadingActivityTargets,
|
||||
@ -23,9 +42,14 @@ export const useTimelineActivities = ({
|
||||
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
||||
const activityIds = activityTargets
|
||||
?.map((activityTarget) => activityTarget.activityId)
|
||||
.filter(isNonEmptyString);
|
||||
const activityIds = Array.from(
|
||||
new Set(
|
||||
activityTargets
|
||||
?.map((activityTarget) => activityTarget.activityId)
|
||||
.filter(isNonEmptyString)
|
||||
.toSorted(sortByAscString),
|
||||
),
|
||||
);
|
||||
|
||||
const timelineActivitiesQueryVariables = makeTimelineActivitiesQueryVariables(
|
||||
{
|
||||
@ -33,17 +57,30 @@ export const useTimelineActivities = ({
|
||||
},
|
||||
);
|
||||
|
||||
const { records: activities, loading: loadingActivities } =
|
||||
const { records: activitiesWithConnection, loading: loadingActivities } =
|
||||
useFindManyRecords<Activity>({
|
||||
skip: loadingActivityTargets || !isNonEmptyArray(activityTargets),
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
filter: timelineActivitiesQueryVariables.filter,
|
||||
orderBy: timelineActivitiesQueryVariables.orderBy,
|
||||
onCompleted: () => {
|
||||
if (!initialized) {
|
||||
setInitialized(true);
|
||||
}
|
||||
},
|
||||
onCompleted: useRecoilCallback(
|
||||
({ set }) =>
|
||||
(data) => {
|
||||
if (!initialized) {
|
||||
setInitialized(true);
|
||||
}
|
||||
|
||||
const activities = getRecordsFromRecordConnection({
|
||||
recordConnection: data,
|
||||
});
|
||||
|
||||
for (const activity of activities) {
|
||||
set(recordStoreFamilyState(activity.id), activity);
|
||||
}
|
||||
},
|
||||
[initialized],
|
||||
),
|
||||
depth: 3,
|
||||
});
|
||||
|
||||
const noActivityTargets =
|
||||
@ -57,6 +94,11 @@ export const useTimelineActivities = ({
|
||||
|
||||
const loading = loadingActivities || loadingActivityTargets;
|
||||
|
||||
const activities = activitiesWithConnection
|
||||
?.map(makeActivityWithoutConnection as any)
|
||||
.map(({ activity }: any) => activity as any)
|
||||
.filter(isDefined);
|
||||
|
||||
return {
|
||||
activities,
|
||||
loading,
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
|
||||
export const timelineTargetableObjectState =
|
||||
atom<ActivityTargetableObject | null>({
|
||||
key: 'timelineTargetableObjectState',
|
||||
default: null,
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
|
||||
import { sortByAscString } from '~/utils/array/sortByAscString';
|
||||
|
||||
export const makeTimelineActivitiesQueryVariables = ({
|
||||
activityIds,
|
||||
@ -8,7 +9,7 @@ export const makeTimelineActivitiesQueryVariables = ({
|
||||
return {
|
||||
filter: {
|
||||
id: {
|
||||
in: activityIds,
|
||||
in: activityIds.toSorted(sortByAscString),
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
|
||||
Reference in New Issue
Block a user