refactor modal and confirm alert

This commit is contained in:
Konstantin Schaper
2020-09-23 14:34:21 +02:00
parent fc534605f0
commit 3e5349d5d1
3 changed files with 93 additions and 67 deletions

View File

@@ -25,7 +25,7 @@
import { storiesOf } from "@storybook/react";
import { MemoryRouter } from "react-router-dom";
import * as React from "react";
import ConfirmAlert from "./ConfirmAlert";
import ConfirmAlert, { confirmAlert } from "./ConfirmAlert";
const body =
"Mind-paralyzing change needed improbability vortex machine sorts sought same theory upending job just allows\n " +
@@ -40,11 +40,21 @@ const buttons = [
onClick: () => null
},
{
label: "Submit",
onClick: () => {}
label: "Submit"
}
];
storiesOf("Modal|ConfirmAlert", module)
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
.add("Default", () => <ConfirmAlert message={body} title={"Are you sure about that?"} buttons={buttons} />);
.add("Default", () => <ConfirmAlert message={body} title={"Are you sure about that?"} buttons={buttons} />)
.add("WithButton", () => {
const buttonClick = () => {
confirmAlert({ message: body, title: "Are you sure about that?", buttons });
};
return (
<>
<button onClick={buttonClick}>Open ConfirmAlert</button>
<div id="modalRoot" />
</>
);
});

View File

@@ -22,6 +22,7 @@
* SOFTWARE.
*/
import * as React from "react";
import { FC, useState } from "react";
import ReactDOM from "react-dom";
import Modal from "./Modal";
import classNames from "classnames";
@@ -29,59 +30,71 @@ import classNames from "classnames";
type Button = {
className?: string;
label: string;
onClick: () => void | null;
onClick?: () => void | null;
};
type Props = {
title: string;
message: string;
buttons: Button[];
close?: () => void;
};
class ConfirmAlert extends React.Component<Props> {
handleClickButton = (button: Button) => {
export const ConfirmAlert: FC<Props> = ({ title, message, buttons, close }) => {
const [showModal, setShowModal] = useState(true);
const onClose = () => {
if (typeof close === "function") {
close();
} else {
setShowModal(false);
}
};
const handleClickButton = (button: Button) => {
if (button.onClick) {
button.onClick();
}
this.close();
onClose();
};
close = () => {
const container = document.getElementById("modalRoot");
if (container) {
ReactDOM.unmountComponentAtNode(container);
}
};
const body = <>{message}</>;
render() {
const { title, message, buttons } = this.props;
const footer = (
<div className="field is-grouped">
{buttons.map((button, i) => (
<p className="control">
<a
className={classNames("button", "is-info", button.className)}
key={i}
onClick={() => handleClickButton(button)}
>
{button.label}
</a>
</p>
))}
</div>
);
const body = <>{message}</>;
const footer = (
<div className="field is-grouped">
{buttons.map((button, i) => (
<p className="control">
<a
className={classNames("button", "is-info", button.className)}
key={i}
onClick={() => this.handleClickButton(button)}
>
{button.label}
</a>
</p>
))}
</div>
);
return <Modal title={title} closeFunction={() => this.close()} body={body} active={true} footer={footer} />;
}
}
return (
(showModal && <Modal title={title} closeFunction={onClose} body={body} active={true} footer={footer} />) || null
);
};
/**
* @deprecated Use the {@link ConfirmAlert} component directly instead.
*/
export function confirmAlert(properties: Props) {
const root = document.getElementById("modalRoot");
if (root) {
ReactDOM.render(<ConfirmAlert {...properties} />, root);
const close = () => {
const container = document.getElementById("modalRoot");
if (container) {
ReactDOM.unmountComponentAtNode(container);
}
};
const props = { ...properties, close };
ReactDOM.render(<ConfirmAlert {...props} />, root);
}
}

View File

@@ -22,7 +22,10 @@
* SOFTWARE.
*/
import * as React from "react";
import {FC} from "react";
import classNames from "classnames";
import usePortalRootElement from "../usePortalRootElement";
import ReactDOM from "react-dom";
type Props = {
title: string;
@@ -31,38 +34,38 @@ type Props = {
footer?: any;
active: boolean;
className?: string;
headColor: string;
headColor?: string;
};
class Modal extends React.Component<Props> {
static defaultProps = {
headColor: "light"
};
export const Modal: FC<Props> = ({ title, closeFunction, body, footer, active, className, headColor = "light" }) => {
const portalRootElement = usePortalRootElement("modalsRoot");
render() {
const { title, closeFunction, body, footer, active, className, headColor } = this.props;
const isActive = active ? "is-active" : null;
let showFooter = null;
if (footer) {
showFooter = <footer className="modal-card-foot">{footer}</footer>;
}
return (
<div className={classNames("modal", className, isActive)}>
<div className="modal-background" />
<div className="modal-card">
<header className={classNames("modal-card-head", `has-background-${headColor}`)}>
<p className="modal-card-title is-marginless">{title}</p>
<button className="delete" aria-label="close" onClick={closeFunction} />
</header>
<section className="modal-card-body">{body}</section>
{showFooter}
</div>
</div>
);
if (!portalRootElement) {
return null;
}
}
const isActive = active ? "is-active" : null;
let showFooter = null;
if (footer) {
showFooter = <footer className="modal-card-foot">{footer}</footer>;
}
const modalElement = (
<div className={classNames("modal", className, isActive)}>
<div className="modal-background" />
<div className="modal-card">
<header className={classNames("modal-card-head", `has-background-${headColor}`)}>
<p className="modal-card-title is-marginless">{title}</p>
<button className="delete" aria-label="close" onClick={closeFunction} />
</header>
<section className="modal-card-body">{body}</section>
{showFooter}
</div>
</div>
);
return ReactDOM.createPortal(modalElement, portalRootElement);
};
export default Modal;