indicators.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import React from 'react';
  2. import {ThemeProvider} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {AnimatePresence} from 'framer-motion';
  5. import {Indicator, removeIndicator} from 'app/actionCreators/indicator';
  6. import ToastIndicator from 'app/components/alerts/toastIndicator';
  7. import IndicatorStore from 'app/stores/indicatorStore';
  8. import {lightTheme} from 'app/utils/theme';
  9. const Toasts = styled('div')`
  10. position: fixed;
  11. right: 30px;
  12. bottom: 30px;
  13. z-index: ${p => p.theme.zIndex.toast};
  14. `;
  15. type Props = {
  16. items: Indicator[];
  17. className?: string;
  18. };
  19. class Indicators extends React.Component<Props> {
  20. static defaultProps = {
  21. items: [],
  22. };
  23. handleDismiss = (indicator: Indicator) => {
  24. removeIndicator(indicator);
  25. };
  26. render() {
  27. const {items, ...props} = this.props;
  28. return (
  29. <Toasts {...props}>
  30. <AnimatePresence>
  31. {items.map((indicator, i) => (
  32. // We purposefully use `i` as key here because of transitions
  33. // Toasts can now queue up, so when we change from [firstToast] -> [secondToast],
  34. // we don't want to animate `firstToast` out and `secondToast` in, rather we want
  35. // to replace `firstToast` with `secondToast`
  36. <ToastIndicator
  37. onDismiss={this.handleDismiss}
  38. indicator={indicator}
  39. key={i}
  40. />
  41. ))}
  42. </AnimatePresence>
  43. </Toasts>
  44. );
  45. }
  46. }
  47. type State = {
  48. items: Indicator[];
  49. };
  50. class IndicatorsContainer extends React.Component<Omit<Props, 'items'>, State> {
  51. state: State = {items: IndicatorStore.get()};
  52. componentWillUnmount() {
  53. this.unlistener?.();
  54. }
  55. unlistener = IndicatorStore.listen((items: Indicator[]) => {
  56. this.setState({items});
  57. }, undefined);
  58. render() {
  59. // #NEW-SETTINGS - remove ThemeProvider here once new settings is merged
  60. // `alerts.html` django view includes this container and doesn't have a theme provider
  61. // not even sure it is used in django views but this is just an easier temp solution
  62. return (
  63. <ThemeProvider theme={lightTheme}>
  64. <Indicators {...this.props} items={this.state.items} />
  65. </ThemeProvider>
  66. );
  67. }
  68. }
  69. export default IndicatorsContainer;
  70. export {Indicators};