dismissable_banner.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. /* eslint-disable @typescript-eslint/no-unsafe-call,
  2. @typescript-eslint/no-unsafe-return,
  3. @typescript-eslint/no-unsafe-assignment,
  4. @typescript-eslint/no-unsafe-member-access
  5. -- the settings store is not yet typed */
  6. import type { PropsWithChildren } from 'react';
  7. import { useCallback, useState, useEffect } from 'react';
  8. import { defineMessages, useIntl } from 'react-intl';
  9. import CloseIcon from '@/material-icons/400-24px/close.svg?react';
  10. import { changeSetting } from 'mastodon/actions/settings';
  11. import { bannerSettings } from 'mastodon/settings';
  12. import { useAppSelector, useAppDispatch } from 'mastodon/store';
  13. import { IconButton } from './icon_button';
  14. const messages = defineMessages({
  15. dismiss: { id: 'dismissable_banner.dismiss', defaultMessage: 'Dismiss' },
  16. });
  17. interface Props {
  18. id: string;
  19. }
  20. export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
  21. id,
  22. children,
  23. }) => {
  24. const dismissed = useAppSelector((state) =>
  25. state.settings.getIn(['dismissed_banners', id], false),
  26. );
  27. const dispatch = useAppDispatch();
  28. const [visible, setVisible] = useState(!bannerSettings.get(id) && !dismissed);
  29. const intl = useIntl();
  30. const handleDismiss = useCallback(() => {
  31. setVisible(false);
  32. bannerSettings.set(id, true);
  33. dispatch(changeSetting(['dismissed_banners', id], true));
  34. }, [id, dispatch]);
  35. useEffect(() => {
  36. if (!visible && !dismissed) {
  37. dispatch(changeSetting(['dismissed_banners', id], true));
  38. }
  39. }, [id, dispatch, visible, dismissed]);
  40. if (!visible) {
  41. return null;
  42. }
  43. return (
  44. <div className='dismissable-banner'>
  45. <div className='dismissable-banner__action'>
  46. <IconButton
  47. icon='times'
  48. iconComponent={CloseIcon}
  49. title={intl.formatMessage(messages.dismiss)}
  50. onClick={handleDismiss}
  51. />
  52. </div>
  53. <div className='dismissable-banner__message'>{children}</div>
  54. </div>
  55. );
  56. };