diff options
Diffstat (limited to 'src/components/ui/Infobox.tsx')
-rw-r--r-- | src/components/ui/Infobox.tsx | 111 |
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 @@ | |||
1 | import { Component, MouseEventHandler, ReactElement, ReactNode } from 'react'; | ||
2 | import classnames from 'classnames'; | ||
3 | import Loader from 'react-loader'; | ||
4 | import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; | ||
5 | import { mdiAlert, mdiCheckboxMarkedCircleOutline, mdiClose } from '@mdi/js'; | ||
6 | import { noop } from 'lodash'; | ||
7 | import { observer } from 'mobx-react'; | ||
8 | import Icon from './icon'; | ||
9 | |||
10 | const icons = { | ||
11 | 'checkbox-marked-circle-outline': mdiCheckboxMarkedCircleOutline, | ||
12 | alert: mdiAlert, | ||
13 | }; | ||
14 | |||
15 | const messages = defineMessages({ | ||
16 | dismiss: { | ||
17 | id: 'infobox.dismiss', | ||
18 | defaultMessage: 'Dismiss', | ||
19 | }, | ||
20 | }); | ||
21 | |||
22 | interface 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 | |||
34 | interface IState { | ||
35 | dismissed: boolean; | ||
36 | } | ||
37 | |||
38 | // Can this file be merged into the './infobox/index.tsx' file? | ||
39 | @observer | ||
40 | class 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 | |||
111 | export default injectIntl(Infobox); | ||