diff --git a/src/layouts/sponsor-id-layout.js b/src/layouts/sponsor-id-layout.js index 4b117c411..d39a3d32c 100644 --- a/src/layouts/sponsor-id-layout.js +++ b/src/layouts/sponsor-id-layout.js @@ -145,7 +145,17 @@ class SponsorIdLayout extends React.Component { ( +
+ + +
+ )} /> diff --git a/src/pages/sponsors/__tests__/edit-sponsor-page.test.js b/src/pages/sponsors/__tests__/edit-sponsor-page.test.js index f6a1367d7..13845645d 100644 --- a/src/pages/sponsors/__tests__/edit-sponsor-page.test.js +++ b/src/pages/sponsors/__tests__/edit-sponsor-page.test.js @@ -3,21 +3,32 @@ import userEvent from "@testing-library/user-event"; import { act, screen } from "@testing-library/react"; import EditSponsorPage, { getFragmentFromValue, - getTabFromUrlFragment + getTabFromFragment } from "../edit-sponsor-page"; import { renderWithRedux } from "../../../utils/test-utils"; import { DEFAULT_STATE as currentSponsorDefaultState } from "../../../reducers/sponsors/sponsor-reducer"; +import { DEFAULT_STATE as currentSponsorFormsDefaultState } from "../../../reducers/sponsors/sponsor-page-forms-list-reducer"; import { DEFAULT_ENTITY as defaultSummitEntity, DEFAULT_STATE as currentSummitDefaultState } from "../../../reducers/summits/current-summit-reducer"; -global.window = { location: { pathname: "/sponsor-forms/items" } }; jest.mock( "../sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items.js" ); jest.mock("../sponsor-users-list-per-sponsor/index.js"); +jest.mock("../../../actions/sponsor-actions", () => ({ + ...jest.requireActual("../../../actions/sponsor-actions"), + getSponsorAdvertisements: jest.fn(() => ({ type: "MOCK_ACTION" })), + getSponsorMaterials: jest.fn(() => ({ type: "MOCK_ACTION" })), + getSponsorSocialNetworks: jest.fn(() => ({ type: "MOCK_ACTION" })), + getSponsorLeadReportSettingsMeta: jest.fn(() => ({ type: "MOCK_ACTION" })), + getSponsorTiers: jest.fn(() => ({ type: "MOCK_ACTION" })), + getExtraQuestionMeta: jest.fn(() => ({ type: "MOCK_ACTION" })), + resetSponsorForm: jest.fn(() => ({ type: "MOCK_ACTION" })) +})); + describe("EditSponsorPage", () => { describe("getFragmentFromValue", () => { it("returns correct values", () => { @@ -35,61 +46,34 @@ describe("EditSponsorPage", () => { }); }); - describe("getTabFromUrlFragment", () => { + describe("getTabFromFragment", () => { it("returns correct values for defined fragments", () => { - const newUrl1 = "#general"; - window.location.hash = newUrl1; - - const result1 = getTabFromUrlFragment(); - expect(result1).toBe(0); - - const newUrl2 = "#pages"; - window.location.hash = newUrl2; - - const result2 = getTabFromUrlFragment(); - expect(result2).toBe(2); - - const newUrl3 = "#media_uploads"; - window.location.hash = newUrl3; - - const result3 = getTabFromUrlFragment(); - expect(result3).toBe(3); - - const newUrl4 = "#badge_scans"; - window.location.hash = newUrl4; - - const result4 = getTabFromUrlFragment(); - expect(result4).toBe(7); + expect(getTabFromFragment({ hash: "#general" })).toBe(0); + expect(getTabFromFragment({ hash: "#users" })).toBe(1); + expect(getTabFromFragment({ hash: "#pages" })).toBe(2); + expect(getTabFromFragment({ hash: "#media_uploads" })).toBe(3); + expect(getTabFromFragment({ hash: "#forms" })).toBe(4); + expect(getTabFromFragment({ hash: "#badge_scans" })).toBe(7); }); }); describe("Component", () => { - const originalWindowLocation = window.location; - it("should change the url fragment on tab click", async () => { - delete window.location; - - Object.defineProperty(window, "location", { - configurable: true, - writable: true, - value: { - ...originalWindowLocation, - hash: "#general" - } - }); + it("should change the url fragment on tab click (same path)", async () => { + const mockHistory = { push: jest.fn(), replace: jest.fn() }; renderWithRedux( , { initialState: { currentSummitState: { - currentSummit: defaultSummitEntity, - ...currentSummitDefaultState + ...currentSummitDefaultState, + currentSummit: { ...defaultSummitEntity, id: 12 } }, loggedUserState: { member: { @@ -106,8 +90,11 @@ describe("EditSponsorPage", () => { totalSponsorships: 0 }, currentSponsorState: { - sponsorships: [], - ...currentSponsorDefaultState + ...currentSponsorDefaultState, + entity: { ...currentSponsorDefaultState.entity, id: 123 } + }, + sponsorPageFormsListState: { + ...currentSponsorFormsDefaultState } } } @@ -119,26 +106,69 @@ describe("EditSponsorPage", () => { await userEvent.click(usersTabReference); }); - expect(window.location.hash).toBe("forms"); + expect(mockHistory.replace).toHaveBeenCalledWith( + expect.objectContaining({ + hash: "#forms" + }) + ); + expect(mockHistory.push).not.toHaveBeenCalled(); }); - it("should change the tab rendered on fragment change", async () => { - delete window.location; + it("should call history.push on tab click when on nested route", async () => { + const mockHistory = { push: jest.fn(), replace: jest.fn() }; - Object.defineProperty(window, "location", { - configurable: true, - writable: true, - value: { - ...originalWindowLocation, - hash: "#general" + renderWithRedux( + , + { + initialState: { + currentSummitState: { + ...currentSummitDefaultState, + currentSummit: { ...defaultSummitEntity, id: 12 } + }, + loggedUserState: { + member: { groups: {} } + }, + currentSummitSponsorshipListState: { + sponsorships: [], + currentPage: 1, + lastPage: 1, + perPage: 100, + order: "order", + orderDir: 1, + totalSponsorships: 0 + }, + currentSponsorState: { + ...currentSponsorDefaultState, + entity: { ...currentSponsorDefaultState.entity, id: 44 } + } + } } + ); + + const usersTab = screen.getByText("edit_sponsor.tab.users"); + + await act(async () => { + await userEvent.click(usersTab); }); - renderWithRedux( + expect(mockHistory.push).toHaveBeenCalledWith( + "/app/summits/12/sponsors/44#users" + ); + }); + + it("should change the tab rendered on fragment change", () => { + const { rerender } = renderWithRedux( , @@ -173,26 +203,16 @@ describe("EditSponsorPage", () => { const generalTabPanel = screen.getByTestId("simple-tabpanel-0"); expect(generalTabPanel).toBeDefined(); - delete window.location; - - Object.defineProperty(window, "location", { - configurable: true, - writable: true, - value: { - ...originalWindowLocation, - hash: "#users" - } - }); + rerender( + + ); const usersTabPanel = screen.getByTestId("simple-tabpanel-1"); expect(usersTabPanel).toBeDefined(); }); - - afterEach(() => { - Object.defineProperty(window, "location", { - configurable: true, - value: originalWindowLocation - }); - }); }); }); diff --git a/src/pages/sponsors/edit-sponsor-page.js b/src/pages/sponsors/edit-sponsor-page.js index d3101dc25..c60f68fd0 100644 --- a/src/pages/sponsors/edit-sponsor-page.js +++ b/src/pages/sponsors/edit-sponsor-page.js @@ -59,8 +59,8 @@ export const tabsToFragmentMap = [ export const getFragmentFromValue = (index) => tabsToFragmentMap[index]; -export const getTabFromUrlFragment = () => { - const currentHash = window.location.hash.replace("#", ""); +export const getTabFromFragment = (location) => { + const currentHash = (location.hash || "").replace("#", ""); const result = tabsToFragmentMap.indexOf(currentHash); if (result > -1) return result; return 0; @@ -118,19 +118,36 @@ const EditSponsorPage = (props) => { getExtraQuestionMeta } = props; - const [selectedTab, setSelectedTab] = useState(getTabFromUrlFragment()); + const [selectedTab, setSelectedTab] = useState(getTabFromFragment(location)); + + const isNestedFormItemRoute = !!match.params?.form_id; const handleTabChange = (event, newValue) => { setSelectedTab(newValue); - window.location.hash = getFragmentFromValue(newValue); + const fragment = getFragmentFromValue(newValue); + if (isNestedFormItemRoute) { + history.push( + `/app/summits/${currentSummit.id}/sponsors/${entity.id}#${fragment}` + ); + } else { + history.replace({ ...location, hash: `#${fragment}` }); + } }; useEffect(() => { - const onHashChange = () => setSelectedTab(getTabFromUrlFragment()); - window.addEventListener("hashchange", onHashChange); - // default call - if (!window.location.hash) handleTabChange(null, getTabFromUrlFragment()); - return () => window.removeEventListener("hashchange", onHashChange); + setSelectedTab(getTabFromFragment(location)); + }, [location.hash]); + + useEffect(() => { + if (!location.hash) { + const defaultTab = isNestedFormItemRoute + ? SPONSOR_TABS.FORMS + : SPONSOR_TABS.GENERAL; + history.replace({ + ...location, + hash: `#${getFragmentFromValue(defaultTab)}` + }); + } }, []); useEffect(() => { @@ -173,9 +190,7 @@ const EditSponsorPage = (props) => { } ]; - const sponsorFormItemRoute = - location.pathname.includes("/sponsor-forms/") && - location.pathname.includes("/items"); + const sponsorFormItemRoute = !!match.params?.form_id; return ( @@ -196,7 +211,6 @@ const EditSponsorPage = (props) => { key={t.value} label={t.label} value={t.value} - onClick={() => handleTabChange(null, t.value)} sx={{ fontSize: "1.4rem", lineHeight: "1.8rem", diff --git a/src/pages/sponsors/sponsor-forms-tab/index.js b/src/pages/sponsors/sponsor-forms-tab/index.js index dccaeaabc..1b462c230 100644 --- a/src/pages/sponsors/sponsor-forms-tab/index.js +++ b/src/pages/sponsors/sponsor-forms-tab/index.js @@ -113,7 +113,7 @@ const SponsorFormsTab = ({ const handleManageItems = (item) => { history.push( - `/app/summits/${summitId}/sponsors/${sponsor.id}/sponsor-forms/${item.id}/items` + `/app/summits/${summitId}/sponsors/${sponsor.id}/sponsor-forms/${item.id}/items#forms` ); }; diff --git a/src/reducers/sponsors/sponsor-page-forms-list-reducer.js b/src/reducers/sponsors/sponsor-page-forms-list-reducer.js index 3f6467ccf..40c5cacc0 100644 --- a/src/reducers/sponsors/sponsor-page-forms-list-reducer.js +++ b/src/reducers/sponsors/sponsor-page-forms-list-reducer.js @@ -26,7 +26,7 @@ import { } from "../../actions/sponsor-forms-actions"; import { SET_CURRENT_SUMMIT } from "../../actions/summit-actions"; -const DEFAULT_STATE = { +export const DEFAULT_STATE = { managedForms: { forms: [], order: "name",