InAppNotificationDropdown.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import React, { useState, useEffect, FC } from 'react';
  2. import {
  3. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  4. } from 'reactstrap';
  5. import { useTranslation } from 'react-i18next';
  6. import loggerFactory from '~/utils/logger';
  7. import { apiv3Get, apiv3Post } from '~/client/util/apiv3-client';
  8. import { withUnstatedContainers } from '../UnstatedUtils';
  9. import InAppNotificationList from './InAppNotificationList';
  10. import SocketIoContainer from '~/client/services/SocketIoContainer';
  11. import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
  12. const logger = loggerFactory('growi:InAppNotificationDropdown');
  13. type Props = {
  14. socketIoContainer: SocketIoContainer,
  15. };
  16. const InAppNotificationDropdown: FC<Props> = (props: Props) => {
  17. const { t } = useTranslation();
  18. const [count, setCount] = useState(0);
  19. const [isOpen, setIsOpen] = useState(false);
  20. const limit = 6;
  21. const { data: inAppNotificationData, mutate } = useSWRxInAppNotifications(limit);
  22. const { data: inAppNotificationStatusData } = useSWRxInAppNotificationStatus();
  23. const initializeSocket = (props) => {
  24. const socket = props.socketIoContainer.getSocket();
  25. socket.on('notificationUpdated', (data: { userId: string, count: number }) => {
  26. setCount(data.count);
  27. });
  28. };
  29. const updateNotificationStatus = async() => {
  30. try {
  31. await apiv3Post('/in-app-notification/read');
  32. setCount(0);
  33. }
  34. catch (err) {
  35. logger.error(err);
  36. }
  37. };
  38. const fetchNotificationStatus = async() => {
  39. try {
  40. // const res = await apiv3Get('/in-app-notification/status');
  41. // const { count } = res.data;
  42. if (inAppNotificationStatusData != null) {
  43. console.log('inAppNotificationStatusData', inAppNotificationStatusData);
  44. const { count } = inAppNotificationStatusData;
  45. setCount(count);
  46. }
  47. }
  48. catch (err) {
  49. logger.error(err);
  50. }
  51. };
  52. useEffect(() => {
  53. initializeSocket(props);
  54. fetchNotificationStatus();
  55. }, [props]);
  56. const toggleDropdownHandler = () => {
  57. if (!isOpen && count > 0) {
  58. updateNotificationStatus();
  59. }
  60. const newIsOpenState = !isOpen;
  61. if (newIsOpenState) {
  62. mutate();
  63. }
  64. setIsOpen(newIsOpenState);
  65. };
  66. const badge = count > 0 ? <span className="badge badge-pill badge-danger grw-notification-badge">{count}</span> : '';
  67. return (
  68. <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
  69. <DropdownToggle tag="a">
  70. <button type="button" className="nav-link border-0 bg-transparent waves-effect waves-light">
  71. <i className="icon-bell mr-2" /> {badge}
  72. </button>
  73. </DropdownToggle>
  74. <DropdownMenu className="px-2" right>
  75. <InAppNotificationList inAppNotificationData={inAppNotificationData} />
  76. <DropdownItem divider />
  77. <a className="dropdown-item d-flex justify-content-center" href="/me/all-in-app-notifications">{ t('in_app_notification.see_all') }</a>
  78. </DropdownMenu>
  79. </Dropdown>
  80. );
  81. };
  82. /**
  83. * Wrapper component for using unstated
  84. */
  85. const InAppNotificationDropdownWrapper = withUnstatedContainers(InAppNotificationDropdown, [SocketIoContainer]);
  86. export default InAppNotificationDropdownWrapper;