InAppNotificationDropdown.tsx 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import React, {
  2. useState, useEffect, useRef, type JSX,
  3. } from 'react';
  4. import { useTranslation } from 'next-i18next';
  5. import { useRipple } from 'react-use-ripple';
  6. import {
  7. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  8. } from 'reactstrap';
  9. import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
  10. import { useDefaultSocket } from '~/stores/socket-io';
  11. import InAppNotificationList from './InAppNotificationList';
  12. export const InAppNotificationDropdown = (): JSX.Element => {
  13. const { t } = useTranslation('commons');
  14. const [isOpen, setIsOpen] = useState(false);
  15. const limit = 6;
  16. const { data: socket } = useDefaultSocket();
  17. const { data: inAppNotificationData, mutate: mutateInAppNotificationData } = useSWRxInAppNotifications(
  18. limit, undefined, undefined,
  19. { revalidateOnFocus: isOpen },
  20. );
  21. const { data: inAppNotificationUnreadStatusCount, mutate: mutateInAppNotificationUnreadStatusCount } = useSWRxInAppNotificationStatus();
  22. // ripple
  23. const buttonRef = useRef(null);
  24. useRipple(buttonRef, { rippleColor: 'rgba(255, 255, 255, 0.3)' });
  25. useEffect(() => {
  26. if (socket != null) {
  27. socket.on('notificationUpdated', () => {
  28. mutateInAppNotificationUnreadStatusCount();
  29. });
  30. // clean up
  31. return () => {
  32. socket.off('notificationUpdated');
  33. };
  34. }
  35. }, [mutateInAppNotificationUnreadStatusCount, socket]);
  36. const toggleDropdownHandler = async() => {
  37. if (!isOpen && inAppNotificationUnreadStatusCount != null && inAppNotificationUnreadStatusCount > 0) {
  38. mutateInAppNotificationUnreadStatusCount();
  39. }
  40. const newIsOpenState = !isOpen;
  41. if (newIsOpenState) {
  42. mutateInAppNotificationData();
  43. }
  44. setIsOpen(newIsOpenState);
  45. };
  46. let badge;
  47. if (inAppNotificationUnreadStatusCount != null && inAppNotificationUnreadStatusCount > 0) {
  48. badge = <span className="badge rounded-pill bg-danger grw-notification-badge">{inAppNotificationUnreadStatusCount}</span>;
  49. }
  50. else {
  51. badge = '';
  52. }
  53. return (
  54. <Dropdown className="notification-wrapper grw-notification-dropdown" isOpen={isOpen} toggle={toggleDropdownHandler} direction="end">
  55. <DropdownToggle className="px-3" color="primary" innerRef={buttonRef}>
  56. <span className="material-symbols-outlined">notifications</span> {badge}
  57. </DropdownToggle>
  58. { isOpen && (
  59. <DropdownMenu end>
  60. { inAppNotificationData != null && inAppNotificationData.docs.length === 0
  61. // no items
  62. ? <DropdownItem disabled>{t('in_app_notification.no_unread_messages')}</DropdownItem>
  63. // render DropdownItem
  64. : <InAppNotificationList inAppNotificationData={inAppNotificationData} />
  65. }
  66. <DropdownItem divider />
  67. <DropdownItem tag="a" href="/me/all-in-app-notifications">
  68. { t('in_app_notification.see_all') }
  69. </DropdownItem>
  70. </DropdownMenu>
  71. ) }
  72. </Dropdown>
  73. );
  74. };