Files
twenty/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromInlineCell.ts
T
Charles Bochet f0de6d31b7 Refactor MultipleObjectsPicker component (#10552)
Refactor to only have MultipleRecordPicker and SingleRecordPicker

What's done:
- SingleRecordPicker, MultipleRecordPicker
- RelationToOneInput
- RelationFromManyInput
- usage in TableCell, InlineCell, RelationDetailSection, Workflow

What's left:
- Make a pass on the app, to make sure the hotkeyScopes, clickOutside
are properly set
- Fix flashing on ActivityTarget
- add more tests on the code
2025-03-10 15:04:09 +01:00

174 lines
5.9 KiB
TypeScript

import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
import { NoteTarget } from '@/activities/types/NoteTarget';
import { TaskTarget } from '@/activities/types/TaskTarget';
import { getJoinObjectNameSingular } from '@/activities/utils/getJoinObjectNameSingular';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isNull } from '@sniptt/guards';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared';
import { v4 } from 'uuid';
type UpdateActivityTargetFromInlineCellProps = {
recordPickerInstanceId: string;
morphItem: RecordPickerPickableMorphItem;
activityTargetWithTargetRecords: ActivityTargetWithTargetRecord[];
};
export const useUpdateActivityTargetFromInlineCell = ({
activityObjectNameSingular,
activityId,
}: {
activityObjectNameSingular:
| CoreObjectNameSingular.Note
| CoreObjectNameSingular.Task;
activityId: string;
}) => {
const { createOneRecord: createOneActivityTarget } = useCreateOneRecord<
NoteTarget | TaskTarget
>({
objectNameSingular: getJoinObjectNameSingular(activityObjectNameSingular),
});
const { deleteOneRecord: deleteOneActivityTarget } = useDeleteOneRecord({
objectNameSingular: getJoinObjectNameSingular(activityObjectNameSingular),
});
const setActivityFromStore = useSetRecoilState(
recordStoreFamilyState(activityId),
);
const updateActivityTargetFromInlineCell = useRecoilCallback(
({ snapshot }) =>
async ({
morphItem,
activityTargetWithTargetRecords,
}: UpdateActivityTargetFromInlineCellProps) => {
const targetObjectName =
activityObjectNameSingular === CoreObjectNameSingular.Task
? 'task'
: 'note';
const pickedObjectMetadataItem = snapshot
.getLoadable(objectMetadataItemsState)
.getValue()
.find(
(objectMetadataItem) =>
objectMetadataItem.id === morphItem.objectMetadataId,
);
if (!isDefined(pickedObjectMetadataItem)) {
throw new Error('Could not find object metadata item');
}
let activityTargetsAfterUpdate: (TaskTarget | NoteTarget)[] = [];
const existingActivityTarget = activityTargetWithTargetRecords.find(
(activityTarget) =>
activityTarget.targetObject.id === morphItem.recordId,
);
if (isDefined(existingActivityTarget)) {
activityTargetsAfterUpdate = activityTargetWithTargetRecords
.map((activityTarget) => {
if (
activityTarget.targetObject.id === morphItem.recordId &&
!morphItem.isSelected
) {
return undefined;
}
return activityTarget.activityTarget;
})
.filter(isDefined);
if (!morphItem.isSelected) {
await deleteOneActivityTarget(
existingActivityTarget.targetObject.id,
);
}
} else {
const targetRecord = snapshot
.getLoadable(recordStoreFamilyState(morphItem.recordId))
.getValue();
if (!isDefined(targetRecord)) {
return;
}
if (!morphItem.isSelected) {
return;
}
const activityTarget =
activityObjectNameSingular === CoreObjectNameSingular.Task
? {
id: v4(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
__typename: 'TaskTarget',
taskId: activityId,
task: {
id: activityId,
__typename: 'Task',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
[pickedObjectMetadataItem.nameSingular]: targetRecord,
}
: {
id: v4(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
__typename: 'NoteTarget',
noteId: activityId,
note: {
id: activityId,
__typename: 'Note',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
[pickedObjectMetadataItem.nameSingular]: targetRecord,
};
activityTargetsAfterUpdate = [
...activityTargetWithTargetRecords.map((activityTarget) => {
return activityTarget.activityTarget;
}),
activityTarget as NoteTarget | TaskTarget,
];
await createOneActivityTarget({
...activityTarget,
[targetObjectName]: undefined,
[pickedObjectMetadataItem.nameSingular]: undefined,
} as Partial<NoteTarget | TaskTarget>);
}
setActivityFromStore((currentActivity) => {
if (isNull(currentActivity)) {
return null;
}
return {
...currentActivity,
[`${targetObjectName}Targets`]: activityTargetsAfterUpdate,
};
});
},
[
activityId,
activityObjectNameSingular,
createOneActivityTarget,
deleteOneActivityTarget,
setActivityFromStore,
],
);
return { updateActivityTargetFromInlineCell };
};