1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2024-12-26 00:21:36 +01:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Aleksandr Gumroian
4df4c6e91f Merge branch 'add-action-btn-with-modal' into 'dev'
Add ActionButtonWithModal component and remove RebootButton

See merge request turris/reforis/foris-js!254
2024-11-12 17:39:21 +01:00
Aleksandr Gumroian
c9f2b24095
Replace RebootButton with ActionButtonWithModal component and update documentation 2024-11-12 17:39:01 +01:00
4 changed files with 89 additions and 27 deletions

View File

@ -6,7 +6,9 @@
*/
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { useAPIPost } from "../../api/hooks";
import { API_STATE } from "../../api/utils";
import Button from "../../bootstrap/Button";
@ -19,13 +21,21 @@ import {
import { useAlert } from "../../context/alertContext/AlertContext";
ActionButtonWithModal.propTypes = {
/** Component that triggers the action. */
actionTrigger: PropTypes.elementType.isRequired,
/** URL to send the action to. */
actionUrl: PropTypes.string.isRequired,
/** Title of the modal. */
modalTitle: PropTypes.string.isRequired,
/** Message of the modal. */
modalMessage: PropTypes.string.isRequired,
/** Text of the action button in the modal. */
modalActionText: PropTypes.string,
/** Props for the action button in the modal. */
modalActionProps: PropTypes.object,
/** Message to display on successful action. */
successMessage: PropTypes.string,
/** Message to display on failed action. */
errorMessage: PropTypes.string,
};
@ -89,6 +99,7 @@ ActionModal.propTypes = {
title: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
actionText: PropTypes.string,
actionProps: PropTypes.object,
};
function ActionModal({

View File

@ -5,17 +5,32 @@ reboot of the device.
```jsx
import React, { useEffect, createContext } from "react";
import RebootButton from "./RebootButton";
import { AlertContextProvider } from "../context/alertContext/AlertContext";
import Button from "../../bootstrap/Button";
import { AlertContextProvider } from "../../context/alertContext/AlertContext";
import ActionButtonWithModal from "./ActionButtonWithModal";
window.AlertContext = React.createContext();
const RebootButtonExample = () => {
const ActionButton = (props) => {
return <Button {...props}>Action</Button>;
};
return (
<AlertContextProvider>
<div id="modal-container" />
<div id="alert-container" />
<RebootButton />
<ActionButtonWithModal
actionTrigger={ActionButton}
actionUrl="/reforis/api/action"
modalTitle="Warning!"
modalMessage="Are you sure you want to perform this action?"
modalActionText="Confirm action"
modalActionProps={{ className: "btn-danger" }}
successMessage="Action request succeeded."
errorMessage="Action request failed."
/>
</AlertContextProvider>
);
};

View File

@ -7,6 +7,8 @@
import React from "react";
import Button from "bootstrap/Button";
import {
fireEvent,
getByText,
@ -22,29 +24,43 @@ import ActionButtonWithModal from "../ActionButtonWithModal/ActionButtonWithModa
describe("<ActionButtonWithModal/>", () => {
let componentContainer;
const ActionButton = (props) => (
<Button type="button" {...props}>
Action
</Button>
);
beforeEach(() => {
const { container } = render(
<>
<div id="modal-container" />
<div id="alert-container" />
<ActionButtonWithModal />
<ActionButtonWithModal
actionTrigger={ActionButton}
actionUrl="/reforis/api/action"
modalTitle="Warning!"
modalMessage="Are you sure you want to perform this action?"
modalActionText="Confirm action"
modalActionProps={{ className: "btn-danger" }}
successMessage="Action request succeeded."
errorMessage="Action request failed."
/>
</>
);
componentContainer = container;
});
it("Render.", () => {
it("Render button.", () => {
expect(componentContainer).toMatchSnapshot();
});
it("Render modal.", () => {
expect(queryByText(componentContainer, "Confirm action")).toBeNull();
fireEvent.click(getByText(componentContainer, "Action"));
expect(componentContainer).toMatchSnapshot();
});
it("Confirm action.", () => {
fireEvent.click(getByText(componentContainer, "action"));
fireEvent.click(getByText(componentContainer, "Action"));
fireEvent.click(getByText(componentContainer, "Confirm action"));
expect(mockAxios.post).toHaveBeenCalledWith(
"/reforis/api/action",
@ -61,4 +77,16 @@ describe("<ActionButtonWithModal/>", () => {
expect(mockSetAlert).toBeCalledWith("Action request failed.")
);
});
it("Show success alert on successful action.", async () => {
fireEvent.click(getByText(componentContainer, "Action"));
fireEvent.click(getByText(componentContainer, "Confirm action"));
mockAxios.mockResponse({ status: 200 });
await wait(() =>
expect(mockSetAlert).toBeCalledWith(
"Action request succeeded.",
"success"
)
);
});
});

View File

@ -1,6 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RebootButton/> Render modal. 1`] = `
exports[`<ActionButtonWithModal/> Render button. 1`] = `
<div>
<div
id="modal-container"
/>
<div
id="alert-container"
/>
<button
class="btn btn-primary d-inline-flex justify-content-center align-items-center"
type="button"
>
<span>
Action
</span>
</button>
</div>
`;
exports[`<ActionButtonWithModal/> Render modal. 1`] = `
<div>
<div
id="modal-container"
@ -35,8 +54,10 @@ exports[`<RebootButton/> Render modal. 1`] = `
<div
class="modal-body"
>
<p>
Are you sure you want to restart the router?
<p
class="mb-0"
>
Are you sure you want to perform this action?
</p>
</div>
<div
@ -55,7 +76,7 @@ exports[`<RebootButton/> Render modal. 1`] = `
type="button"
>
<span>
Confirm reboot
Confirm action
</span>
</button>
</div>
@ -63,28 +84,15 @@ exports[`<RebootButton/> Render modal. 1`] = `
</div>
</div>
</div>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
type="button"
>
<span>
Reboot
</span>
</button>
</div>
`;
exports[`<RebootButton/> Render. 1`] = `
<div>
<div
id="modal-container"
id="alert-container"
/>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
class="btn btn-primary d-inline-flex justify-content-center align-items-center"
type="button"
>
<span>
Reboot
Action
</span>
</button>
</div>