aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui/Infobox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ui/Infobox.tsx')
-rw-r--r--src/components/ui/Infobox.tsx111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/components/ui/Infobox.tsx b/src/components/ui/Infobox.tsx
new file mode 100644
index 000000000..1fc24816a
--- /dev/null
+++ b/src/components/ui/Infobox.tsx
@@ -0,0 +1,111 @@
1import { Component, MouseEventHandler, ReactElement, ReactNode } from 'react';
2import classnames from 'classnames';
3import Loader from 'react-loader';
4import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
5import { mdiAlert, mdiCheckboxMarkedCircleOutline, mdiClose } from '@mdi/js';
6import { noop } from 'lodash';
7import { observer } from 'mobx-react';
8import Icon from './icon';
9
10const icons = {
11 'checkbox-marked-circle-outline': mdiCheckboxMarkedCircleOutline,
12 alert: mdiAlert,
13};
14
15const messages = defineMessages({
16 dismiss: {
17 id: 'infobox.dismiss',
18 defaultMessage: 'Dismiss',
19 },
20});
21
22interface IProps extends WrappedComponentProps {
23 children: ReactNode;
24 icon?: string;
25 type?: string;
26 ctaLabel?: string;
27 ctaLoading?: boolean;
28 dismissible?: boolean;
29 ctaOnClick?: MouseEventHandler<HTMLButtonElement>;
30 onDismiss?: () => void;
31 onSeen?: () => void;
32}
33
34interface IState {
35 dismissed: boolean;
36}
37
38// Can this file be merged into the './infobox/index.tsx' file?
39@observer
40class Infobox extends Component<IProps, IState> {
41 constructor(props: IProps) {
42 super(props);
43
44 this.state = {
45 dismissed: false,
46 };
47 }
48
49 componentDidMount(): void {
50 const { onSeen = noop } = this.props;
51 onSeen();
52 }
53
54 render(): ReactElement | null {
55 const {
56 children,
57 icon = '',
58 type = 'primary',
59 dismissible = false,
60 ctaOnClick = noop,
61 ctaLabel = '',
62 ctaLoading = false,
63 onDismiss = noop,
64 intl,
65 } = this.props;
66
67 if (this.state.dismissed) {
68 return null;
69 }
70
71 return (
72 <div
73 className={classnames({
74 infobox: true,
75 [`infobox--${type}`]: type,
76 'infobox--default': !type,
77 })}
78 >
79 {icon && <Icon icon={icons[icon]} />}
80 <div className="infobox__content">{children}</div>
81 {ctaLabel && (
82 <button className="infobox__cta" onClick={ctaOnClick} type="button">
83 <Loader
84 loaded={!ctaLoading}
85 lines={10}
86 scale={0.3}
87 color="#FFF"
88 component="span"
89 />
90 {ctaLabel}
91 </button>
92 )}
93 {dismissible && (
94 <button
95 type="button"
96 onClick={() => {
97 this.setState({ dismissed: true });
98 if (onDismiss) onDismiss();
99 }}
100 className="infobox__delete"
101 aria-label={intl.formatMessage(messages.dismiss)}
102 >
103 <Icon icon={mdiClose} />
104 </button>
105 )}
106 </div>
107 );
108 }
109}
110
111export default injectIntl(Infobox);