diff --git a/.gitignore b/.gitignore index 0b6d632..1ce182b 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,3 @@ coverage.xml dist/ foris-*.tgz styleguide/ -testUtils diff --git a/Makefile b/Makefile index c8aacdd..3e5f5d2 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,8 @@ test-js-watch: .PHONY: test-js-update-snapshots test-js-update-snapshots: npm test -- -u +test-js-watch: + npm test -- --watch # Translations diff --git a/src/customizationContext/CustomizationContext.js b/src/customizationContext/CustomizationContext.js new file mode 100644 index 0000000..e763421 --- /dev/null +++ b/src/customizationContext/CustomizationContext.js @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React, { useContext, useEffect } from "react"; +import PropTypes from "prop-types"; + +import { useAPIGet } from "../api/hooks"; +import { ForisURLs } from "../utils/forisUrls"; + +import { Spinner } from "../bootstrap/Spinner"; + +CustomizationContextProvider.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]), +}; + +function CustomizationContextProvider({ children }) { + const { CustomizationContext } = window; + const [getCustomizationResponse, getCustomization] = useAPIGet( + ForisURLs.about + ); + + useEffect(() => { + getCustomization(); + }, [getCustomization]); + + if (getCustomizationResponse.state !== "success") { + return ; + } + + const deviceDetails = getCustomizationResponse.data || {}; + + const isCustomized = !!( + deviceDetails && + deviceDetails.customization !== undefined && + deviceDetails.customization === "shield" + ); + + return ( + + {children} + + ); +} + +function useCustomizationContext() { + const { CustomizationContext } = window; + return useContext(CustomizationContext); +} + +export { CustomizationContextProvider, useCustomizationContext }; diff --git a/src/customizationContext/CustomizationContext.md b/src/customizationContext/CustomizationContext.md new file mode 100644 index 0000000..1d3e313 --- /dev/null +++ b/src/customizationContext/CustomizationContext.md @@ -0,0 +1,3 @@ +It provides customization context to the children. `CustomizationContext` allows +using `useCustomizationContext` in components to check if the reForis UI is +customized or not for specific devices. diff --git a/src/customizationContext/__tests__/CustomizationContext.test.js b/src/customizationContext/__tests__/CustomizationContext.test.js new file mode 100644 index 0000000..9634afb --- /dev/null +++ b/src/customizationContext/__tests__/CustomizationContext.test.js @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React from "react"; + +import { render, wait } from "customTestRender"; +import mockAxios from "jest-mock-axios"; + +import { + useCustomizationContext, + CustomizationContextProvider, +} from "../CustomizationContext"; + +const CUSTOM = "Description / component for customized reForis (Shield)"; +const ORIGINAL = "Description / component for original reForis (other devices)"; + +function CustomizationTest() { + const isCustomized = useCustomizationContext(); + + return

{isCustomized ? CUSTOM : ORIGINAL}

; +} + +describe("CustomizationContext", () => { + let componentContainer; + + it("should render component without customization", async () => { + const { container, getByText } = render( + + + + ); + componentContainer = container; + + mockAxios.mockResponse({ data: {} }); + await wait(() => getByText(ORIGINAL)); + + expect(componentContainer).toMatchSnapshot(); + }); + + it("should render customized component", async () => { + const { container, getByText } = render( + + + + ); + componentContainer = container; + + mockAxios.mockResponse({ data: { customization: "shield" } }); + await wait(() => getByText(CUSTOM)); + + expect(componentContainer).toMatchSnapshot(); + }); +}); diff --git a/src/customizationContext/__tests__/__snapshots__/CustomizationContext.test.js.snap b/src/customizationContext/__tests__/__snapshots__/CustomizationContext.test.js.snap new file mode 100644 index 0000000..eb6fb1b --- /dev/null +++ b/src/customizationContext/__tests__/__snapshots__/CustomizationContext.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CustomizationContext should render component without customization 1`] = ` +
+

+ Description / component for original reForis (other devices) +

+
+`; + +exports[`CustomizationContext should render customized component 1`] = ` +
+

+ Description / component for customized reForis (Shield) +

+
+`; diff --git a/src/index.js b/src/index.js index c52f1fa..09ec807 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2021 CZ.NIC z.s.p.o. (http://www.nic.cz/) + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) * * This is free software, licensed under the GNU General Public License v3. * See /LICENSE for more information. @@ -91,3 +91,9 @@ export { // Alert context export { AlertContextProvider, useAlert } from "./alertContext/AlertContext"; + +// Customization context +export { + CustomizationContextProvider, + useCustomizationContext, +} from "./customizationContext/CustomizationContext"; diff --git a/src/testUtils/customTestRender.js b/src/testUtils/customTestRender.js index 8d41a60..c256358 100644 --- a/src/testUtils/customTestRender.js +++ b/src/testUtils/customTestRender.js @@ -14,6 +14,7 @@ import { render } from "@testing-library/react"; import PropTypes from "prop-types"; import { AlertContextMock } from "./alertContextMock"; +import { CustomizationContextMock } from "./cutomizationContextMock"; Wrapper.propTypes = { children: PropTypes.oneOfType([ @@ -25,9 +26,11 @@ Wrapper.propTypes = { function Wrapper({ children }) { return ( - - {children} - + + + {children} + + ); } diff --git a/src/testUtils/cutomizationContextMock.js b/src/testUtils/cutomizationContextMock.js new file mode 100644 index 0000000..3b07a29 --- /dev/null +++ b/src/testUtils/cutomizationContextMock.js @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/) + * + * This is free software, licensed under the GNU General Public License v3. + * See /LICENSE for more information. + */ + +import React from "react"; + +window.CustomizationContext = React.createContext(); + +const isCustomized = jest.fn(); + +function CustomizationContextMock({ children }) { + return ( + + {children} + + ); +} + +export { CustomizationContextMock }; diff --git a/src/utils/forisUrls.js b/src/utils/forisUrls.js index 341d1c1..0232d2a 100644 --- a/src/utils/forisUrls.js +++ b/src/utils/forisUrls.js @@ -36,5 +36,6 @@ export const ForisURLs = { luci: "/cgi-bin/luci", // API + about: `${REFORIS_API_URL_PREFIX}/about`, reboot: `${REFORIS_API_URL_PREFIX}/reboot`, }; diff --git a/styleguide.config.js b/styleguide.config.js index 295c93a..f87ee2e 100644 --- a/styleguide.config.js +++ b/styleguide.config.js @@ -34,6 +34,12 @@ module.exports = { exampleMode: "expand", usageMode: "expand", }, + { + name: "Customization Context", + components: ["src/customizationContext/CustomizationContext.js"], + exampleMode: "expand", + usageMode: "expand", + }, { name: "Bootstrap components", description: "Set of bootstrap components.",