Add a confirmation modal for relation object deletion (#8818)
Fixes #8698
1. Summary
We decided to add a confirmation modal for the relation object deletion.
It's gonna a bit of safety to the user interactions because this action
can be disruptive even though it can be restored.
2. Solution
Used `createPortal` function to address the issue where the vertical
scrollbar shows over the modal. Added a logic that displays a
confirmation modal for deletion in [this
file](d284419d66/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx).
I can update the text(title, description, and CTA) as necessary based on
the feedback.
_**However, I observed an issue that the deleted object still shows up
under the list until hard-refresh. I figured that can be addressed as a
separate issue.**_
3. Recording
https://github.com/user-attachments/assets/1a64b702-a915-49f3-a226-2c2d5af8a1d7
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useCallback, useContext } from 'react';
|
import { useCallback, useContext, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
AnimatedEaseInOut,
|
AnimatedEaseInOut,
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
@ -17,6 +17,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
|||||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||||
|
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||||
import { RecordChip } from '@/object-record/components/RecordChip';
|
import { RecordChip } from '@/object-record/components/RecordChip';
|
||||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
@ -39,6 +40,8 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||||
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
import { RelationDefinitionType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
const StyledListItem = styled(RecordDetailRecordsListItem)<{
|
const StyledListItem = styled(RecordDetailRecordsListItem)<{
|
||||||
@ -94,6 +97,9 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
}: RecordDetailRelationRecordsListItemProps) => {
|
}: RecordDetailRelationRecordsListItemProps) => {
|
||||||
const { fieldDefinition } = useContext(FieldContext);
|
const { fieldDefinition } = useContext(FieldContext);
|
||||||
|
|
||||||
|
const [isDeleteRelationModalOpen, setIsDeleteRelationModalOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
relationFieldMetadataId,
|
relationFieldMetadataId,
|
||||||
relationObjectMetadataNameSingular,
|
relationObjectMetadataNameSingular,
|
||||||
@ -106,6 +112,10 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
objectNameSingular: relationObjectMetadataNameSingular,
|
objectNameSingular: relationObjectMetadataNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const relationObjectTypeName = getObjectTypename(
|
||||||
|
relationObjectMetadataNameSingular,
|
||||||
|
);
|
||||||
|
|
||||||
const { objectMetadataItems } = useObjectMetadataItems();
|
const { objectMetadataItems } = useObjectMetadataItems();
|
||||||
|
|
||||||
const persistField = usePersistField();
|
const persistField = usePersistField();
|
||||||
@ -158,8 +168,13 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
|
setIsDeleteRelationModalOpen(true);
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirmDelete = async () => {
|
||||||
await deleteOneRelationRecord(relationRecord.id);
|
await deleteOneRelationRecord(relationRecord.id);
|
||||||
|
setIsDeleteRelationModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useUpdateOneObjectRecordMutation: RecordUpdateHook = () => {
|
const useUpdateOneObjectRecordMutation: RecordUpdateHook = () => {
|
||||||
@ -268,6 +283,24 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
)}
|
)}
|
||||||
</StyledPropertyBox>
|
</StyledPropertyBox>
|
||||||
</AnimatedEaseInOut>
|
</AnimatedEaseInOut>
|
||||||
|
{createPortal(
|
||||||
|
<ConfirmationModal
|
||||||
|
isOpen={isDeleteRelationModalOpen}
|
||||||
|
setIsOpen={setIsDeleteRelationModalOpen}
|
||||||
|
title={`Delete Related ${relationObjectTypeName}`}
|
||||||
|
subtitle={
|
||||||
|
<>
|
||||||
|
Are you sure you want to delete this related{' '}
|
||||||
|
{relationObjectMetadataNameSingular}?
|
||||||
|
<br />
|
||||||
|
This action will break all its relationships with other objects.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
onConfirmClick={handleConfirmDelete}
|
||||||
|
deleteButtonText={`Delete ${relationObjectTypeName}`}
|
||||||
|
/>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user