Activity cache injection (#3791)
* WIP * Minor fixes * Added TODO * Fix post merge * Fix * Fixed warnings * Fixed comments * Fixed comments * Fixed naming * Removed comment * WIP * WIP 2 * Finished working version * Fixes * Fixed typing * Fixes * Fixes * Fixes * Naming fixes * WIP * Fix import * WIP * Working version on title * Fixed create record id overwrite * Removed unecessary callback * Masterpiece * Fixed delete on click outside drawer or delete * Cleaned * Cleaned * Cleaned * Minor fixes * Fixes * Fixed naming * WIP * Fix * Fixed create from target inline cell * Removed console.log * Fixed delete activity optimistic effect * Fixed no title * Fixed debounce and title body creation --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -0,0 +1,34 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useActivityConnectionUtils } from '@/activities/utils/useActivityConnectionUtils';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
|
||||
const QUERY_DEPTH_TO_GET_ACTIVITY_TARGET_RELATIONS = 3;
|
||||
|
||||
export const useActivityById = ({ activityId }: { activityId: string }) => {
|
||||
const setEntityFields = useSetRecoilState(recordStoreFamilyState(activityId));
|
||||
|
||||
const { makeActivityWithoutConnection } = useActivityConnectionUtils();
|
||||
|
||||
const { record: activityWithConnections } = useFindOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activityId,
|
||||
skip: !activityId,
|
||||
onCompleted: (activityWithConnections: any) => {
|
||||
const { activity } = makeActivityWithoutConnection(
|
||||
activityWithConnections,
|
||||
);
|
||||
|
||||
setEntityFields(activity);
|
||||
},
|
||||
depth: QUERY_DEPTH_TO_GET_ACTIVITY_TARGET_RELATIONS,
|
||||
});
|
||||
|
||||
const { activity } = makeActivityWithoutConnection(activityWithConnections);
|
||||
|
||||
return {
|
||||
activity,
|
||||
};
|
||||
};
|
||||
@ -1,3 +1,4 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { ActivityTargetObjectRecord } from '@/activities/types/ActivityTargetObject';
|
||||
@ -17,6 +18,7 @@ export const useActivityTargetObjectRecords = ({
|
||||
const { records: activityTargets, loading: loadingActivityTargets } =
|
||||
useFindManyRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
skip: !isNonEmptyString(activityId),
|
||||
filter: {
|
||||
activityId: {
|
||||
eq: activityId,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
@ -6,7 +7,7 @@ import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getTarget
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
|
||||
export const useActivityTargets = ({
|
||||
export const useActivityTargetsForTargetableObject = ({
|
||||
targetableObject,
|
||||
}: {
|
||||
targetableObject: ActivityTargetableObject;
|
||||
@ -17,9 +18,14 @@ export const useActivityTargets = ({
|
||||
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
||||
const targetableObjectId = targetableObject.id;
|
||||
|
||||
const skipRequest = !isNonEmptyString(targetableObjectId);
|
||||
|
||||
const { records: activityTargets, loading: loadingActivityTargets } =
|
||||
useFindManyRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
skip: skipRequest,
|
||||
filter: {
|
||||
[targetObjectFieldName]: {
|
||||
eq: targetableObject.id,
|
||||
@ -0,0 +1,91 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { StringKeyOf } from 'type-fest';
|
||||
|
||||
import { getRelationDefinition } from '@/apollo/optimistic-effect/utils/getRelationDefinition';
|
||||
import { triggerAttachRelationOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerAttachRelationOptimisticEffect';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useAttachRelationInBothDirections = () => {
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const attachRelationInBothDirections = <
|
||||
Source extends ObjectRecord = ObjectRecord,
|
||||
Target extends ObjectRecord = ObjectRecord,
|
||||
>({
|
||||
sourceRecord,
|
||||
targetRecords,
|
||||
sourceObjectNameSingular,
|
||||
targetObjectNameSingular,
|
||||
fieldNameOnSourceRecord,
|
||||
fieldNameOnTargetRecord,
|
||||
}: {
|
||||
sourceRecord: Source;
|
||||
targetRecords: Target[];
|
||||
sourceObjectNameSingular: string;
|
||||
targetObjectNameSingular: string;
|
||||
fieldNameOnSourceRecord: StringKeyOf<Source>;
|
||||
fieldNameOnTargetRecord: StringKeyOf<Target>;
|
||||
}) => {
|
||||
const sourceObjectMetadataItem = getObjectMetadataItemByNameSingular({
|
||||
objectMetadataItems,
|
||||
objectNameSingular: sourceObjectNameSingular,
|
||||
});
|
||||
|
||||
const targetObjectMetadataItem = getObjectMetadataItemByNameSingular({
|
||||
objectMetadataItems,
|
||||
objectNameSingular: targetObjectNameSingular,
|
||||
});
|
||||
|
||||
const fieldMetadataItemOnSourceRecord =
|
||||
sourceObjectMetadataItem.fields.find(
|
||||
(field) => field.name === fieldNameOnSourceRecord,
|
||||
);
|
||||
|
||||
if (!isDefined(fieldMetadataItemOnSourceRecord)) {
|
||||
throw new Error(
|
||||
`Field ${fieldNameOnSourceRecord} not found on object ${sourceObjectNameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
const relationDefinition = getRelationDefinition({
|
||||
fieldMetadataItemOnSourceRecord: fieldMetadataItemOnSourceRecord,
|
||||
objectMetadataItems,
|
||||
});
|
||||
|
||||
if (!isDefined(relationDefinition)) {
|
||||
throw new Error(
|
||||
`Relation metadata not found for field ${fieldNameOnSourceRecord} on object ${sourceObjectNameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: could we use triggerUpdateRelationsOptimisticEffect here?
|
||||
targetRecords.forEach((relationTargetRecord) => {
|
||||
triggerAttachRelationOptimisticEffect({
|
||||
cache: apolloClient.cache,
|
||||
sourceObjectNameSingular: sourceObjectMetadataItem.nameSingular,
|
||||
sourceRecordId: sourceRecord.id,
|
||||
fieldNameOnTargetRecord: fieldNameOnTargetRecord,
|
||||
targetObjectNameSingular: targetObjectMetadataItem.nameSingular,
|
||||
targetRecordId: relationTargetRecord.id,
|
||||
});
|
||||
|
||||
triggerAttachRelationOptimisticEffect({
|
||||
cache: apolloClient.cache,
|
||||
sourceObjectNameSingular: targetObjectMetadataItem.nameSingular,
|
||||
sourceRecordId: relationTargetRecord.id,
|
||||
fieldNameOnTargetRecord: fieldNameOnSourceRecord,
|
||||
targetObjectNameSingular: sourceObjectMetadataItem.nameSingular,
|
||||
targetRecordId: sourceRecord.id,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
attachRelationInBothDirections,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,115 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useAttachRelationInBothDirections } from '@/activities/hooks/useAttachRelationInBothDirections';
|
||||
import { useInjectIntoActivityTargetInlineCellCache } from '@/activities/inline-cell/hooks/useInjectIntoActivityTargetInlineCellCache';
|
||||
import { useInjectIntoTimelineActivitiesQueryAfterDrawerMount } from '@/activities/timeline/hooks/useInjectIntoTimelineActivitiesQueryAfterDrawerMount';
|
||||
import { Activity, ActivityType } from '@/activities/types/Activity';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { getActivityTargetsToCreateFromTargetableObjects } from '@/activities/utils/getActivityTargetsToCreateFromTargetableObjects';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateManyRecordsInCache } from '@/object-record/hooks/useCreateManyRecordsInCache';
|
||||
import { useCreateOneRecordInCache } from '@/object-record/hooks/useCreateOneRecordInCache';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
|
||||
export const useCreateActivityInCache = () => {
|
||||
const { createManyRecordsInCache: createManyActivityTargetsInCache } =
|
||||
useCreateManyRecordsInCache<ActivityTarget>({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const { createOneRecordInCache: createOneActivityInCache } =
|
||||
useCreateOneRecordInCache<Activity>({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const { record: workspaceMemberRecord } = useFindOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
objectRecordId: currentWorkspaceMember?.id,
|
||||
depth: 3,
|
||||
});
|
||||
|
||||
const { injectIntoTimelineActivitiesQueryAfterDrawerMount } =
|
||||
useInjectIntoTimelineActivitiesQueryAfterDrawerMount();
|
||||
|
||||
const { injectIntoActivityTargetInlineCellCache } =
|
||||
useInjectIntoActivityTargetInlineCellCache();
|
||||
|
||||
const {
|
||||
attachRelationInBothDirections:
|
||||
attachRelationSourceRecordToItsRelationTargetRecordsAndViceVersaInCache,
|
||||
} = useAttachRelationInBothDirections();
|
||||
|
||||
const createActivityInCache = ({
|
||||
type,
|
||||
targetableObjects,
|
||||
timelineTargetableObject,
|
||||
assigneeId,
|
||||
}: {
|
||||
type: ActivityType;
|
||||
targetableObjects: ActivityTargetableObject[];
|
||||
timelineTargetableObject: ActivityTargetableObject;
|
||||
assigneeId?: string;
|
||||
}) => {
|
||||
const activityId = v4();
|
||||
|
||||
const createdActivityInCache = createOneActivityInCache({
|
||||
id: activityId,
|
||||
author: workspaceMemberRecord,
|
||||
authorId: workspaceMemberRecord?.id,
|
||||
assignee: !assigneeId ? workspaceMemberRecord : undefined,
|
||||
assigneeId:
|
||||
assigneeId ?? isNonEmptyString(workspaceMemberRecord?.id)
|
||||
? workspaceMemberRecord?.id
|
||||
: undefined,
|
||||
type: type,
|
||||
});
|
||||
|
||||
const activityTargetsToCreate =
|
||||
getActivityTargetsToCreateFromTargetableObjects({
|
||||
activityId,
|
||||
targetableObjects,
|
||||
});
|
||||
|
||||
const createdActivityTargetsInCache = createManyActivityTargetsInCache(
|
||||
activityTargetsToCreate,
|
||||
);
|
||||
|
||||
injectIntoTimelineActivitiesQueryAfterDrawerMount({
|
||||
activityToInject: createdActivityInCache,
|
||||
activityTargetsToInject: createdActivityTargetsInCache,
|
||||
timelineTargetableObject,
|
||||
});
|
||||
|
||||
injectIntoActivityTargetInlineCellCache({
|
||||
activityId,
|
||||
activityTargetsToInject: createdActivityTargetsInCache,
|
||||
});
|
||||
|
||||
attachRelationSourceRecordToItsRelationTargetRecordsAndViceVersaInCache({
|
||||
sourceRecord: createdActivityInCache,
|
||||
fieldNameOnSourceRecord: 'activityTargets',
|
||||
sourceObjectNameSingular: CoreObjectNameSingular.Activity,
|
||||
fieldNameOnTargetRecord: 'activity',
|
||||
targetObjectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
targetRecords: createdActivityTargetsInCache,
|
||||
});
|
||||
|
||||
return {
|
||||
createdActivityInCache: {
|
||||
...createdActivityInCache,
|
||||
activityTargets: createdActivityTargetsInCache,
|
||||
},
|
||||
createdActivityTargetsInCache,
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
createActivityInCache,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,59 @@
|
||||
import { isNonEmptyArray } from '@sniptt/guards';
|
||||
|
||||
import { useModifyActivityTargetsOnActivityCache } from '@/activities/hooks/useModifyActivityTargetsOnActivityCache';
|
||||
import { ActivityForEditor } from '@/activities/types/ActivityForEditor';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { useActivityConnectionUtils } from '@/activities/utils/useActivityConnectionUtils';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
|
||||
export const useCreateActivityInDB = () => {
|
||||
const { createOneRecord: createOneActivity } = useCreateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const { createManyRecords: createManyActivityTargets } =
|
||||
useCreateManyRecords<ActivityTarget>({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const { makeActivityWithConnection } = useActivityConnectionUtils();
|
||||
|
||||
const { modifyActivityTargetsOnActivityCache } =
|
||||
useModifyActivityTargetsOnActivityCache();
|
||||
|
||||
const createActivityInDB = async (activityToCreate: ActivityForEditor) => {
|
||||
const { activityWithConnection } = makeActivityWithConnection(
|
||||
activityToCreate as any, // TODO: fix type
|
||||
);
|
||||
|
||||
await createOneActivity?.(
|
||||
{
|
||||
...activityWithConnection,
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
skipOptimisticEffect: true,
|
||||
},
|
||||
);
|
||||
|
||||
const activityTargetsToCreate = activityToCreate.activityTargets ?? [];
|
||||
|
||||
if (isNonEmptyArray(activityTargetsToCreate)) {
|
||||
await createManyActivityTargets(activityTargetsToCreate, {
|
||||
skipOptimisticEffect: true,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: replace by trigger optimistic effect
|
||||
modifyActivityTargetsOnActivityCache({
|
||||
activityId: activityToCreate.id,
|
||||
activityTargets: activityTargetsToCreate,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
createActivityInDB,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { ActivityForEditor } from '@/activities/types/ActivityForEditor';
|
||||
import { useActivityConnectionUtils } from '@/activities/utils/useActivityConnectionUtils';
|
||||
import { triggerDeleteRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect';
|
||||
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
|
||||
// TODO: this should be useDeleteRecordFromCache
|
||||
export const useDeleteActivityFromCache = () => {
|
||||
const { makeActivityWithConnection } = useActivityConnectionUtils();
|
||||
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const { objectMetadataItem: objectMetadataItemActivity } =
|
||||
useObjectMetadataItemOnly({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const deleteActivityFromCache = (activityToDelete: ActivityForEditor) => {
|
||||
const { activityWithConnection } = makeActivityWithConnection(
|
||||
activityToDelete as any, // TODO: fix type
|
||||
);
|
||||
|
||||
triggerDeleteRecordsOptimisticEffect({
|
||||
cache: apolloClient.cache,
|
||||
objectMetadataItem: objectMetadataItemActivity,
|
||||
objectMetadataItems,
|
||||
recordsToDelete: [activityWithConnection],
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
deleteActivityFromCache,
|
||||
};
|
||||
};
|
||||
@ -1,163 +1,61 @@
|
||||
import { useCallback } from 'react';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useActivityTargets } from '@/activities/hooks/useActivityTargets';
|
||||
import { useModifyActivityOnActivityTargetsCache } from '@/activities/hooks/useModifyActivityOnActivityTargetCache';
|
||||
import { useModifyActivityTargetsOnActivityCache } from '@/activities/hooks/useModifyActivityTargetsOnActivityCache';
|
||||
import { useWriteActivityTargetsInCache } from '@/activities/hooks/useWriteActivityTargetsInCache';
|
||||
import { useInjectIntoActivityTargetInlineCellCache } from '@/activities/inline-cell/hooks/useInjectIntoActivityTargetInlineCellCache';
|
||||
import { useInjectIntoTimelineActivitiesQuery } from '@/activities/timeline/hooks/useInjectIntoTimelineActivitiesQuery';
|
||||
import { Activity, ActivityType } from '@/activities/types/Activity';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { getActivityTargetsToCreateFromTargetableObjects } from '@/activities/utils/getActivityTargetsToCreateFromTargetableObjects';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateManyRecordsInCache } from '@/object-record/hooks/useCreateManyRecordsInCache';
|
||||
import { useCreateOneRecordInCache } from '@/object-record/hooks/useCreateOneRecordInCache';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { mapToRecordId } from '@/object-record/utils/mapToObjectId';
|
||||
import { useCreateActivityInCache } from '@/activities/hooks/useCreateActivityInCache';
|
||||
import { activityTargetableEntityArrayState } from '@/activities/states/activityTargetableEntityArrayState';
|
||||
import { isCreatingActivityState } from '@/activities/states/isCreatingActivityState';
|
||||
import { temporaryActivityForEditorState } from '@/activities/states/temporaryActivityForEditorState';
|
||||
import { viewableActivityIdState } from '@/activities/states/viewableActivityIdState';
|
||||
import { ActivityType } from '@/activities/types/Activity';
|
||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
|
||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
|
||||
import { activityTargetableEntityArrayState } from '../states/activityTargetableEntityArrayState';
|
||||
import { viewableActivityIdState } from '../states/viewableActivityIdState';
|
||||
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
|
||||
|
||||
export const useOpenCreateActivityDrawerV2 = ({
|
||||
targetableObject,
|
||||
}: {
|
||||
targetableObject: ActivityTargetableObject;
|
||||
}) => {
|
||||
export const useOpenCreateActivityDrawerV2 = () => {
|
||||
const { openRightDrawer } = useRightDrawer();
|
||||
|
||||
const { createManyRecordsInCache: createManyActivityTargetsInCache } =
|
||||
useCreateManyRecordsInCache<ActivityTarget>({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const { createOneRecordInCache: createOneActivityInCache } =
|
||||
useCreateOneRecordInCache<Activity>({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
|
||||
const { record: workspaceMemberRecord } = useFindOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||
objectRecordId: currentWorkspaceMember?.id,
|
||||
});
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { createActivityInCache } = useCreateActivityInCache();
|
||||
|
||||
const [, setActivityTargetableEntityArray] = useRecoilState(
|
||||
activityTargetableEntityArrayState,
|
||||
);
|
||||
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
||||
|
||||
const { activityTargets } = useActivityTargets({
|
||||
targetableObject,
|
||||
});
|
||||
const setIsCreatingActivity = useSetRecoilState(isCreatingActivityState);
|
||||
|
||||
const { injectIntoTimelineActivitiesNextQuery } =
|
||||
useInjectIntoTimelineActivitiesQuery();
|
||||
const setTemporaryActivityForEditor = useSetRecoilState(
|
||||
temporaryActivityForEditorState,
|
||||
);
|
||||
|
||||
const { injectIntoActivityTargetInlineCellCache } =
|
||||
useInjectIntoActivityTargetInlineCellCache();
|
||||
|
||||
const { injectIntoUseActivityTargets } = useWriteActivityTargetsInCache();
|
||||
|
||||
const { modifyActivityTargetsOnActivityCache } =
|
||||
useModifyActivityTargetsOnActivityCache();
|
||||
|
||||
const { modifyActivityOnActivityTargetsCache } =
|
||||
useModifyActivityOnActivityTargetsCache();
|
||||
|
||||
return useCallback(
|
||||
async ({
|
||||
const openCreateActivityDrawer = async ({
|
||||
type,
|
||||
targetableObjects,
|
||||
timelineTargetableObject,
|
||||
assigneeId,
|
||||
}: {
|
||||
type: ActivityType;
|
||||
targetableObjects: ActivityTargetableObject[];
|
||||
timelineTargetableObject: ActivityTargetableObject;
|
||||
assigneeId?: string;
|
||||
}) => {
|
||||
const { createdActivityInCache } = createActivityInCache({
|
||||
type,
|
||||
targetableObjects,
|
||||
timelineTargetableObject,
|
||||
assigneeId,
|
||||
}: {
|
||||
type: ActivityType;
|
||||
targetableObjects: ActivityTargetableObject[];
|
||||
assigneeId?: string;
|
||||
}) => {
|
||||
const activityId = v4();
|
||||
});
|
||||
|
||||
const createdActivityInCache = await createOneActivityInCache({
|
||||
id: activityId,
|
||||
author: workspaceMemberRecord,
|
||||
authorId: workspaceMemberRecord?.id,
|
||||
assignee: !assigneeId ? workspaceMemberRecord : undefined,
|
||||
assigneeId:
|
||||
assigneeId ?? isNonEmptyString(workspaceMemberRecord?.id)
|
||||
? workspaceMemberRecord?.id
|
||||
: undefined,
|
||||
type: type,
|
||||
});
|
||||
setTemporaryActivityForEditor(createdActivityInCache);
|
||||
setIsCreatingActivity(true);
|
||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||
setViewableActivityId(createdActivityInCache.id);
|
||||
setActivityTargetableEntityArray(targetableObjects ?? []);
|
||||
openRightDrawer(RightDrawerPages.CreateActivity);
|
||||
};
|
||||
|
||||
if (!createdActivityInCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activityTargetsToCreate =
|
||||
getActivityTargetsToCreateFromTargetableObjects({
|
||||
activityId,
|
||||
targetableObjects,
|
||||
});
|
||||
|
||||
const createdActivityTargetsInCache =
|
||||
await createManyActivityTargetsInCache(activityTargetsToCreate);
|
||||
|
||||
injectIntoUseActivityTargets({
|
||||
targetableObject,
|
||||
activityTargetsToInject: createdActivityTargetsInCache,
|
||||
});
|
||||
|
||||
injectIntoTimelineActivitiesNextQuery({
|
||||
activityTargets,
|
||||
activityToInject: createdActivityInCache,
|
||||
});
|
||||
|
||||
injectIntoActivityTargetInlineCellCache({
|
||||
activityId,
|
||||
activityTargetsToInject: createdActivityTargetsInCache,
|
||||
});
|
||||
|
||||
modifyActivityTargetsOnActivityCache({
|
||||
activityId,
|
||||
activityTargets: createdActivityTargetsInCache,
|
||||
});
|
||||
|
||||
modifyActivityOnActivityTargetsCache({
|
||||
activityTargetIds: createdActivityTargetsInCache.map(mapToRecordId),
|
||||
activity: createdActivityInCache,
|
||||
});
|
||||
|
||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||
setViewableActivityId(activityId);
|
||||
setActivityTargetableEntityArray(targetableObjects ?? []);
|
||||
openRightDrawer(RightDrawerPages.CreateActivity);
|
||||
},
|
||||
[
|
||||
openRightDrawer,
|
||||
setActivityTargetableEntityArray,
|
||||
createManyActivityTargetsInCache,
|
||||
setHotkeyScope,
|
||||
setViewableActivityId,
|
||||
createOneActivityInCache,
|
||||
workspaceMemberRecord,
|
||||
activityTargets,
|
||||
targetableObject,
|
||||
injectIntoTimelineActivitiesNextQuery,
|
||||
injectIntoActivityTargetInlineCellCache,
|
||||
injectIntoUseActivityTargets,
|
||||
modifyActivityTargetsOnActivityCache,
|
||||
modifyActivityOnActivityTargetsCache,
|
||||
],
|
||||
);
|
||||
return openCreateActivityDrawer;
|
||||
};
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useCreateActivityInDB } from '@/activities/hooks/useCreateActivityInDB';
|
||||
import { isCreatingActivityState } from '@/activities/states/isCreatingActivityState';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
|
||||
export const useUpsertActivity = () => {
|
||||
const [isCreatingActivity, setIsCreatingActivity] = useRecoilState(
|
||||
isCreatingActivityState,
|
||||
);
|
||||
|
||||
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord<Activity>({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
});
|
||||
|
||||
const { createActivityInDB } = useCreateActivityInDB();
|
||||
|
||||
const upsertActivity = ({
|
||||
activity,
|
||||
input,
|
||||
}: {
|
||||
activity: Activity;
|
||||
input: Partial<Activity>;
|
||||
}) => {
|
||||
if (isCreatingActivity) {
|
||||
createActivityInDB({
|
||||
...activity,
|
||||
...input,
|
||||
});
|
||||
|
||||
setIsCreatingActivity(false);
|
||||
} else {
|
||||
updateOneActivity?.({
|
||||
idToUpdate: activity.id,
|
||||
updateOneRecordInput: input,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
upsertActivity,
|
||||
};
|
||||
};
|
||||
@ -1,84 +0,0 @@
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getTargetObjectFilterFieldName';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { ObjectRecordConnection } from '@/object-record/types/ObjectRecordConnection';
|
||||
|
||||
export const useWriteActivityTargetsInCache = () => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const {
|
||||
objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
findManyRecordsQuery: findManyActivityTargetsQuery,
|
||||
} = useObjectMetadataItem({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const injectIntoUseActivityTargets = ({
|
||||
targetableObject,
|
||||
activityTargetsToInject,
|
||||
}: {
|
||||
targetableObject: Pick<
|
||||
ActivityTargetableObject,
|
||||
'id' | 'targetObjectNameSingular'
|
||||
>;
|
||||
activityTargetsToInject: ActivityTarget[];
|
||||
}) => {
|
||||
const targetObjectFieldName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetableObject.targetObjectNameSingular,
|
||||
});
|
||||
|
||||
const existingActivityTargetsForTargetableObjectQueryResult =
|
||||
apolloClient.readQuery({
|
||||
query: findManyActivityTargetsQuery,
|
||||
variables: {
|
||||
filter: {
|
||||
[targetObjectFieldName]: {
|
||||
eq: targetableObject.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const existingActivityTargetsForTargetableObject =
|
||||
getRecordsFromRecordConnection({
|
||||
recordConnection: existingActivityTargetsForTargetableObjectQueryResult[
|
||||
objectMetadataItemActivityTarget.namePlural
|
||||
] as ObjectRecordConnection<ActivityTarget>,
|
||||
});
|
||||
|
||||
const newActivityTargetsForTargetableObject = [
|
||||
...existingActivityTargetsForTargetableObject,
|
||||
...activityTargetsToInject,
|
||||
];
|
||||
|
||||
const newActivityTargetsConnection = getRecordConnectionFromRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
records: newActivityTargetsForTargetableObject,
|
||||
});
|
||||
|
||||
apolloClient.writeQuery({
|
||||
query: findManyActivityTargetsQuery,
|
||||
variables: {
|
||||
filter: {
|
||||
[targetObjectFieldName]: {
|
||||
eq: targetableObject.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
data: {
|
||||
[objectMetadataItemActivityTarget.namePlural]:
|
||||
newActivityTargetsConnection,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
injectIntoUseActivityTargets,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user