Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import {
ActionRow,
Button,
Expand All @@ -9,17 +8,29 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';
import LoadingButton from '../loading-button';

interface DeleteModalProps {
isOpen: boolean;
close: () => void;
category?: string;
onDeleteSubmit: () => void | Promise<void>;
title?: string;
description?: React.ReactNode | React.ReactNode[];
variant?: string;
btnLabel?: string;
icon?: React.ElementType;
}

const DeleteModal = ({
category,
category = '',
isOpen,
close,
onDeleteSubmit,
title,
description,
variant,
variant = 'default',
btnLabel,
icon,
}) => {
}: DeleteModalProps) => {
const intl = useIntl();

const modalTitle = title || intl.formatMessage(messages.title, { category });
Expand Down Expand Up @@ -62,28 +73,4 @@ const DeleteModal = ({
);
};

DeleteModal.defaultProps = {
category: '',
title: '',
description: '',
variant: 'default',
btnLabel: '',
icon: null,
};

DeleteModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
close: PropTypes.func.isRequired,
category: PropTypes.string,
onDeleteSubmit: PropTypes.func.isRequired,
title: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.element,
PropTypes.string,
]),
variant: PropTypes.string,
btnLabel: PropTypes.string,
icon: PropTypes.elementType,
};

export default DeleteModal;
2 changes: 1 addition & 1 deletion src/library-authoring/LibraryAuthoringPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ const LibraryAuthoringPage = ({
[ContentType.units]: intl.formatMessage(messages.unitsTab),
};
const visibleTabsToRender = visibleTabs.map((contentType) => (
<Tab eventKey={contentType} title={tabTitles[contentType]} />
<Tab key={contentType} eventKey={contentType} title={tabTitles[contentType]} />

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to the issues, but this was raising an error on the console.

));

return (
Expand Down
30 changes: 19 additions & 11 deletions src/library-authoring/components/ComponentDeleter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useContext } from 'react';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { Warning } from '@openedx/paragon/icons';
import { Icon } from '@openedx/paragon';
import { CalendarViewDay, School, Warning } from '@openedx/paragon/icons';

import { useSidebarContext } from '../common/context/SidebarContext';
import { useDeleteLibraryBlock, useLibraryBlockMetadata, useRestoreLibraryBlock } from '../data/apiHooks';
Expand Down Expand Up @@ -66,23 +67,30 @@ const ComponentDeleter = ({ usageKey, ...props }: Props) => {
return null;
}

const deleteText = intl.formatMessage(messages.deleteComponentConfirm, {
componentName: <b><BlockName usageKey={usageKey} /></b>,
message: (
<>
<div className="d-flex mt-2">
<Icon className="mr-2" src={School} />
{intl.formatMessage(messages.deleteComponentConfirmMsg1)}
</div>
<div className="d-flex mt-2">
<Icon className="mr-2" src={CalendarViewDay} />
{intl.formatMessage(messages.deleteComponentConfirmMsg2)}
</div>
</>
),
});

return (
<DeleteModal
isOpen
close={props.cancelDelete}
variant="warning"
title={intl.formatMessage(messages.deleteComponentWarningTitle)}
icon={Warning}
description={(
<FormattedMessage
{...messages.deleteComponentConfirm}
values={{
componentName: (
<strong><BlockName usageKey={usageKey} /></strong>
),
}}
/>
)}
description={deleteText}
onDeleteSubmit={doDelete}
/>
);
Expand Down
4 changes: 2 additions & 2 deletions src/library-authoring/components/ContainerDeleter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, useCallback, useContext } from 'react';
import { useCallback, useContext } from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Icon } from '@openedx/paragon';
import { Warning, School, Widgets } from '@openedx/paragon/icons';
Expand Down Expand Up @@ -47,7 +47,7 @@ const ContainerDeleter = ({
</div>
</>
),
}) as ReactNode as string;
});
const deleteSuccess = intl.formatMessage(messages.deleteUnitSuccess);
const deleteError = intl.formatMessage(messages.deleteUnitFailed);
const undoDeleteError = messages.undoDeleteUnitToastFailed;
Expand Down
12 changes: 11 additions & 1 deletion src/library-authoring/components/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,19 @@ const messages = defineMessages({
},
deleteComponentConfirm: {
id: 'course-authoring.library-authoring.component.delete-confirmation-text',
defaultMessage: 'Delete {componentName}? If this component has been used in a course, those copies won\'t be deleted, but they will no longer receive updates from the library.',
defaultMessage: 'Delete {componentName}? {message}',
description: 'Confirmation text to display before deleting a component',
},
deleteComponentConfirmMsg1: {
id: 'course-authoring.library-authoring.component.delete-confirmation-msg-1',
defaultMessage: 'If this component has been used in a course, those copies won\'t be deleted, but they will no longer receive updates from the library.',
description: 'First part of confirmation message to display before deleting a component',
},
deleteComponentConfirmMsg2: {
id: 'course-authoring.library-authoring.component.delete-confirmation-msg-2',
defaultMessage: 'If this component has been used in any units, it will also be deleted from those units.',
description: 'Second part of confirmation message to display before deleting a component',
},
deleteComponentCancelButton: {
id: 'course-authoring.library-authoring.component.cancel-delete-button',
defaultMessage: 'Cancel',
Expand Down
17 changes: 13 additions & 4 deletions src/library-authoring/data/apiHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,13 +642,22 @@ export const useAddComponentsToContainer = (containerId?: string) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (componentIds: string[]) => {
if (containerId !== undefined) {
return api.addComponentsToContainer(containerId, componentIds);
// istanbul ignore if: this should never happen
if (!containerId) {
return undefined;
}
return undefined;
return api.addComponentsToContainer(containerId, componentIds);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: libraryAuthoringQueryKeys.containerChildren(containerId!) });
// istanbul ignore if: this should never happen
if (!containerId) {
return;
}
// NOTE: We invalidate the library query here because we need to update the library's
// container list.
const libraryId = getLibraryId(containerId);
queryClient.invalidateQueries({ queryKey: libraryAuthoringQueryKeys.containerChildren(containerId) });
queryClient.invalidateQueries({ predicate: (query) => libraryQueryPredicate(query, libraryId) });
},
});
};
Expand Down