Files
twenty/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetInlineCellEditMode.tsx
Charles Bochet cfb0cce9b8 Refactor Views by cleaning the code, relying on apolloCache and improving performances (#4516)
* Wip refactoring view

* Post merge conflicts

* Fix review

* Add create view capability

* Fix create object missing view

* Fix tests
2024-03-20 14:21:58 +01:00

178 lines
6.1 KiB
TypeScript

import styled from '@emotion/styled';
import { isNonEmptyArray } from '@sniptt/guards';
import { useRecoilState } from 'recoil';
import { v4 } from 'uuid';
import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity';
import { useInjectIntoActivityTargetInlineCellCache } from '@/activities/inline-cell/hooks/useInjectIntoActivityTargetInlineCellCache';
import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState';
import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getTargetObjectFilterFieldName';
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useGenerateObjectRecordOptimisticResponse } from '@/object-record/cache/hooks/useGenerateObjectRecordOptimisticResponse';
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { MultipleObjectRecordSelect } from '@/object-record/relation-picker/components/MultipleObjectRecordSelect';
import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
const StyledSelectContainer = styled.div`
left: 0px;
position: absolute;
top: -8px;
`;
type ActivityTargetInlineCellEditModeProps = {
activity: Activity;
activityTargetWithTargetRecords: ActivityTargetWithTargetRecord[];
};
export const ActivityTargetInlineCellEditMode = ({
activity,
activityTargetWithTargetRecords,
}: ActivityTargetInlineCellEditModeProps) => {
const [isActivityInCreateMode] = useRecoilState(isActivityInCreateModeState);
const selectedTargetObjectIds = activityTargetWithTargetRecords.map(
(activityTarget) => ({
objectNameSingular: activityTarget.targetObjectNameSingular,
id: activityTarget.targetObject.id,
}),
);
const { createManyRecords: createManyActivityTargets } =
useCreateManyRecords<ActivityTarget>({
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
});
const { deleteManyRecords: deleteManyActivityTargets } = useDeleteManyRecords(
{
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
},
);
const { closeInlineCell: closeEditableField } = useInlineCell();
const { upsertActivity } = useUpsertActivity();
const { objectMetadataItem: objectMetadataItemActivityTarget } =
useObjectMetadataItemOnly({
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
});
const { injectIntoActivityTargetInlineCellCache } =
useInjectIntoActivityTargetInlineCellCache();
const { generateObjectRecordOptimisticResponse } =
useGenerateObjectRecordOptimisticResponse({
objectMetadataItem: objectMetadataItemActivityTarget,
});
const handleSubmit = async (selectedRecords: ObjectRecordForSelect[]) => {
closeEditableField();
const activityTargetsToDelete = activityTargetWithTargetRecords.filter(
(activityTargetObjectRecord) =>
!selectedRecords.some(
(selectedRecord) =>
selectedRecord.recordIdentifier.id ===
activityTargetObjectRecord.targetObject.id,
),
);
const selectedTargetObjectsToCreate = selectedRecords.filter(
(selectedRecord) =>
!activityTargetWithTargetRecords.some(
(activityTargetWithTargetRecord) =>
activityTargetWithTargetRecord.targetObject.id ===
selectedRecord.recordIdentifier.id,
),
);
const existingActivityTargets = activityTargetWithTargetRecords.map(
(activityTargetObjectRecord) => activityTargetObjectRecord.activityTarget,
);
let activityTargetsAfterUpdate = Array.from(existingActivityTargets);
const activityTargetsToCreate = selectedTargetObjectsToCreate.map(
(selectedRecord) => {
const emptyActivityTarget =
generateObjectRecordOptimisticResponse<ActivityTarget>({
id: v4(),
activityId: activity.id,
activity,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
[getActivityTargetObjectFieldIdName({
nameSingular: selectedRecord.objectMetadataItem.nameSingular,
})]: selectedRecord.recordIdentifier.id,
});
return emptyActivityTarget;
},
);
activityTargetsAfterUpdate.push(...activityTargetsToCreate);
if (isNonEmptyArray(activityTargetsToDelete)) {
activityTargetsAfterUpdate = activityTargetsAfterUpdate.filter(
(activityTarget) =>
!activityTargetsToDelete.some(
(activityTargetToDelete) =>
activityTargetToDelete.activityTarget.id === activityTarget.id,
),
);
}
injectIntoActivityTargetInlineCellCache({
activityId: activity.id,
activityTargetsToInject: activityTargetsAfterUpdate,
});
if (isActivityInCreateMode) {
upsertActivity({
activity,
input: {
activityTargets: activityTargetsAfterUpdate,
},
});
} else {
if (activityTargetsToCreate.length > 0) {
await createManyActivityTargets(activityTargetsToCreate, {
skipOptimisticEffect: true,
});
}
if (activityTargetsToDelete.length > 0) {
await deleteManyActivityTargets(
activityTargetsToDelete.map(
(activityTargetObjectRecord) =>
activityTargetObjectRecord.activityTarget.id,
),
{
skipOptimisticEffect: true,
},
);
}
}
};
const handleCancel = () => {
closeEditableField();
};
return (
<StyledSelectContainer>
<MultipleObjectRecordSelect
selectedObjectRecordIds={selectedTargetObjectIds}
onCancel={handleCancel}
onSubmit={handleSubmit}
/>
</StyledSelectContainer>
);
};