diff --git a/src/common/ActionButtonWithModal/ActionButtonWithModal.js b/src/common/ActionButtonWithModal/ActionButtonWithModal.js new file mode 100644 index 0000000..783b76b --- /dev/null +++ b/src/common/ActionButtonWithModal/ActionButtonWithModal.js @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019-2024 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, { 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"; +import { + Modal, + ModalHeader, + ModalBody, + ModalFooter, +} from "../../bootstrap/Modal"; +import { useAlert } from "../../context/alertContext/AlertContext"; + +ActionButtonWithModal.propTypes = { + actionTrigger: PropTypes.elementType.isRequired, + actionUrl: PropTypes.string.isRequired, + modalTitle: PropTypes.string.isRequired, + modalMessage: PropTypes.string.isRequired, + modalActionText: PropTypes.string, + modalActionProps: PropTypes.object, + successMessage: PropTypes.string, + errorMessage: PropTypes.string, +}; + +function ActionButtonWithModal({ + actionTrigger: ActionTriggerComponent, + actionUrl, + modalTitle, + modalMessage, + modalActionText, + modalActionProps, + successMessage, + errorMessage, +}) { + const [triggered, setTriggered] = useState(false); + const [modalShown, setModalShown] = useState(false); + const [triggerActionStatus, triggerAction] = useAPIPost(actionUrl); + + const [setAlert] = useAlert(); + useEffect(() => { + if (triggerActionStatus.state === API_STATE.SUCCESS) { + setAlert( + successMessage || _("Action successful."), + API_STATE.SUCCESS + ); + } + if (triggerActionStatus.state === API_STATE.ERROR) { + setAlert(errorMessage || _("Action failed.")); + } + }, [triggerActionStatus, setAlert, successMessage, errorMessage]); + + const actionHandler = () => { + setTriggered(true); + triggerAction(); + setModalShown(false); + }; + + return ( + <> + + setModalShown(true)} + /> + + ); +} + +ActionModal.propTypes = { + shown: PropTypes.bool.isRequired, + setShown: PropTypes.func.isRequired, + onAction: PropTypes.func.isRequired, + title: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, + actionText: PropTypes.string, +}; + +function ActionModal({ + shown, + setShown, + onAction, + title, + message, + actionText, + actionProps, +}) { + return ( + + + +

{message}

+
+ + + + +
+ ); +} + +export default ActionButtonWithModal; diff --git a/src/common/RebootButton.md b/src/common/ActionButtonWithModal/ActionButtonWithModal.md similarity index 100% rename from src/common/RebootButton.md rename to src/common/ActionButtonWithModal/ActionButtonWithModal.md diff --git a/src/common/RebootButton.js b/src/common/RebootButton.js deleted file mode 100644 index 380b30d..0000000 --- a/src/common/RebootButton.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019-2024 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, { 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"; -import { Modal, ModalHeader, ModalBody, ModalFooter } from "../bootstrap/Modal"; -import { useAlert } from "../context/alertContext/AlertContext"; -import { ForisURLs } from "../utils/forisUrls"; - -RebootButton.propTypes = { - /** Additional props to be passed to the button */ - props: PropTypes.object, -}; - -function RebootButton(props) { - const [triggered, setTriggered] = useState(false); - const [modalShown, setModalShown] = useState(false); - const [triggerRebootStatus, triggerReboot] = useAPIPost(ForisURLs.reboot); - - const [setAlert] = useAlert(); - useEffect(() => { - if (triggerRebootStatus.state === API_STATE.ERROR) { - setAlert(_("Reboot request failed.")); - } - }); - - const rebootHandler = () => { - setTriggered(true); - triggerReboot(); - setModalShown(false); - }; - - return ( - <> - - - - ); -} - -RebootModal.propTypes = { - shown: PropTypes.bool.isRequired, - setShown: PropTypes.func.isRequired, - onReboot: PropTypes.func.isRequired, -}; - -function RebootModal({ shown, setShown, onReboot }) { - return ( - - - -

{_("Are you sure you want to restart the router?")}

-
- - - - -
- ); -} - -export default RebootButton; diff --git a/src/common/__tests__/RebootButton.test.js b/src/common/__tests__/ActionButtonWithModal.test.js similarity index 57% rename from src/common/__tests__/RebootButton.test.js rename to src/common/__tests__/ActionButtonWithModal.test.js index 74c5b8e..11858a6 100644 --- a/src/common/__tests__/RebootButton.test.js +++ b/src/common/__tests__/ActionButtonWithModal.test.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/) + * Copyright (C) 2019-2024 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. @@ -18,15 +18,16 @@ import mockAxios from "jest-mock-axios"; import { mockJSONError } from "testUtils/network"; import { mockSetAlert } from "testUtils/alertContextMock"; -import RebootButton from "../RebootButton"; +import ActionButtonWithModal from "../ActionButtonWithModal/ActionButtonWithModal"; -describe("", () => { +describe("", () => { let componentContainer; beforeEach(() => { const { container } = render( <>