diff --git a/src/index.scss b/src/index.scss
index f1e1999361..480e868998 100755
--- a/src/index.scss
+++ b/src/index.scss
@@ -19,4 +19,4 @@
@import "course-updates/CourseUpdates";
@import "export-page/CourseExportPage";
@import "import-page/CourseImportPage";
-@import "taxonomy/TaxonomyCard.scss";
+@import "taxonomy/taxonomy-card/TaxonomyCard.scss";
diff --git a/src/taxonomy/TaxonomyListPage.jsx b/src/taxonomy/TaxonomyListPage.jsx
index 6026e34d27..bf285133dc 100644
--- a/src/taxonomy/TaxonomyListPage.jsx
+++ b/src/taxonomy/TaxonomyListPage.jsx
@@ -9,7 +9,7 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import Header from '../header';
import SubHeader from '../generic/sub-header/SubHeader';
import messages from './messages';
-import TaxonomyCard from './TaxonomyCard';
+import TaxonomyCard from './taxonomy-card/TaxonomyCard';
import { useTaxonomyListDataResponse, useIsTaxonomyListDataLoaded } from './api/hooks/selectors';
const TaxonomyListPage = ({ intl }) => {
diff --git a/src/taxonomy/messages.js b/src/taxonomy/messages.js
index f64a56156c..24f80bf6da 100644
--- a/src/taxonomy/messages.js
+++ b/src/taxonomy/messages.js
@@ -45,6 +45,30 @@ const messages = defineMessages({
id: 'course-authoring.taxonomy-list.menu.alt',
defaultMessage: '{name} menu',
},
+ exportModalTitle: {
+ id: 'course-authoring.taxonomy-list.modal.export.title',
+ defaultMessage: 'Select format to export',
+ },
+ exportModalBodyDescription: {
+ id: 'course-authoring.taxonomy-list.modal.export.body',
+ defaultMessage: 'Select the file format in which you would like the taxonomy to be exported:',
+ },
+ exportModalSubmitButtonLabel: {
+ id: 'course-authoring.taxonomy-list.modal.export.submit.label',
+ defaultMessage: 'Export',
+ },
+ taxonomyCSVFormat: {
+ id: 'course-authoring.taxonomy-list.csv-format',
+ defaultMessage: 'CSV file',
+ },
+ taxonomyJSONFormat: {
+ id: 'course-authoring.taxonomy-list.json-format',
+ defaultMessage: 'JSON file',
+ },
+ taxonomyModalsCancelLabel: {
+ id: 'course-authoring.taxonomy-list.modal.cancel',
+ defaultMessage: 'Cancel',
+ },
});
export default messages;
diff --git a/src/taxonomy/modals/ExportModal.jsx b/src/taxonomy/modals/ExportModal.jsx
new file mode 100644
index 0000000000..360151dc1b
--- /dev/null
+++ b/src/taxonomy/modals/ExportModal.jsx
@@ -0,0 +1,79 @@
+import React, { useState } from 'react';
+import {
+ ActionRow,
+ Button,
+ Form,
+ ModalDialog,
+} from '@edx/paragon';
+import PropTypes from 'prop-types';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import messages from '../messages';
+
+const ExportModal = ({
+ taxonomyId,
+ isOpen,
+ onClose,
+ intl,
+}) => {
+ const [modalSize, setModalSize] = useState('csv');
+
+ return (
+
+
+
+ {intl.formatMessage(messages.exportModalTitle)}
+
+
+
+
+
+ {intl.formatMessage(messages.exportModalBodyDescription)}
+
+ setModalSize(e.target.value)}
+ >
+
+ {intl.formatMessage(messages.taxonomyCSVFormat)}
+
+
+ {intl.formatMessage(messages.taxonomyJSONFormat)}
+
+
+
+
+
+
+
+ {intl.formatMessage(messages.taxonomyModalsCancelLabel)}
+
+
+
+
+
+ );
+};
+
+ExportModal.propTypes = {
+ taxonomyId: PropTypes.number.isRequired,
+ isOpen: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(ExportModal);
diff --git a/src/taxonomy/TaxonomyCard.jsx b/src/taxonomy/taxonomy-card/TaxonomyCard.jsx
similarity index 54%
rename from src/taxonomy/TaxonomyCard.jsx
rename to src/taxonomy/taxonomy-card/TaxonomyCard.jsx
index c4d4c25d5a..df340fe1cf 100644
--- a/src/taxonomy/TaxonomyCard.jsx
+++ b/src/taxonomy/taxonomy-card/TaxonomyCard.jsx
@@ -1,31 +1,36 @@
import React, { useState } from 'react';
import {
Badge,
- IconButton,
Card,
OverlayTrigger,
Popover,
- ModalPopup,
- Menu,
- Icon,
- MenuItem,
} from '@edx/paragon';
-import { MoreVert } from '@edx/paragon/icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import classNames from 'classnames';
-import messages from './messages';
+import messages from '../messages';
+import TaxonomyCardMenu from './TaxonomyCardMenu';
+import ExportModal from '../modals/ExportModal';
const TaxonomyCard = ({ className, original, intl }) => {
const {
id, name, description, systemDefined, orgsCount,
} = original;
- const [menuIsOpen, setMenuIsOpen] = useState(false);
- const [menuTarget, setMenuTarget] = useState(null);
+ const [isExportModalOpen, setIsExportModalOpen] = useState(false);
const orgsCountEnabled = () => orgsCount !== undefined && orgsCount !== 0;
+ const onClickMenuItem = (menuName) => {
+ switch (menuName) {
+ case 'export':
+ setIsExportModalOpen(true);
+ break;
+ default:
+ break;
+ }
+ };
+
const getSystemBadgeToolTip = () => (
@@ -61,52 +66,42 @@ const TaxonomyCard = ({ className, original, intl }) => {
return undefined;
};
- const onClickExport = () => {
- setMenuIsOpen(false);
- };
-
const getHeaderActions = () => (
+
+ );
+
+ const renderModals = () => (
+ // eslint-disable-next-line react/jsx-no-useless-fragment
<>
- setMenuIsOpen(true)}
- ref={setMenuTarget}
- src={MoreVert}
- iconAs={Icon}
- alt={intl.formatMessage(messages.taxonomyMenuAlt, { name })}
- data-testid={`taxonomy-card-menu-button-${id}`}
- />
- setMenuIsOpen(false)}
- >
-
-
+ {isExportModalOpen && (
+ setIsExportModalOpen(false)}
+ />
+ )}
>
);
return (
-
-
-
-
- {description}
-
-
-
+ <>
+
+
+
+
+ {description}
+
+
+
+ {renderModals()}
+ >
);
};
diff --git a/src/taxonomy/TaxonomyCard.scss b/src/taxonomy/taxonomy-card/TaxonomyCard.scss
similarity index 100%
rename from src/taxonomy/TaxonomyCard.scss
rename to src/taxonomy/taxonomy-card/TaxonomyCard.scss
diff --git a/src/taxonomy/TaxonomyCard.test.jsx b/src/taxonomy/taxonomy-card/TaxonomyCard.test.jsx
similarity index 81%
rename from src/taxonomy/TaxonomyCard.test.jsx
rename to src/taxonomy/taxonomy-card/TaxonomyCard.test.jsx
index a4e192342a..91e76c984a 100644
--- a/src/taxonomy/TaxonomyCard.test.jsx
+++ b/src/taxonomy/taxonomy-card/TaxonomyCard.test.jsx
@@ -5,7 +5,7 @@ import { AppProvider } from '@edx/frontend-platform/react';
import { render, fireEvent } from '@testing-library/react';
import PropTypes from 'prop-types';
-import initializeStore from '../store';
+import initializeStore from '../../store';
import TaxonomyCard from './TaxonomyCard';
@@ -92,7 +92,7 @@ describe('', async () => {
// Click on the menu button to open
fireEvent.click(getByTestId('taxonomy-card-menu-button-1'));
- // Menu open
+ // Menu opened
expect(getByTestId('taxonomy-card-menu-1')).toBeInTheDocument();
// Click on any element to close the menu
@@ -101,4 +101,24 @@ describe('', async () => {
// Menu closed
expect(() => getByTestId('taxonomy-card-menu-1')).toThrow();
});
+
+ test('should open export modal on export menu click', () => {
+ const { getByTestId, getByText } = render();
+
+ // Modal closed
+ expect(() => getByText('Select format to export')).toThrow();
+
+ // Click on export menu
+ fireEvent.click(getByTestId('taxonomy-card-menu-button-1'));
+ fireEvent.click(getByText('Export'));
+
+ // Modal opened
+ expect(getByText('Select format to export')).toBeInTheDocument();
+
+ // Click on cancel button
+ fireEvent.click(getByText('Cancel'));
+
+ // Modal closed
+ expect(() => getByText('Select format to export')).toThrow();
+ });
});
diff --git a/src/taxonomy/taxonomy-card/TaxonomyCardMenu.jsx b/src/taxonomy/taxonomy-card/TaxonomyCardMenu.jsx
new file mode 100644
index 0000000000..87e1722f4e
--- /dev/null
+++ b/src/taxonomy/taxonomy-card/TaxonomyCardMenu.jsx
@@ -0,0 +1,58 @@
+import React, { useState } from 'react';
+import {
+ IconButton,
+ ModalPopup,
+ Menu,
+ Icon,
+ MenuItem,
+} from '@edx/paragon';
+import { MoreVert } from '@edx/paragon/icons';
+import PropTypes from 'prop-types';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import messages from '../messages';
+
+const TaxonomyCardMenu = ({
+ id, name, onClickMenuItem, intl,
+}) => {
+ const [menuIsOpen, setMenuIsOpen] = useState(false);
+ const [menuTarget, setMenuTarget] = useState(null);
+
+ const onClickItem = (menuName) => {
+ setMenuIsOpen(false);
+ onClickMenuItem(menuName);
+ };
+
+ return (
+ <>
+ setMenuIsOpen(true)}
+ ref={setMenuTarget}
+ src={MoreVert}
+ iconAs={Icon}
+ alt={intl.formatMessage(messages.taxonomyMenuAlt, { name })}
+ data-testid={`taxonomy-card-menu-button-${id}`}
+ />
+ setMenuIsOpen(false)}
+ >
+
+
+ >
+ );
+};
+
+TaxonomyCardMenu.propTypes = {
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ onClickMenuItem: PropTypes.func.isRequired,
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(TaxonomyCardMenu);