InAppNotificationDropdown.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import React, { useState, useEffect, FC } from 'react';
  2. import {
  3. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  4. } from 'reactstrap';
  5. import loggerFactory from '~/utils/logger';
  6. import AppContainer from '../../client/services/AppContainer';
  7. import { withUnstatedContainers } from '../UnstatedUtils';
  8. import InAppNotificationContents from './InAppNotificationContents';
  9. import SocketIoContainer from '../../client/services/SocketIoContainer';
  10. const logger = loggerFactory('growi:InAppNotificationDropdown');
  11. type Props = {
  12. appContainer: AppContainer,
  13. socketIoContainer: SocketIoContainer,
  14. };
  15. const InAppNotificationDropdown: FC<Props> = (props: Props) => {
  16. const { appContainer } = props;
  17. const [count, setCount] = useState(0);
  18. const [isLoaded, setIsLoaded] = useState(false);
  19. const [notifications, setNotifications] = useState([]);
  20. const [isOpen, setIsOpen] = useState(false);
  21. useEffect(() => {
  22. initializeSocket(props);
  23. fetchNotificationStatus();
  24. }, []);
  25. const initializeSocket = (props) => {
  26. const socket = props.socketIoContainer.getSocket();
  27. socket.on('notificationUpdated', (data: { userId: string, count: number }) => {
  28. setCount(data.count);
  29. // eslint-disable-next-line no-console
  30. console.log('socketData', data);
  31. });
  32. };
  33. const updateNotificationStatus = async() => {
  34. try {
  35. await appContainer.apiv3Post('/in-app-notification/read');
  36. setCount(0);
  37. }
  38. catch (err) {
  39. logger.error(err);
  40. }
  41. };
  42. const fetchNotificationStatus = async() => {
  43. try {
  44. const res = await appContainer.apiv3Get('/in-app-notification/status');
  45. const { count } = res.data;
  46. setCount(count);
  47. }
  48. catch (err) {
  49. logger.error(err);
  50. }
  51. };
  52. /**
  53. * TODO: Fetch notification list by GW-7473
  54. */
  55. const fetchNotificationList = async() => {
  56. const limit = 6;
  57. try {
  58. const paginationResult = await appContainer.apiv3Get('/in-app-notification/list', { limit });
  59. setNotifications(paginationResult.data.docs);
  60. setIsLoaded(true);
  61. }
  62. catch (err) {
  63. logger.error(err);
  64. }
  65. };
  66. const toggleDropdownHandler = () => {
  67. if (isOpen === false && count > 0) {
  68. updateNotificationStatus();
  69. }
  70. const newIsOpenState = !isOpen;
  71. setIsOpen(newIsOpenState);
  72. if (newIsOpenState === true) {
  73. fetchNotificationList();
  74. }
  75. };
  76. /**
  77. * TODO: Jump to the page by clicking on the notification by GW-7472
  78. */
  79. const badge = count > 0 ? <span className="badge badge-pill badge-danger grw-notification-badge">{count}</span> : '';
  80. return (
  81. <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
  82. <DropdownToggle tag="a">
  83. <button type="button" className="nav-link border-0 bg-transparent waves-effect waves-light">
  84. <i className="icon-bell mr-2" /> {badge}
  85. </button>
  86. </DropdownToggle>
  87. <DropdownMenu className="px-2" right>
  88. <InAppNotificationContents notifications={notifications} isLoaded={isLoaded} />
  89. <DropdownItem divider />
  90. {/* TODO: Able to show all notifications by #79317 */}
  91. <a className="dropdown-item d-flex justify-content-center" href="/me/all-in-app-notifications">See All</a>
  92. </DropdownMenu>
  93. </Dropdown>
  94. );
  95. };
  96. /**
  97. * Wrapper component for using unstated
  98. */
  99. const InAppNotificationDropdownWrapper = withUnstatedContainers(InAppNotificationDropdown, [AppContainer, SocketIoContainer]);
  100. export default InAppNotificationDropdownWrapper;