1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2025-08-01 20:03:28 +02:00

Move contexts in a context folder

This commit is contained in:
Aleksandr Gumroian
2022-12-22 15:14:32 +01:00
parent f382e743aa
commit f2ae6c4d0a
13 changed files with 17 additions and 12 deletions

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information.
*/
import React, { useState, useContext, useCallback } from "react";
import PropTypes from "prop-types";
import { Alert, ALERT_TYPES } from "../../bootstrap/Alert";
import { Portal } from "../../utils/Portal";
AlertContextProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
};
function AlertContextProvider({ children }) {
const { AlertContext } = window;
const [alert, setAlert] = useState(null);
const setAlertWrapper = useCallback(
(message, type = ALERT_TYPES.DANGER) => {
setAlert({ message, type });
},
[setAlert]
);
const dismissAlert = useCallback(() => setAlert(null), [setAlert]);
return (
<>
{alert && (
<Portal containerId="alert-container">
<Alert type={alert.type} onDismiss={dismissAlert}>
{alert.message}
</Alert>
</Portal>
)}
<AlertContext.Provider value={[setAlertWrapper, dismissAlert]}>
{children}
</AlertContext.Provider>
</>
);
}
function useAlert() {
const { AlertContext } = window;
return useContext(AlertContext);
}
export { AlertContextProvider, useAlert };

View File

@@ -0,0 +1,5 @@
It provides alert context to children. `AlertContext` allows using `useAlert` in
components.
Notice that `<div id="alert-container"/>` should be presented in HTML doc to get
it work (In reForis it's already done with base Jinja2 templates).

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2019 CZ.NIC z.s.p.o. (http://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, getByText, queryByText, fireEvent } from "customTestRender";
import { useAlert, AlertContextProvider } from "../AlertContext";
function AlertTest() {
const [setAlert, dismissAlert] = useAlert();
// alert-container serves as an output for Portal which renders Alert
return (
<>
<div id="alert-container" />
<button onClick={() => setAlert("Alert content")}>Set alert</button>
<button onClick={dismissAlert}>Dismiss alert</button>
</>
);
}
describe("AlertContext", () => {
let componentContainer;
beforeEach(() => {
const { container } = render(
<AlertContextProvider>
<AlertTest />
</AlertContextProvider>
);
componentContainer = container;
});
it("should render component without alert", () => {
expect(componentContainer).toMatchSnapshot();
});
it("should render alert", () => {
fireEvent.click(getByText(componentContainer, "Set alert"));
expect(componentContainer).toMatchSnapshot();
});
it("should dismiss alert with alert button", () => {
fireEvent.click(getByText(componentContainer, "Set alert"));
// Alert is present
expect(getByText(componentContainer, "Alert content")).toBeDefined();
fireEvent.click(componentContainer.querySelector(".close"));
// Alert is gone
expect(queryByText(componentContainer, "Alert content")).toBeNull();
});
it("should dismiss alert with external button", () => {
fireEvent.click(getByText(componentContainer, "Set alert"));
// Alert is present
expect(getByText(componentContainer, "Alert content")).toBeDefined();
fireEvent.click(getByText(componentContainer, "Dismiss alert"));
// Alert is gone
expect(queryByText(componentContainer, "Alert content")).toBeNull();
});
});

View File

@@ -0,0 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AlertContext should render alert 1`] = `
<div>
<div
id="alert-container"
>
<div
class="alert alert-dismissible alert-danger"
>
<button
class="close"
type="button"
>
×
</button>
Alert content
</div>
</div>
<button>
Set alert
</button>
<button>
Dismiss alert
</button>
</div>
`;
exports[`AlertContext should render component without alert 1`] = `
<div>
<div
id="alert-container"
/>
<button>
Set alert
</button>
<button>
Dismiss alert
</button>
</div>
`;

View File

@@ -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 <Spinner fullScreen />;
}
const deviceDetails = getCustomizationResponse.data || {};
const isCustomized = !!(
deviceDetails &&
deviceDetails.customization !== undefined &&
deviceDetails.customization === "shield"
);
return (
<CustomizationContext.Provider value={{ deviceDetails, isCustomized }}>
{children}
</CustomizationContext.Provider>
);
}
function useCustomizationContext() {
const { CustomizationContext } = window;
return useContext(CustomizationContext);
}
export { CustomizationContextProvider, useCustomizationContext };

View File

@@ -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.

View File

@@ -0,0 +1,53 @@
/*
* 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, getByText } 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)";
const CustomizationTest = () => {
const { isCustomized } = useCustomizationContext();
return <p>{isCustomized ? CUSTOM : ORIGINAL}</p>;
};
describe("CustomizationContext", () => {
let componentContainer;
beforeEach(() => {
const { container } = render(
<CustomizationContextProvider>
<CustomizationTest />
</CustomizationContextProvider>
);
componentContainer = container;
});
it("should render component without customization", async () => {
mockAxios.mockResponse({ data: {} });
await wait(() => getByText(componentContainer, ORIGINAL));
expect(componentContainer).toMatchSnapshot();
});
it("should render customized component", async () => {
mockAxios.mockResponse({ data: { customization: "shield" } });
await wait(() => getByText(componentContainer, CUSTOM));
expect(componentContainer).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CustomizationContext should render component without customization 1`] = `
<div>
<p>
Description / component for original reForis (other devices)
</p>
</div>
`;
exports[`CustomizationContext should render customized component 1`] = `
<div>
<p>
Description / component for customized reForis (Shield)
</p>
</div>
`;