diff --git a/src/pages/sponsors/__tests__/edit-sponsor-page.test.js b/src/pages/sponsors/__tests__/edit-sponsor-page.test.js
new file mode 100644
index 000000000..f6a1367d7
--- /dev/null
+++ b/src/pages/sponsors/__tests__/edit-sponsor-page.test.js
@@ -0,0 +1,198 @@
+import React from "react";
+import userEvent from "@testing-library/user-event";
+import { act, screen } from "@testing-library/react";
+import EditSponsorPage, {
+ getFragmentFromValue,
+ getTabFromUrlFragment
+} from "../edit-sponsor-page";
+import { renderWithRedux } from "../../../utils/test-utils";
+import { DEFAULT_STATE as currentSponsorDefaultState } from "../../../reducers/sponsors/sponsor-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");
+
+describe("EditSponsorPage", () => {
+ describe("getFragmentFromValue", () => {
+ it("returns correct values", () => {
+ const result1 = getFragmentFromValue(0);
+ expect(result1).toBe("general");
+
+ const result2 = getFragmentFromValue(2);
+ expect(result2).toBe("pages");
+
+ const result3 = getFragmentFromValue(3);
+ expect(result3).toBe("media_uploads");
+
+ const result4 = getFragmentFromValue(7);
+ expect(result4).toBe("badge_scans");
+ });
+ });
+
+ describe("getTabFromUrlFragment", () => {
+ 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);
+ });
+ });
+
+ 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"
+ }
+ });
+
+ renderWithRedux(
+ ,
+ {
+ initialState: {
+ currentSummitState: {
+ currentSummit: defaultSummitEntity,
+ ...currentSummitDefaultState
+ },
+ loggedUserState: {
+ member: {
+ groups: {}
+ }
+ },
+ currentSummitSponsorshipListState: {
+ sponsorships: [],
+ currentPage: 1,
+ lastPage: 1,
+ perPage: 100,
+ order: "order",
+ orderDir: 1,
+ totalSponsorships: 0
+ },
+ currentSponsorState: {
+ sponsorships: [],
+ ...currentSponsorDefaultState
+ }
+ }
+ }
+ );
+
+ const usersTabReference = screen.getByText("edit_sponsor.tab.forms");
+
+ await act(async () => {
+ await userEvent.click(usersTabReference);
+ });
+
+ expect(window.location.hash).toBe("forms");
+ });
+
+ it("should change the tab rendered on fragment change", async () => {
+ delete window.location;
+
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ writable: true,
+ value: {
+ ...originalWindowLocation,
+ hash: "#general"
+ }
+ });
+
+ renderWithRedux(
+ ,
+ {
+ initialState: {
+ currentSummitState: {
+ currentSummit: defaultSummitEntity,
+ ...currentSummitDefaultState
+ },
+ loggedUserState: {
+ member: {
+ groups: {}
+ }
+ },
+ currentSummitSponsorshipListState: {
+ sponsorships: [],
+ currentPage: 1,
+ lastPage: 1,
+ perPage: 100,
+ order: "order",
+ orderDir: 1,
+ totalSponsorships: 0
+ },
+ currentSponsorState: {
+ sponsorships: [],
+ ...currentSponsorDefaultState
+ }
+ }
+ }
+ );
+
+ 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"
+ }
+ });
+
+ 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 3a4e9a709..d3101dc25 100644
--- a/src/pages/sponsors/edit-sponsor-page.js
+++ b/src/pages/sponsors/edit-sponsor-page.js
@@ -46,7 +46,27 @@ import SponsorCartTab from "./sponsor-cart-tab";
import SponsorFormsManageItems from "./sponsor-forms-tab/components/manage-items/sponsor-forms-manage-items";
import { SPONSOR_TABS } from "../../utils/constants";
-const CustomTabPanel = (props) => {
+export const tabsToFragmentMap = [
+ "general",
+ "users",
+ "pages",
+ "media_uploads",
+ "forms",
+ "cart",
+ "purchases",
+ "badge_scans"
+];
+
+export const getFragmentFromValue = (index) => tabsToFragmentMap[index];
+
+export const getTabFromUrlFragment = () => {
+ const currentHash = window.location.hash.replace("#", "");
+ const result = tabsToFragmentMap.indexOf(currentHash);
+ if (result > -1) return result;
+ return 0;
+};
+
+export const CustomTabPanel = (props) => {
const { children, value, index, ...other } = props;
return (
@@ -54,6 +74,7 @@ const CustomTabPanel = (props) => {
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
+ data-testid={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
@@ -97,18 +118,21 @@ const EditSponsorPage = (props) => {
getExtraQuestionMeta
} = props;
- const [selectedTab, setSelectedTab] = useState(
- location.pathname.includes("/sponsor-forms/") &&
- location.pathname.includes("/items")
- ? SPONSOR_TABS.FORMS
- : 0
- );
+ const [selectedTab, setSelectedTab] = useState(getTabFromUrlFragment());
const handleTabChange = (event, newValue) => {
setSelectedTab(newValue);
- history.push(`/app/summits/${currentSummit.id}/sponsors/${entity.id}`);
+ window.location.hash = getFragmentFromValue(newValue);
};
+ useEffect(() => {
+ const onHashChange = () => setSelectedTab(getTabFromUrlFragment());
+ window.addEventListener("hashchange", onHashChange);
+ // default call
+ if (!window.location.hash) handleTabChange(null, getTabFromUrlFragment());
+ return () => window.removeEventListener("hashchange", onHashChange);
+ }, []);
+
useEffect(() => {
if (entity.id > 0) {
getSponsorAdvertisements(entity.id);
diff --git a/src/reducers/sponsors/sponsor-reducer.js b/src/reducers/sponsors/sponsor-reducer.js
index ff98dd6e2..142bca97e 100644
--- a/src/reducers/sponsors/sponsor-reducer.js
+++ b/src/reducers/sponsors/sponsor-reducer.js
@@ -132,7 +132,7 @@ export const DEFAULT_ENTITY = {
sponsorships_collection: DEFAULT_SPONSORHIPS_STATE
};
-const DEFAULT_STATE = {
+export const DEFAULT_STATE = {
entity: DEFAULT_ENTITY,
selectedSponsorship: null,
errors: {}
diff --git a/src/reducers/summits/current-summit-reducer.js b/src/reducers/summits/current-summit-reducer.js
index 88d7cc951..3e229b606 100644
--- a/src/reducers/summits/current-summit-reducer.js
+++ b/src/reducers/summits/current-summit-reducer.js
@@ -214,7 +214,7 @@ const DEFAULT_PRINT_APP_MARKETING_SETTINGS = {
PRINT_APP_HIDE_FIND_TICKET_BY_FULLNAME: { id: 0, value: false }
};
-const DEFAULT_STATE = {
+export const DEFAULT_STATE = {
currentSummit: DEFAULT_ENTITY,
errors: {},
loading: true,
diff --git a/yarn.lock b/yarn.lock
index e3e15533f..3b62ca6e4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11048,16 +11048,7 @@ prop-types-extra@^1.0.1:
react-is "^16.3.2"
warning "^4.0.0"
-prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
- version "15.8.1"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
- integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
- dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.13.1"
-
-prop-types@^15.8.1:
+prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==