@@ -4,60 +4,101 @@ import { Warning } from '@openedx/paragon/icons';
44
55import DeleteModal from '@src/generic/delete-modal/DeleteModal' ;
66import { ToastContext } from '@src/generic/toast-context' ;
7- import { useLibraryContext } from '.. /common/context/LibraryContext' ;
8- import { useSidebarContext } from '.. /common/context/SidebarContext' ;
7+ import { useLibraryContext } from '@src/library-authoring /common/context/LibraryContext' ;
8+ import { useSidebarContext } from '@src/library-authoring /common/context/SidebarContext' ;
99import {
1010 useContainer ,
1111 useRemoveContainerChildren ,
12- useAddItemsToContainer ,
1312 useLibraryBlockMetadata ,
14- } from '../data/apiHooks' ;
13+ useContainerChildren ,
14+ useUpdateContainerChildren ,
15+ } from '@src/library-authoring/data/apiHooks' ;
16+ import { LibraryBlockMetadata } from '@src/library-authoring/data/api' ;
1517import messages from './messages' ;
1618
1719interface Props {
1820 usageKey : string ;
21+ index ?: number ;
1922 close : ( ) => void ;
2023}
2124
22- const ComponentRemover = ( { usageKey, close } : Props ) => {
25+ const ComponentRemover = ( { usageKey, index , close } : Props ) => {
2326 const intl = useIntl ( ) ;
2427 const { sidebarItemInfo, closeLibrarySidebar } = useSidebarContext ( ) ;
25- const { containerId } = useLibraryContext ( ) ;
28+ const { containerId, showOnlyPublished } = useLibraryContext ( ) ;
2629 const { showToast } = useContext ( ToastContext ) ;
2730
2831 const removeContainerItemMutation = useRemoveContainerChildren ( containerId ) ;
29- const addItemToContainerMutation = useAddItemsToContainer ( containerId ) ;
32+ const updateContainerChildrenMutation = useUpdateContainerChildren ( containerId ) ;
3033 const { data : container , isPending : isPendingParentContainer } = useContainer ( containerId ) ;
3134 const { data : component , isPending } = useLibraryBlockMetadata ( usageKey ) ;
35+ // Use update api for children if duplicates are present to avoid removing all instances of the child
36+ const { data : children } = useContainerChildren < LibraryBlockMetadata > ( containerId , showOnlyPublished ) ;
37+ const childrenUsageIds = children ?. map ( ( child ) => child . id ) ;
38+ const hasDuplicates = ( childrenUsageIds ?. filter ( ( child ) => child === usageKey ) . length || 0 ) > 1 ;
3239
3340 // istanbul ignore if: loading state
3441 if ( isPending || isPendingParentContainer ) {
3542 // Only show the modal when all data is ready
3643 return null ;
3744 }
3845
46+ const restoreComponent = ( ) => {
47+ // istanbul ignore if: this should never happen
48+ if ( ! childrenUsageIds ) {
49+ return ;
50+ }
51+ updateContainerChildrenMutation . mutateAsync ( childrenUsageIds ) . then ( ( ) => {
52+ showToast ( intl . formatMessage ( messages . undoRemoveComponentFromContainerToastSuccess ) ) ;
53+ } ) . catch ( ( ) => {
54+ showToast ( intl . formatMessage ( messages . undoRemoveComponentFromContainerToastFailed ) ) ;
55+ } ) ;
56+ } ;
57+
58+ const showSuccessToast = ( ) => {
59+ showToast (
60+ intl . formatMessage ( messages . removeComponentFromContainerSuccess ) ,
61+ {
62+ label : intl . formatMessage ( messages . undoRemoveComponentFromContainerToastAction ) ,
63+ onClick : restoreComponent ,
64+ } ,
65+ ) ;
66+ } ;
67+
68+ const showFailureToast = ( ) => showToast ( intl . formatMessage ( messages . removeComponentFromContainerFailure ) ) ;
69+
3970 const removeFromContainer = ( ) => {
40- const restoreComponent = ( ) => {
41- addItemToContainerMutation . mutateAsync ( [ usageKey ] ) . then ( ( ) => {
42- showToast ( intl . formatMessage ( messages . undoRemoveComponentFromContainerToastSuccess ) ) ;
43- } ) . catch ( ( ) => {
44- showToast ( intl . formatMessage ( messages . undoRemoveComponentFromContainerToastFailed ) ) ;
45- } ) ;
46- } ;
4771 removeContainerItemMutation . mutateAsync ( [ usageKey ] ) . then ( ( ) => {
4872 if ( sidebarItemInfo ?. id === usageKey ) {
4973 // Close sidebar if current component is open
5074 closeLibrarySidebar ( ) ;
5175 }
52- showToast (
53- intl . formatMessage ( messages . removeComponentFromContainerSuccess ) ,
54- {
55- label : intl . formatMessage ( messages . undoRemoveComponentFromContainerToastAction ) ,
56- onClick : restoreComponent ,
57- } ,
58- ) ;
76+ showSuccessToast ( ) ;
77+ } ) . catch ( ( ) => {
78+ showFailureToast ( ) ;
79+ } ) ;
80+
81+ close ( ) ;
82+ } ;
83+
84+ const excludeOneInstance = ( ) => {
85+ if ( ! childrenUsageIds || typeof index === 'undefined' ) {
86+ return ;
87+ }
88+ const updatedKeys = childrenUsageIds . filter ( ( childId , idx ) => childId !== usageKey || idx !== index ) ;
89+ updateContainerChildrenMutation . mutateAsync ( updatedKeys ) . then ( ( ) => {
90+ // istanbul ignore if
91+ if ( sidebarItemInfo ?. id === usageKey && sidebarItemInfo ?. index === index ) {
92+ // Close sidebar if current component is open
93+ closeLibrarySidebar ( ) ;
94+ }
95+ // Already tested as part of removeFromContainer
96+ // istanbul ignore next
97+ showSuccessToast ( ) ;
5998 } ) . catch ( ( ) => {
60- showToast ( intl . formatMessage ( messages . removeComponentFromContainerFailure ) ) ;
99+ // Already tested as part of removeFromContainer
100+ // istanbul ignore next
101+ showFailureToast ( ) ;
61102 } ) ;
62103
63104 close ( ) ;
@@ -76,7 +117,7 @@ const ComponentRemover = ({ usageKey, close }: Props) => {
76117 title = { intl . formatMessage ( messages . removeComponentWarningTitle ) }
77118 icon = { Warning }
78119 description = { removeText }
79- onDeleteSubmit = { removeFromContainer }
120+ onDeleteSubmit = { hasDuplicates ? excludeOneInstance : removeFromContainer }
80121 btnLabel = { intl . formatMessage ( messages . componentRemoveButtonLabel ) }
81122 buttonVariant = "primary"
82123 />
0 commit comments