1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2024-11-14 17:35:35 +01:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Aleksandr Gumroian
62a4934988 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 14:31:56 +01:00
Aleksandr Gumroian
7f9fc8e91b
Add ActionButtonWithModal component and remove RebootButton 2024-11-11 01:09:36 +01:00
4 changed files with 29 additions and 91 deletions

View File

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

View File

@ -5,32 +5,17 @@ reboot of the device.
```jsx ```jsx
import React, { useEffect, createContext } from "react"; import React, { useEffect, createContext } from "react";
import RebootButton from "./RebootButton";
import Button from "../../bootstrap/Button"; import { AlertContextProvider } from "../context/alertContext/AlertContext";
import { AlertContextProvider } from "../../context/alertContext/AlertContext";
import ActionButtonWithModal from "./ActionButtonWithModal";
window.AlertContext = React.createContext(); window.AlertContext = React.createContext();
const RebootButtonExample = () => { const RebootButtonExample = () => {
const ActionButton = (props) => {
return <Button {...props}>Action</Button>;
};
return ( return (
<AlertContextProvider> <AlertContextProvider>
<div id="modal-container" /> <div id="modal-container" />
<div id="alert-container" /> <div id="alert-container" />
<ActionButtonWithModal <RebootButton />
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> </AlertContextProvider>
); );
}; };

View File

@ -7,8 +7,6 @@
import React from "react"; import React from "react";
import Button from "bootstrap/Button";
import { import {
fireEvent, fireEvent,
getByText, getByText,
@ -24,43 +22,29 @@ import ActionButtonWithModal from "../ActionButtonWithModal/ActionButtonWithModa
describe("<ActionButtonWithModal/>", () => { describe("<ActionButtonWithModal/>", () => {
let componentContainer; let componentContainer;
const ActionButton = (props) => (
<Button type="button" {...props}>
Action
</Button>
);
beforeEach(() => { beforeEach(() => {
const { container } = render( const { container } = render(
<> <>
<div id="modal-container" /> <div id="modal-container" />
<div id="alert-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; componentContainer = container;
}); });
it("Render button.", () => { it("Render.", () => {
expect(componentContainer).toMatchSnapshot(); expect(componentContainer).toMatchSnapshot();
}); });
it("Render modal.", () => { it("Render modal.", () => {
expect(queryByText(componentContainer, "Confirm action")).toBeNull();
fireEvent.click(getByText(componentContainer, "Action")); fireEvent.click(getByText(componentContainer, "Action"));
expect(componentContainer).toMatchSnapshot(); expect(componentContainer).toMatchSnapshot();
}); });
it("Confirm action.", () => { it("Confirm action.", () => {
fireEvent.click(getByText(componentContainer, "Action")); fireEvent.click(getByText(componentContainer, "action"));
fireEvent.click(getByText(componentContainer, "Confirm action")); fireEvent.click(getByText(componentContainer, "Confirm action"));
expect(mockAxios.post).toHaveBeenCalledWith( expect(mockAxios.post).toHaveBeenCalledWith(
"/reforis/api/action", "/reforis/api/action",
@ -77,16 +61,4 @@ describe("<ActionButtonWithModal/>", () => {
expect(mockSetAlert).toBeCalledWith("Action request failed.") 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,25 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<ActionButtonWithModal/> Render button. 1`] = ` exports[`<RebootButton/> Render modal. 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>
<div <div
id="modal-container" id="modal-container"
@ -54,10 +35,8 @@ exports[`<ActionButtonWithModal/> Render modal. 1`] = `
<div <div
class="modal-body" class="modal-body"
> >
<p <p>
class="mb-0" Are you sure you want to restart the router?
>
Are you sure you want to perform this action?
</p> </p>
</div> </div>
<div <div
@ -76,7 +55,7 @@ exports[`<ActionButtonWithModal/> Render modal. 1`] = `
type="button" type="button"
> >
<span> <span>
Confirm action Confirm reboot
</span> </span>
</button> </button>
</div> </div>
@ -84,15 +63,28 @@ exports[`<ActionButtonWithModal/> Render modal. 1`] = `
</div> </div>
</div> </div>
</div> </div>
<div
id="alert-container"
/>
<button <button
class="btn btn-primary d-inline-flex justify-content-center align-items-center" class="btn btn-danger d-inline-flex justify-content-center align-items-center"
type="button" type="button"
> >
<span> <span>
Action Reboot
</span>
</button>
</div>
`;
exports[`<RebootButton/> Render. 1`] = `
<div>
<div
id="modal-container"
/>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
type="button"
>
<span>
Reboot
</span> </span>
</button> </button>
</div> </div>