diff --git a/src/actions/page-template-actions.js b/src/actions/page-template-actions.js
index 9283195ef..1fa0f7fab 100644
--- a/src/actions/page-template-actions.js
+++ b/src/actions/page-template-actions.js
@@ -32,6 +32,7 @@ import {
PAGES_MODULE_KINDS
} from "../utils/constants";
import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions";
+import { GLOBAL_PAGE_CLONED } from "./sponsor-pages-actions";
export const ADD_PAGE_TEMPLATE = "ADD_PAGE_TEMPLATE";
export const PAGE_TEMPLATE_ADDED = "PAGE_TEMPLATE_ADDED";
@@ -171,7 +172,7 @@ const normalizeEntity = (entity) => {
return normalizedEntity;
};
-export const savePageTemplate = (entity) => async (dispatch, getState) => {
+export const savePageTemplate = (entity) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const params = {
access_token: accessToken
@@ -197,7 +198,7 @@ export const savePageTemplate = (entity) => async (dispatch, getState) => {
html: T.translate("page_template_list.page_crud.page_saved")
})
);
- getPageTemplates()(dispatch, getState);
+ getPageTemplates()(dispatch);
})
.catch((err) => {
console.error(err);
@@ -222,7 +223,7 @@ export const savePageTemplate = (entity) => async (dispatch, getState) => {
html: T.translate("page_template_list.page_crud.page_created")
})
);
- getPageTemplates()(dispatch, getState);
+ getPageTemplates()(dispatch);
})
.catch((err) => {
console.error(err);
@@ -263,3 +264,32 @@ export const unarchivePageTemplate = (pageTemplateId) => async (dispatch) => {
dispatch(stopLoading());
});
};
+
+export const clonePageTemplate = (templateId) => async (dispatch) => {
+ const accessToken = await getAccessTokenSafely();
+
+ dispatch(startLoading());
+
+ const params = {
+ access_token: accessToken
+ };
+
+ return postRequest(
+ null,
+ createAction(GLOBAL_PAGE_CLONED),
+ `${window.SPONSOR_PAGES_API_URL}/api/v1/page-templates/${templateId}/clone`,
+ {},
+ snackbarErrorHandler
+ )(params)(dispatch)
+ .then(() => {
+ getPageTemplates()(dispatch);
+ dispatch(
+ snackbarSuccessHandler({
+ title: T.translate("general.success"),
+ html: T.translate("page_template_list.clone_success")
+ })
+ );
+ })
+ .catch(console.error)
+ .finally(() => dispatch(stopLoading()));
+};
diff --git a/src/actions/sponsor-pages-actions.js b/src/actions/sponsor-pages-actions.js
index cb7355d1d..e71feb99a 100644
--- a/src/actions/sponsor-pages-actions.js
+++ b/src/actions/sponsor-pages-actions.js
@@ -21,7 +21,6 @@ import {
} from "openstack-uicore-foundation/lib/utils/actions";
import T from "i18n-react/dist/i18n-react";
import { escapeFilterValue, getAccessTokenSafely } from "../utils/methods";
-import { getSponsorForms } from "./sponsor-forms-actions";
import {
DEFAULT_CURRENT_PAGE,
DEFAULT_ORDER_DIR,
@@ -123,7 +122,7 @@ export const cloneGlobalPage =
snackbarErrorHandler
)(params)(dispatch)
.then(() => {
- dispatch(getSponsorForms());
+ dispatch(getSponsorPages());
dispatch(
snackbarSuccessHandler({
title: T.translate("general.success"),
diff --git a/src/components/select-page-template-dialog/__tests__/select-page-template-dialog.test.js b/src/components/select-page-template-dialog/__tests__/select-page-template-dialog.test.js
new file mode 100644
index 000000000..6875e2811
--- /dev/null
+++ b/src/components/select-page-template-dialog/__tests__/select-page-template-dialog.test.js
@@ -0,0 +1,382 @@
+// ---- Mocks must come first ----
+
+// i18n translate: echo the key
+import React from "react";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import "@testing-library/jest-dom";
+import { Provider } from "react-redux";
+import configureMockStore from "redux-mock-store";
+import thunk from "redux-thunk";
+import SelectPageTemplateDialog from "../index";
+
+jest.mock("i18n-react/dist/i18n-react", () => ({
+ __esModule: true,
+ default: { translate: (key) => key }
+}));
+
+// Mock Redux actions
+jest.mock("../../../actions/page-template-actions", () => ({
+ getPageTemplates: jest.fn(() => () => Promise.resolve())
+}));
+
+// Avoid MUI ripple noise
+jest.mock("@mui/material/IconButton", () => {
+ const React = require("react");
+ return {
+ __esModule: true,
+ default: ({ children, onClick, ...rest }) => (
+
+ )
+ };
+});
+jest.mock("@mui/material/ButtonBase/TouchRipple", () => ({
+ __esModule: true,
+ default: () => null
+}));
+
+const middlewares = [thunk];
+const mockStore = configureMockStore(middlewares);
+
+// Mock page templates data
+const mockPageTemplates = [
+ {
+ id: 1,
+ code: "TPL001",
+ name: "Template One",
+ info_mod: "Info Module 1",
+ download_mod: "Download Module 1",
+ upload_mod: "Upload Module 1"
+ },
+ {
+ id: 2,
+ code: "TPL002",
+ name: "Template Two",
+ info_mod: "Info Module 2",
+ download_mod: "Download Module 2",
+ upload_mod: "Upload Module 2"
+ },
+ {
+ id: 3,
+ code: "TPL003",
+ name: "Template Three",
+ info_mod: "Info Module 3",
+ download_mod: "Download Module 3",
+ upload_mod: "Upload Module 3"
+ }
+];
+
+// Helper function to render the component with Redux store
+const renderWithStore = (props, storeState = {}) => {
+ const defaultState = {
+ pageTemplateListState: {
+ pageTemplates: mockPageTemplates,
+ currentPage: 1,
+ term: "",
+ order: "id",
+ orderDir: 1,
+ total: mockPageTemplates.length,
+ ...storeState
+ }
+ };
+
+ const store = mockStore(defaultState);
+
+ return render(
+
+
+
+ );
+};
+
+describe("SelectPageTemplateDialog", () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe("Component Initialization", () => {
+ test("renders the dialog with title", () => {
+ renderWithStore();
+
+ expect(
+ screen.getByText("sponsor_pages.global_page_popup.title")
+ ).toBeInTheDocument();
+ });
+
+ test("calls getPageTemplates on mount", () => {
+ const {
+ getPageTemplates
+ } = require("../../../actions/page-template-actions");
+
+ renderWithStore();
+
+ expect(getPageTemplates).toHaveBeenCalledWith("", 1, 10, "id", 1, true);
+ });
+
+ test("displays initial selection count as 0", () => {
+ renderWithStore();
+
+ expect(screen.getByText("0 items selected")).toBeInTheDocument();
+ });
+
+ test("renders close button", () => {
+ renderWithStore();
+
+ const closeButton = screen.getByRole("button", { name: "" });
+ expect(closeButton).toBeInTheDocument();
+ });
+
+ test("renders search input", () => {
+ renderWithStore();
+
+ expect(
+ screen.getByPlaceholderText("sponsor_pages.placeholders.search")
+ ).toBeInTheDocument();
+ });
+
+ test("renders save button as disabled initially", () => {
+ renderWithStore();
+
+ const saveButton = screen.getByRole("button", {
+ name: "sponsor_pages.global_page_popup.add_selected"
+ });
+ expect(saveButton).toBeDisabled();
+ });
+
+ test("renders all page templates in table", () => {
+ renderWithStore();
+
+ expect(screen.getByText("TPL001")).toBeInTheDocument();
+ expect(screen.getByText("Template One")).toBeInTheDocument();
+ expect(screen.getByText("TPL002")).toBeInTheDocument();
+ expect(screen.getByText("Template Two")).toBeInTheDocument();
+ });
+ });
+
+ describe("Multi-selection mode (isMulti=true)", () => {
+ test("renders checkboxes when isMulti is true", () => {
+ renderWithStore({ isMulti: true });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+ expect(checkboxes.length).toBe(mockPageTemplates.length);
+ });
+
+ test("allows selecting multiple items", async () => {
+ renderWithStore({ isMulti: true });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+
+ // Select first checkbox
+ await userEvent.click(checkboxes[0]);
+ expect(screen.getByText("1 items selected")).toBeInTheDocument();
+
+ // Select second checkbox
+ await userEvent.click(checkboxes[1]);
+ expect(screen.getByText("2 items selected")).toBeInTheDocument();
+ });
+
+ test("allows deselecting items", async () => {
+ renderWithStore({ isMulti: true });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+
+ // Select and deselect first checkbox
+ await userEvent.click(checkboxes[0]);
+ expect(screen.getByText("1 items selected")).toBeInTheDocument();
+
+ await userEvent.click(checkboxes[0]);
+ expect(screen.getByText("0 items selected")).toBeInTheDocument();
+ });
+
+ test("enables save button when items are selected", async () => {
+ renderWithStore({ isMulti: true });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+ const saveButton = screen.getByRole("button", {
+ name: "sponsor_pages.global_page_popup.add_selected"
+ });
+
+ expect(saveButton).toBeDisabled();
+
+ await userEvent.click(checkboxes[0]);
+
+ expect(saveButton).not.toBeDisabled();
+ });
+
+ test("calls onSave with all selected row IDs", async () => {
+ const onSave = jest.fn();
+ renderWithStore({ isMulti: true, onSave });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+
+ // Select first and third items
+ await userEvent.click(checkboxes[0]);
+ await userEvent.click(checkboxes[2]);
+
+ const saveButton = screen.getByRole("button", {
+ name: "sponsor_pages.global_page_popup.add_selected"
+ });
+ await userEvent.click(saveButton);
+
+ expect(onSave).toHaveBeenCalledWith([1, 3]);
+ });
+ });
+
+ describe("Single-selection mode (isMulti=false)", () => {
+ test("renders radio buttons when isMulti is false", () => {
+ renderWithStore({ isMulti: false });
+
+ const radioButtons = screen.getAllByRole("radio");
+ expect(radioButtons.length).toBe(mockPageTemplates.length);
+ });
+
+ test("allows selecting only one item at a time", async () => {
+ renderWithStore({ isMulti: false });
+
+ const radioButtons = screen.getAllByRole("radio");
+
+ // Select first radio
+ await userEvent.click(radioButtons[0]);
+ expect(screen.getByText("1 items selected")).toBeInTheDocument();
+ expect(radioButtons[0]).toBeChecked();
+
+ // Select second radio - should deselect first
+ await userEvent.click(radioButtons[1]);
+ expect(screen.getByText("1 items selected")).toBeInTheDocument();
+ expect(radioButtons[0]).not.toBeChecked();
+ expect(radioButtons[1]).toBeChecked();
+ });
+
+ test("enables save button when one item is selected", async () => {
+ renderWithStore({ isMulti: false });
+
+ const radioButtons = screen.getAllByRole("radio");
+ const saveButton = screen.getByRole("button", {
+ name: "sponsor_pages.global_page_popup.add_selected"
+ });
+
+ expect(saveButton).toBeDisabled();
+
+ await userEvent.click(radioButtons[0]);
+
+ expect(saveButton).not.toBeDisabled();
+ });
+
+ test("calls onSave with single selected row ID", async () => {
+ const onSave = jest.fn();
+ renderWithStore({ isMulti: false, onSave });
+
+ const radioButtons = screen.getAllByRole("radio");
+
+ await userEvent.click(radioButtons[1]);
+
+ const saveButton = screen.getByRole("button", {
+ name: "sponsor_pages.global_page_popup.add_selected"
+ });
+ await userEvent.click(saveButton);
+
+ expect(onSave).toHaveBeenCalledWith([2]);
+ });
+ });
+
+ describe("Search functionality", () => {
+ test("calls getPageTemplates with search term", async () => {
+ const {
+ getPageTemplates
+ } = require("../../../actions/page-template-actions");
+ renderWithStore();
+
+ const searchInput = screen.getByPlaceholderText(
+ "sponsor_pages.placeholders.search"
+ );
+
+ await userEvent.type(searchInput, "Template");
+ await userEvent.keyboard("{Enter}");
+
+ await waitFor(() => {
+ expect(getPageTemplates).toHaveBeenCalledWith(
+ "Template",
+ 1,
+ 10,
+ "id",
+ 1,
+ true
+ );
+ });
+ });
+ });
+
+ describe("Close functionality", () => {
+ test("calls onClose when close button is clicked", async () => {
+ const onClose = jest.fn();
+ renderWithStore({ onClose });
+
+ const closeButton = screen.getByRole("button", { name: "" });
+ await userEvent.click(closeButton);
+
+ expect(onClose).toHaveBeenCalled();
+ });
+
+ test("resets selected rows when closing", async () => {
+ const onClose = jest.fn();
+ renderWithStore({ isMulti: true, onClose });
+
+ const checkboxes = screen.getAllByRole("checkbox");
+
+ // Select an item
+ await userEvent.click(checkboxes[0]);
+ expect(screen.getByText("1 items selected")).toBeInTheDocument();
+
+ // Close dialog
+ const closeButton = screen.getByRole("button", { name: "" });
+ await userEvent.click(closeButton);
+
+ expect(onClose).toHaveBeenCalled();
+ });
+ });
+
+ describe("Load more functionality", () => {
+ test("calls getPageTemplates to load more when scrolling", () => {
+ const {
+ getPageTemplates
+ } = require("../../../actions/page-template-actions");
+ renderWithStore({}, { total: 20 }); // More items available than displayed
+
+ // The component should be rendered with loadMoreData available
+ // This would typically be triggered by scrolling in the MuiInfiniteTable
+ // The test verifies the component is set up with the correct total
+ expect(getPageTemplates).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe("Sorting functionality", () => {
+ test("calls getPageTemplates with sort parameters", () => {
+ const {
+ getPageTemplates
+ } = require("../../../actions/page-template-actions");
+ renderWithStore();
+
+ // Initial call on mount
+ expect(getPageTemplates).toHaveBeenCalledWith("", 1, 10, "id", 1, true);
+
+ // The actual sort interaction would be handled by MuiInfiniteTable
+ // This test verifies the component is initialized with correct sort params
+ });
+ });
+
+ describe("Empty state", () => {
+ test("renders nothing when no templates are available", () => {
+ renderWithStore({}, { pageTemplates: [] });
+
+ // Table headers might still be present, but no template rows
+ expect(screen.queryByText("TPL001")).not.toBeInTheDocument();
+ expect(screen.queryByText("Template One")).not.toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/pages/sponsors/sponsor-pages-list-page/components/global-page/select-pages-dialog.js b/src/components/select-page-template-dialog/index.js
similarity index 74%
rename from src/pages/sponsors/sponsor-pages-list-page/components/global-page/select-pages-dialog.js
rename to src/components/select-page-template-dialog/index.js
index 2a8e4a2b4..f52f696bf 100644
--- a/src/pages/sponsors/sponsor-pages-list-page/components/global-page/select-pages-dialog.js
+++ b/src/components/select-page-template-dialog/index.js
@@ -13,17 +13,17 @@ import {
FormControlLabel,
Grid2,
IconButton,
+ Radio,
Typography
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
-import SearchInput from "../../../../../components/mui/search-input";
-import { getPageTemplates } from "../../../../../actions/page-template-actions";
-import { DEFAULT_PER_PAGE } from "../../../../../utils/constants";
-import MuiInfiniteTable from "../../../../../components/mui/infinite-table";
+import SearchInput from "../mui/search-input";
+import { getPageTemplates } from "../../actions/page-template-actions";
+import { DEFAULT_PER_PAGE } from "../../utils/constants";
+import MuiInfiniteTable from "../mui/infinite-table";
-const SelectPagesDialog = ({
+const SelectPageTemplateDialog = ({
pageTemplates,
- items,
currentPage,
term,
order,
@@ -31,6 +31,7 @@ const SelectPagesDialog = ({
total,
onSave,
onClose,
+ isMulti = false,
getPageTemplates
}) => {
const [selectedRows, setSelectedRows] = useState([]);
@@ -44,7 +45,7 @@ const SelectPagesDialog = ({
};
const handleLoadMore = () => {
- if (total > items.length) {
+ if (total > pageTemplates.length) {
getPageTemplates(
term,
currentPage + 1,
@@ -62,10 +63,15 @@ const SelectPagesDialog = ({
};
const handleOnCheck = (rowId, checked) => {
- if (checked) {
- setSelectedRows([...selectedRows, rowId]);
+ if (isMulti) {
+ if (checked) {
+ setSelectedRows([...selectedRows, rowId]);
+ } else {
+ setSelectedRows(selectedRows.filter((r) => r !== rowId));
+ }
} else {
- setSelectedRows(selectedRows.filter((r) => r !== rowId));
+ // For single selection (radio), always set to the selected row
+ setSelectedRows(checked ? [rowId] : []);
}
};
@@ -83,17 +89,28 @@ const SelectPagesDialog = ({
header: "",
width: 30,
align: "center",
- render: (row) => (
- handleOnCheck(row.id, ev.target.checked)}
- />
- }
- />
- )
+ render: (row) =>
+ isMulti ? (
+ handleOnCheck(row.id, ev.target.checked)}
+ />
+ }
+ />
+ ) : (
+ handleOnCheck(row.id, ev.target.checked)}
+ />
+ }
+ />
+ )
},
{
columnKey: "code",
@@ -177,7 +194,7 @@ const SelectPagesDialog = ({
);
};
-SelectPagesDialog.propTypes = {
+SelectPageTemplateDialog.propTypes = {
onClose: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired
};
@@ -188,4 +205,4 @@ const mapStateToProps = ({ pageTemplateListState }) => ({
export default connect(mapStateToProps, {
getPageTemplates
-})(SelectPagesDialog);
+})(SelectPageTemplateDialog);
diff --git a/src/i18n/en.json b/src/i18n/en.json
index abea35a2c..9170f97b4 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -3965,6 +3965,7 @@
"max_file_size": "Max File Size (MB)",
"allowed_formats": "Allowed Formats",
"module_remove_warning": "Are you sure you want to delete {name}"
- }
+ },
+ "clone_success": "Page template cloned successfully."
}
}
diff --git a/src/pages/sponsors-global/page-templates/page-template-clone-popup/index.js b/src/pages/sponsors-global/page-templates/page-template-clone-popup/index.js
new file mode 100644
index 000000000..39c2f6bf7
--- /dev/null
+++ b/src/pages/sponsors-global/page-templates/page-template-clone-popup/index.js
@@ -0,0 +1,31 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { connect } from "react-redux";
+import { Dialog } from "@mui/material";
+import SelectPageTemplateDialog from "../../../../components/select-page-template-dialog";
+import { clonePageTemplate } from "../../../../actions/page-template-actions";
+
+const PageTemplateClonePopup = ({ open, onClose, clonePageTemplate }) => {
+ const handleOnSave = (template) => {
+ clonePageTemplate(template).finally(() => {
+ onClose();
+ });
+ };
+
+ return (
+
+ );
+};
+
+PageTemplateClonePopup.propTypes = {
+ open: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+};
+
+const mapStateToProps = () => ({});
+
+export default connect(mapStateToProps, {
+ clonePageTemplate
+})(PageTemplateClonePopup);
diff --git a/src/pages/sponsors-global/page-templates/page-template-list-page.js b/src/pages/sponsors-global/page-templates/page-template-list-page.js
index 34b09dd59..473b5fc0c 100644
--- a/src/pages/sponsors-global/page-templates/page-template-list-page.js
+++ b/src/pages/sponsors-global/page-templates/page-template-list-page.js
@@ -35,6 +35,7 @@ import MuiTable from "../../../components/mui/table/mui-table";
import SearchInput from "../../../components/mui/search-input";
import { DEFAULT_CURRENT_PAGE } from "../../../utils/constants";
import PageTemplatePopup from "./page-template-popup";
+import PageTemplateClonePopup from "./page-template-clone-popup";
const PageTemplateListPage = ({
pageTemplates,
@@ -52,6 +53,7 @@ const PageTemplateListPage = ({
deletePageTemplate
}) => {
const [pageTemplateId, setPageTemplateId] = useState(null);
+ const [openCloneDialog, setOpenCloneDialog] = useState(false);
useEffect(() => {
getPageTemplates();
@@ -103,7 +105,7 @@ const PageTemplateListPage = ({
};
const handleClonePageTemplate = () => {
- console.log("CLONE PAGE");
+ setOpenCloneDialog(true);
};
const handleSavePageTemplate = (entity) => {
@@ -267,6 +269,10 @@ const PageTemplateListPage = ({
onClose={() => setPageTemplateId(null)}
onSave={handleSavePageTemplate}
/>
+ setOpenCloneDialog(false)}
+ />
);
};
diff --git a/src/pages/sponsors-global/page-templates/page-template-popup.js b/src/pages/sponsors-global/page-templates/page-template-popup/index.js
similarity index 98%
rename from src/pages/sponsors-global/page-templates/page-template-popup.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/index.js
index 586d76919..4514f8908 100644
--- a/src/pages/sponsors-global/page-templates/page-template-popup.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/index.js
@@ -18,12 +18,12 @@ import AddIcon from "@mui/icons-material/Add";
import CloseIcon from "@mui/icons-material/Close";
import { FormikProvider, useFormik } from "formik";
import * as yup from "yup";
-import MuiFormikTextField from "../../../components/mui/formik-inputs/mui-formik-textfield";
+import MuiFormikTextField from "../../../../components/mui/formik-inputs/mui-formik-textfield";
import PageModules from "./page-template-modules-form";
import {
PAGES_MODULE_KINDS,
PAGE_MODULES_MEDIA_TYPES
-} from "../../../utils/constants";
+} from "../../../../utils/constants";
const PageTemplatePopup = ({ pageTemplate, open, onClose, onSave }) => {
const handleClose = () => {
diff --git a/src/pages/sponsors-global/page-templates/modules/page-template-document-download-module.js b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-document-download-module.js
similarity index 89%
rename from src/pages/sponsors-global/page-templates/modules/page-template-document-download-module.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-document-download-module.js
index 86c4b25f4..029a92a19 100644
--- a/src/pages/sponsors-global/page-templates/modules/page-template-document-download-module.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-document-download-module.js
@@ -3,8 +3,8 @@ import PropTypes from "prop-types";
import T from "i18n-react/dist/i18n-react";
import { Grid2, InputLabel } from "@mui/material";
-import MuiFormikUpload from "../../../../components/mui/formik-inputs/mui-formik-upload";
-import MuiFormikTextField from "../../../../components/mui/formik-inputs/mui-formik-textfield";
+import MuiFormikUpload from "../../../../../components/mui/formik-inputs/mui-formik-upload";
+import MuiFormikTextField from "../../../../../components/mui/formik-inputs/mui-formik-textfield";
const DocumentDownloadModule = ({ baseName, index }) => {
const buildFieldName = (field) => `${baseName}[${index}].${field}`;
diff --git a/src/pages/sponsors-global/page-templates/modules/page-template-info-module.js b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-info-module.js
similarity index 91%
rename from src/pages/sponsors-global/page-templates/modules/page-template-info-module.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-info-module.js
index f67549f29..86a8c0070 100644
--- a/src/pages/sponsors-global/page-templates/modules/page-template-info-module.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-info-module.js
@@ -3,7 +3,7 @@ import PropTypes from "prop-types";
import T from "i18n-react/dist/i18n-react";
import { Grid2, Box, InputLabel } from "@mui/material";
-import FormikTextEditor from "../../../../components/inputs/formik-text-editor";
+import FormikTextEditor from "../../../../../components/inputs/formik-text-editor";
const InfoModule = ({ baseName, index }) => {
const buildFieldName = (field) => `${baseName}[${index}].${field}`;
diff --git a/src/pages/sponsors-global/page-templates/modules/page-template-media-request-module.js b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-media-request-module.js
similarity index 85%
rename from src/pages/sponsors-global/page-templates/modules/page-template-media-request-module.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-media-request-module.js
index 1b6117eac..24269887a 100644
--- a/src/pages/sponsors-global/page-templates/modules/page-template-media-request-module.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/modules/page-template-media-request-module.js
@@ -3,12 +3,12 @@ import PropTypes from "prop-types";
import T from "i18n-react/dist/i18n-react";
import { useFormikContext, getIn } from "formik";
import { Grid2, Divider, InputLabel } from "@mui/material";
-import MuiFormikTextField from "../../../../components/mui/formik-inputs/mui-formik-textfield";
-import MuiFormikDatepicker from "../../../../components/mui/formik-inputs/mui-formik-datepicker";
-import MuiFormikRadioGroup from "../../../../components/mui/formik-inputs/mui-formik-radio-group";
-import { PAGE_MODULES_MEDIA_TYPES } from "../../../../utils/constants";
-import MuiFormikAsyncAutocomplete from "../../../../components/mui/formik-inputs/mui-formik-async-select";
-import { queryMediaFileTypes } from "../../../../actions/media-file-type-actions";
+import MuiFormikTextField from "../../../../../components/mui/formik-inputs/mui-formik-textfield";
+import MuiFormikDatepicker from "../../../../../components/mui/formik-inputs/mui-formik-datepicker";
+import MuiFormikRadioGroup from "../../../../../components/mui/formik-inputs/mui-formik-radio-group";
+import { PAGE_MODULES_MEDIA_TYPES } from "../../../../../utils/constants";
+import MuiFormikAsyncAutocomplete from "../../../../../components/mui/formik-inputs/mui-formik-async-select";
+import { queryMediaFileTypes } from "../../../../../actions/media-file-type-actions";
const MediaRequestModule = ({ baseName, index }) => {
const { values } = useFormikContext();
diff --git a/src/pages/sponsors-global/page-templates/page-template-module-form.test.js b/src/pages/sponsors-global/page-templates/page-template-popup/page-template-module-form.test.js
similarity index 95%
rename from src/pages/sponsors-global/page-templates/page-template-module-form.test.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/page-template-module-form.test.js
index 2277e4ff9..2a406b3be 100644
--- a/src/pages/sponsors-global/page-templates/page-template-module-form.test.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/page-template-module-form.test.js
@@ -4,17 +4,17 @@ import userEvent from "@testing-library/user-event";
import { Formik, Form, useFormikContext } from "formik";
import "@testing-library/jest-dom";
import PageModules from "./page-template-modules-form";
-import showConfirmDialog from "../../../components/mui/showConfirmDialog";
+import showConfirmDialog from "../../../../components/mui/showConfirmDialog";
import {
PAGES_MODULE_KINDS,
PAGE_MODULES_MEDIA_TYPES
-} from "../../../utils/constants";
+} from "../../../../utils/constants";
// Mocks
-jest.mock("../../../components/mui/showConfirmDialog", () => jest.fn());
+jest.mock("../../../../components/mui/showConfirmDialog", () => jest.fn());
jest.mock(
- "../../../components/inputs/formik-text-editor",
+ "../../../../components/inputs/formik-text-editor",
() =>
function MockFormikTextEditor({ name }) {
return ;
@@ -22,7 +22,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-upload",
+ "../../../../components/mui/formik-inputs/mui-formik-upload",
() =>
function MockMuiFormikUpload({ name }) {
return Upload
;
@@ -30,7 +30,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-textfield",
+ "../../../../components/mui/formik-inputs/mui-formik-textfield",
() =>
function MockMuiFormikTextField({ name }) {
return ;
@@ -38,7 +38,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-select",
+ "../../../../components/mui/formik-inputs/mui-formik-select",
() =>
function MockMuiFormikSelect({ name, children }) {
return ;
@@ -46,7 +46,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-datepicker",
+ "../../../../components/mui/formik-inputs/mui-formik-datepicker",
() =>
function MockMuiFormikDatepicker({ name }) {
return ;
@@ -54,7 +54,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-radio-group",
+ "../../../../components/mui/formik-inputs/mui-formik-radio-group",
() =>
function MockMuiFormikRadioGroup({ name }) {
return ;
@@ -62,7 +62,7 @@ jest.mock(
);
jest.mock(
- "../../../components/mui/formik-inputs/mui-formik-async-select",
+ "../../../../components/mui/formik-inputs/mui-formik-async-select",
() =>
function MockMuiFormikAsyncSelect({ name }) {
return ;
@@ -72,7 +72,7 @@ jest.mock(
// Mock DragAndDropList to capture onReorder
let capturedOnReorder = null;
jest.mock(
- "../../../components/mui/dnd-list",
+ "../../../../components/mui/dnd-list",
() =>
function MockDragAndDropList({ items, renderItem, onReorder }) {
capturedOnReorder = onReorder;
diff --git a/src/pages/sponsors-global/page-templates/page-template-modules-form.js b/src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
similarity index 96%
rename from src/pages/sponsors-global/page-templates/page-template-modules-form.js
rename to src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
index f66c03c34..350a54273 100644
--- a/src/pages/sponsors-global/page-templates/page-template-modules-form.js
+++ b/src/pages/sponsors-global/page-templates/page-template-popup/page-template-modules-form.js
@@ -13,9 +13,9 @@ import {
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import DeleteIcon from "@mui/icons-material/Delete";
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
-import DragAndDropList from "../../../components/mui/dnd-list";
-import showConfirmDialog from "../../../components/mui/showConfirmDialog";
-import { PAGES_MODULE_KINDS } from "../../../utils/constants";
+import DragAndDropList from "../../../../components/mui/dnd-list";
+import showConfirmDialog from "../../../../components/mui/showConfirmDialog";
+import { PAGES_MODULE_KINDS } from "../../../../utils/constants";
import InfoModule from "./modules/page-template-info-module";
import DocumentDownloadModule from "./modules/page-template-document-download-module";
import MediaRequestModule from "./modules/page-template-media-request-module";
diff --git a/src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js b/src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js
index 327dd6a34..2416fa1a6 100644
--- a/src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js
+++ b/src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Dialog } from "@mui/material";
-import SelectPagesDialog from "./select-pages-dialog";
+import SelectPageTemplateDialog from "../../../../../components/select-page-template-dialog";
import SelectSponsorshipsDialog from "../../../sponsor-forms-list-page/components/global-template/select-sponsorships-dialog";
import { cloneGlobalPage } from "../../../../../actions/sponsor-pages-actions";
@@ -31,9 +31,10 @@ const GlobalPagePopup = ({ open, onClose, cloneGlobalPage }) => {
return (