diff --git a/src/actions/sponsor-pages-actions.js b/src/actions/sponsor-pages-actions.js index ece734cd3..4a9d3cd75 100644 --- a/src/actions/sponsor-pages-actions.js +++ b/src/actions/sponsor-pages-actions.js @@ -23,7 +23,10 @@ import { } from "openstack-uicore-foundation/lib/utils/actions"; import T from "i18n-react/dist/i18n-react"; import moment from "moment-timezone"; -import { getAccessTokenSafely } from "../utils/methods"; +import { + getAccessTokenSafely, + normalizeSelectAllField +} from "../utils/methods"; import { snackbarErrorHandler, snackbarSuccessHandler } from "./base-actions"; import { DEFAULT_CURRENT_PAGE, @@ -37,8 +40,10 @@ export const RESET_EDIT_PAGE = "RESET_EDIT_PAGE"; export const REQUEST_SPONSOR_MANAGED_PAGES = "REQUEST_SPONSOR_MANAGED_PAGES"; export const RECEIVE_SPONSOR_MANAGED_PAGES = "RECEIVE_SPONSOR_MANAGED_PAGES"; +export const RECEIVE_SPONSOR_MANAGED_PAGE = "RECEIVE_SPONSOR_MANAGED_PAGE"; export const SPONSOR_MANAGED_PAGE_ADDED = "SPONSOR_MANAGED_PAGE_ADDED"; export const SPONSOR_MANAGED_PAGE_DELETED = "SPONSOR_MANAGED_PAGE_DELETED"; +export const SPONSOR_MANAGED_PAGE_UPDATED = "SPONSOR_MANAGED_PAGE_UPDATED"; export const REQUEST_SPONSOR_CUSTOMIZED_PAGES = "REQUEST_SPONSOR_CUSTOMIZED_PAGES"; @@ -158,6 +163,28 @@ export const getSponsorManagedPages = }); }; +export const getSponsorManagedPage = (pageId) => async (dispatch, getState) => { + const { currentSummitState } = getState(); + const { currentSummit } = currentSummitState; + const accessToken = await getAccessTokenSafely(); + + dispatch(startLoading()); + + const params = { + access_token: accessToken, + expand: "modules" + }; + + return getRequest( + null, + createAction(RECEIVE_SPONSOR_MANAGED_PAGE), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/show-pages/${pageId}`, + snackbarErrorHandler + )(params)(dispatch).finally(() => { + dispatch(stopLoading()); + }); +}; + export const saveSponsorManagedPage = (entity) => async (dispatch, getState) => { const { currentSummitState, currentSponsorState } = getState(); @@ -169,13 +196,37 @@ export const saveSponsorManagedPage = dispatch(startLoading()); - const normalizedEntity = normalizeSponsorManagedPage(entity); - const params = { access_token: accessToken, fields: "id,code,name,kind,modules_count,allowed_add_ons" }; + if (entity.id) { + const normalizedEntity = normalizeSponsorManagedPageToCustomize(entity); + + return putRequest( + null, + createAction(SPONSOR_CUSTOMIZED_PAGE_UPDATED), + `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/sponsors/${sponsorId}/managed-pages/${entity.id}`, + normalizedEntity, + snackbarErrorHandler, + entity + )(params)(dispatch) + .then(() => { + dispatch( + snackbarSuccessHandler({ + title: T.translate("general.success"), + html: T.translate("edit_sponsor.pages_tab.managed_page_saved") + }) + ); + }) + .finally(() => { + dispatch(stopLoading()); + }); + } + + const normalizedEntity = normalizeSponsorManagedPage(entity); + return postRequest( null, createAction(SPONSOR_MANAGED_PAGE_ADDED), @@ -187,7 +238,7 @@ export const saveSponsorManagedPage = dispatch( snackbarSuccessHandler({ title: T.translate("general.success"), - html: T.translate("edit_sponsor.pages_tab.managed_page_saved") + html: T.translate("edit_sponsor.pages_tab.managed_page_created") }) ); }) @@ -233,7 +284,7 @@ const normalizeSponsorManagedPage = (entity) => { show_page_ids: entity.pages }; - if (entity.add_ons.includes("all")) { + if (normalizedEntity.allowed_add_ons.includes("all")) { normalizedEntity.apply_to_all_add_ons = true; normalizedEntity.allowed_add_ons = []; } else { @@ -243,6 +294,49 @@ const normalizeSponsorManagedPage = (entity) => { return normalizedEntity; }; + +const normalizeSponsorManagedPageToCustomize = (entity) => { + const normalizedEntity = { + ...entity, + ...normalizeSelectAllField( + entity.allowed_add_ons, + "apply_to_all_add_ons", + "allowed_add_ons" + ) + }; + + normalizedEntity.modules = entity.modules.map((module) => { + const normalizedModule = { ...module }; + + if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) { + normalizedModule.upload_deadline = moment + .utc(module.upload_deadline) + .unix(); + } + + if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.file_type_id) { + normalizedModule.file_type_id = + module.file_type_id?.value || module.file_type_id; + } + + if (module.kind === PAGES_MODULE_KINDS.DOCUMENT && module.file) { + normalizedModule.file = module.file[0] || null; + } + + delete normalizedModule._tempId; + + return normalizedModule; + }); + + delete normalizedEntity.page_ptr_id; + delete normalizedEntity.sponsorship_types; + delete normalizedEntity.summit_id; + delete normalizedEntity.template_id; + delete normalizedEntity.modules_count; + delete normalizedEntity.id; + + return normalizedEntity; +}; /* ************************************************************************ */ /* CUSTOMIZED PAGES */ /* ************************************************************************ */ diff --git a/src/i18n/en.json b/src/i18n/en.json index 26e6aa499..a4a0e8a4b 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2500,11 +2500,13 @@ "no_pages": "There are no pages that match the criteria", "add_page_using_template": "Add Page Template", "add_selected_page_template": "Add Selected Page Template", - "managed_page_saved": "Managed Page updated successfully.", - "custom_page_saved": "Custom Sponsor Page saved", - "custom_page_created": "Custom Sponsor Page created", + "title_customize": "Customize Managed Page", "customized_page_archived": "Customized Sponsor Page successfully archived.", - "customized_page_unarchived": "Customized Sponsor Page successfully unarchived." + "customized_page_unarchived": "Customized Sponsor Page successfully unarchived.", + "custom_page_saved": "Custom Sponsor Page saved successfully", + "custom_page_created": "Custom Sponsor Page created successfully", + "managed_page_saved": "Sponsor Managed Page saved successfully", + "managed_page_created": "Sponsor Managed Page created successfully" }, "cart_tab": { "new_form": "New Form", @@ -4054,7 +4056,8 @@ "sponsorship_type": "Always apply to" }, "page_crud": { - "title": "Create New Page", + "title_create": "Create New Page", + "title_edit": "Edit Page", "add_info": "Add Info", "add_doc": "Add Document Download", "add_media": "Add Media Request", diff --git a/src/pages/sponsors-global/page-templates/page-template-popup/index.js b/src/pages/sponsors-global/page-templates/page-template-popup/index.js index 95e01f8d0..9e568ba86 100644 --- a/src/pages/sponsors-global/page-templates/page-template-popup/index.js +++ b/src/pages/sponsors-global/page-templates/page-template-popup/index.js @@ -31,7 +31,21 @@ import DropdownCheckbox from "../../../../components/mui/dropdown-checkbox"; import MuiFormikSelectGroup from "../../../../components/mui/formik-inputs/mui-formik-select-group"; import { querySponsorAddons } from "../../../../actions/sponsor-actions"; -const PageTemplatePopup = ({ pageTemplate, onClose, onSave, sponsorships, summitId, sponsorId, sponsorshipIds }) => { +const PageTemplatePopup = ({ + pageTemplate, + onClose, + onSave, + sponsorships, + summitId, + sponsorId, + sponsorshipIds, + title +}) => { + const popupTitle = + title ?? + (pageTemplate?.id + ? T.translate("page_template_list.page_crud.title_edit") + : T.translate("page_template_list.page_crud.title_create")); const showSponsorships = Array.isArray(sponsorships) && sponsorships.length > 0; @@ -157,9 +171,7 @@ const PageTemplatePopup = ({ pageTemplate, onClose, onSave, sponsorships, summit return ( - - {T.translate("page_template_list.page_crud.title")} - + {popupTitle} @@ -278,7 +290,8 @@ PageTemplatePopup.propTypes = { sponsorships: PropTypes.array, sponsorshipIds: PropTypes.array, summitId: PropTypes.number, - sponsorId: PropTypes.number + sponsorId: PropTypes.number, + title: PropTypes.string }; export default PageTemplatePopup; diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js index 28b4189b7..3cb4a54e2 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js @@ -6,6 +6,10 @@ import { renderWithRedux } from "../../../../../../utils/test-utils"; import { DEFAULT_STATE as sponsorPagesDefaultState } from "../../../../../../reducers/sponsors/sponsor-page-pages-list-reducer"; import { getSponsorCustomizedPage, + getSponsorManagedPage, + getSponsorManagedPages, + getSponsorCustomizedPages, + saveSponsorManagedPage, archiveCustomizedPage, unarchiveCustomizedPage } from "../../../../../../actions/sponsor-pages-actions"; @@ -49,6 +53,7 @@ jest.mock("../../../../../../actions/sponsor-pages-actions", () => ({ () => () => Promise.resolve({ id: 1, name: "Test Page" }) ), saveSponsorCustomizedPage: jest.fn(() => () => Promise.resolve()), + getSponsorManagedPage: jest.fn(() => () => Promise.resolve()), saveSponsorManagedPage: jest.fn(() => () => Promise.resolve()), resetSponsorPage: jest.fn(() => ({ type: "MOCK_ACTION" })), archiveCustomizedPage: jest.fn(() => () => Promise.resolve()), @@ -68,6 +73,14 @@ const createSponsor = (overrides = {}) => ({ ...overrides }); +const createManagedPage = (id, overrides = {}) => ({ + id, + code: `MANAGED-${id}`, + name: `Managed Page ${id}`, + assigned_type: "EXPLICIT", + ...overrides +}); + const createCustomizedPage = (id, overrides = {}) => ({ id, code: `CODE-${id}`, @@ -197,6 +210,119 @@ describe("SponsorPagesTab", () => { }); }); + it("should render Customize button in managed pages rows", async () => { + renderWithRedux( + , + { + initialState: { + ...defaultState, + sponsorPagePagesListState: { + ...defaultState.sponsorPagePagesListState, + managedPages: { + ...defaultState.sponsorPagePagesListState.managedPages, + pages: [createManagedPage(1)], + totalItems: 1 + } + } + } + } + ); + + expect( + screen.getByText("edit_sponsor.forms_tab.customize") + ).toBeInTheDocument(); + expect(screen.getByTestId("ArrowForwardIcon")).toBeInTheDocument(); + }); + + it("should call getSponsorManagedPage and open popup when Customize is clicked", async () => { + renderWithRedux( + , + { + initialState: { + ...defaultState, + sponsorPagePagesListState: { + ...defaultState.sponsorPagePagesListState, + managedPages: { + ...defaultState.sponsorPagePagesListState.managedPages, + pages: [createManagedPage(1)], + totalItems: 1 + } + } + } + } + ); + + const customizeButton = screen.getByText( + "edit_sponsor.forms_tab.customize" + ); + await act(async () => { + await userEvent.click(customizeButton); + }); + + expect(getSponsorManagedPage).toHaveBeenCalledWith(1); + await waitFor(() => { + expect(screen.getByTestId("page-template-popup")).toBeInTheDocument(); + }); + }); + + it("should call saveSponsorManagedPage, refresh both grids, and close popup after saving a managed page customization", async () => { + renderWithRedux( + , + { + initialState: { + ...defaultState, + sponsorPagePagesListState: { + ...defaultState.sponsorPagePagesListState, + managedPages: { + ...defaultState.sponsorPagePagesListState.managedPages, + pages: [createManagedPage(1)], + totalItems: 1 + } + } + } + } + ); + + const customizeButton = screen.getByText( + "edit_sponsor.forms_tab.customize" + ); + await act(async () => { + await userEvent.click(customizeButton); + }); + + await waitFor(() => { + expect(screen.getByTestId("page-template-popup")).toBeInTheDocument(); + }); + + const saveButton = screen.getByText("Save"); + await act(async () => { + await userEvent.click(saveButton); + }); + + expect(saveSponsorManagedPage).toHaveBeenCalled(); + + await waitFor(() => { + expect(getSponsorManagedPages).toHaveBeenCalledTimes(2); + expect(getSponsorCustomizedPages).toHaveBeenCalledTimes(2); + }); + + expect( + screen.queryByTestId("page-template-popup") + ).not.toBeInTheDocument(); + }); + it("should refresh customized pages list after save", async () => { const { getSponsorCustomizedPages diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/index.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/index.js index 7d2fdf266..b31032fd8 100644 --- a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/index.js +++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/index.js @@ -23,16 +23,18 @@ import { Grid2 } from "@mui/material"; import AddIcon from "@mui/icons-material/Add"; +import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; import { - archiveCustomizedPage, - deleteSponsorManagedPage, - getSponsorCustomizedPage, - getSponsorCustomizedPages, getSponsorManagedPages, - resetSponsorPage, - saveSponsorCustomizedPage, + getSponsorManagedPage, + getSponsorCustomizedPages, saveSponsorManagedPage, - unarchiveCustomizedPage + saveSponsorCustomizedPage, + getSponsorCustomizedPage, + deleteSponsorManagedPage, + unarchiveCustomizedPage, + archiveCustomizedPage, + resetSponsorPage, } from "../../../../../actions/sponsor-pages-actions"; import CustomAlert from "../../../../../components/mui/custom-alert"; import SearchInput from "../../../../../components/mui/search-input"; @@ -54,6 +56,7 @@ const SponsorPagesTab = ({ summitTZ, currentEditPage, getSponsorManagedPages, + getSponsorManagedPage, saveSponsorManagedPage, getSponsorCustomizedPages, saveSponsorCustomizedPage, @@ -170,7 +173,7 @@ const SponsorPagesTab = ({ }; const handleAddPage = () => { - setOpenPopup("pagePopup"); + setOpenPopup("customizedPagePopup"); }; const handleArchiveCustomizedPage = (item) => @@ -193,7 +196,8 @@ const SponsorPagesTab = ({ console.log("ARCHIVE MANAGED ", item); const handleManagedEdit = (item) => { - console.log("EDIT MANAGED ", item); + console.log("CHECK!", item); + getSponsorManagedPage(item.id).then(() => setOpenPopup("managedPagePopup")); }; const handleManagedDelete = (itemId) => { @@ -211,7 +215,9 @@ const SponsorPagesTab = ({ }; const handleCustomizedEdit = (item) => { - getSponsorCustomizedPage(item.id).then(() => setOpenPopup("pagePopup")); + getSponsorCustomizedPage(item.id).then(() => + setOpenPopup("customizedPagePopup") + ); }; const handleCustomizedDelete = (itemId) => { @@ -246,7 +252,8 @@ const SponsorPagesTab = ({ DEFAULT_CURRENT_PAGE, perPage, order, - orderDir + orderDir, + hideArchived ); }) .finally(() => setOpenPopup(null)); @@ -261,7 +268,31 @@ const SponsorPagesTab = ({ DEFAULT_CURRENT_PAGE, perPage, order, - orderDir + orderDir, + hideArchived + ); + }) + .finally(() => setOpenPopup(null)); + }; + + const handleSaveManagedPage = (entity) => { + saveSponsorManagedPage(entity) + .then(() => { + getSponsorManagedPages( + term, + DEFAULT_CURRENT_PAGE, + managedPages.perPage, + managedPages.order, + managedPages.orderDir, + hideArchived + ); + getSponsorCustomizedPages( + term, + DEFAULT_CURRENT_PAGE, + customizedPages.perPage, + customizedPages.order, + customizedPages.orderDir, + hideArchived ); }) .finally(() => setOpenPopup(null)); @@ -307,7 +338,25 @@ const SponsorPagesTab = ({ ]; const managedPagesColumns = [ - ...baseColumns(T.translate("edit_sponsor.pages_tab.managed_pages")) + ...baseColumns(T.translate("edit_sponsor.pages_tab.managed_pages")), + { + columnKey: "customize", + header: "", + width: 156, + align: "center", + render: (row) => ( + + ), + dottedBorder: true + } ]; const customizedPagesColumns = [ @@ -426,7 +475,6 @@ const SponsorPagesTab = ({ onPageChange={handleManagedPageChange} onPerPageChange={handleManagedPerPageChange} onSort={handleManagedSort} - onEdit={handleManagedEdit} onDelete={handleManagedDelete} canDelete={(row) => row.assigned_type === SPONSOR_MANAGED_PAGE_ASSIGNMENT.EXPLICIT @@ -444,9 +492,19 @@ const SponsorPagesTab = ({ /> )} - {openPopup === "pagePopup" && ( + {(openPopup === "customizedPagePopup" || + openPopup === "managedPagePopup") && ( { } }; } + case RECEIVE_SPONSOR_MANAGED_PAGE: { + const editPage = payload.response; + + const currentEditPage = { + ...editPage, + modules: editPage.modules.map((m) => ({ + ...m, + ...(m.upload_deadline + ? { + upload_deadline: epochToMomentTimeZone( + m.upload_deadline, + state.summitTZ || "UTC" + ) + } + : {}) + })) + }; + return { ...state, currentEditPage }; + } case RECEIVE_SPONSOR_CUSTOMIZED_PAGE: { const customizedPage = payload.response;