InAppNotificationDropdown.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import React, { useState, useEffect, FC } from 'react';
  2. import {
  3. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  4. } from 'reactstrap';
  5. import PropTypes from 'prop-types';
  6. import AppContainer from '~/client/services/AppContainer';
  7. import { toastError } from '~/client/util/apiNotification';
  8. import { withUnstatedContainers } from '../UnstatedUtils';
  9. import { InAppNotification as IInAppNotification } from '../../interfaces/in-app-notification';
  10. // import DropdownMenu from './InAppNotificationDropdown/DropdownMenu';
  11. // import Crowi from 'client/util/Crowi'
  12. // import { Notification } from 'client/types/crowi'
  13. import { InAppNotification } from './InAppNotification';
  14. import SocketIoContainer from '../../client/services/SocketIoContainer';
  15. const InAppNotificationDropdown: FC = (props) => {
  16. const [count, setCount] = useState(0);
  17. const [isLoaded, setIsLoaded] = useState(false);
  18. const [notifications, setNotifications] = useState<IInAppNotification[]>([{
  19. // This is dummy notification data. Delete it after fetching notification list by #78756
  20. _id: '1',
  21. user: 'kaori1',
  22. targetModel: 'Page',
  23. target: 'hogePage',
  24. action: 'COMMENT',
  25. status: 'hoge',
  26. actionUsers: ['taro', 'yamada'],
  27. createdAt: 'hoge',
  28. }]);
  29. const [isOpen, setIsOpen] = useState(false);
  30. useEffect(() => {
  31. initializeSocket(props);
  32. fetchNotificationList(props);
  33. }, []);
  34. const initializeSocket = (props) => {
  35. console.log(props);
  36. const socket = props.socketIoContainer.getSocket();
  37. socket.on('commentUpdated', (data: { userId: string, count: number }) => {
  38. // eslint-disable-next-line no-console
  39. console.log('socketData', data);
  40. if (props.me === data.userId) {
  41. // TODO: Fetch notification list by #78557
  42. // fetchNotificationList();
  43. }
  44. });
  45. };
  46. const updateNotificationStatus = () => {
  47. try {
  48. // await this.props.crowi.apiPost('/notification.read');
  49. setCount(0);
  50. }
  51. catch (err) {
  52. // TODO: error handling
  53. }
  54. };
  55. /**
  56. * TODO: Fetch notification list by GW-7473
  57. */
  58. const fetchNotificationList = async(props) => {
  59. const limit = 6;
  60. try {
  61. const inAppNotificationList = await props.appContainer.apiv3Get('/in-app-notification/list', { limit });
  62. // setNotifications(notifications);
  63. // setIsLoaded(true);
  64. }
  65. catch (err) {
  66. // TODO: error handling
  67. }
  68. };
  69. const toggleDropdownHandler = () => {
  70. if (isOpen === false && count > 0) {
  71. updateNotificationStatus();
  72. }
  73. setIsOpen(!isOpen);
  74. };
  75. /**
  76. * TODO: Jump to the page by clicking on the notification by GW-7472
  77. */
  78. const notificationClickHandler = async(notification: Notification) => {
  79. try {
  80. // await this.props.crowi.apiPost('/notification.open', { id: notification._id });
  81. // jump to target page
  82. // window.location.href = notification.target.path;
  83. }
  84. catch (err) {
  85. // TODO: error handling
  86. }
  87. };
  88. const badge = count > 0 ? <span className="badge badge-pill badge-danger notification-badge">{count}</span> : '';
  89. const RenderUnLoadedInAppNotification = (): JSX.Element => {
  90. return (
  91. <i className="fa fa-spinner"></i>
  92. );
  93. };
  94. const RenderEmptyInAppNotification = (): JSX.Element => {
  95. return (
  96. // TODO: apply i18n by #78569
  97. <>You had no notifications, yet.</>
  98. );
  99. };
  100. // TODO: improve renderInAppNotificationList by GW-7535
  101. // refer to https://github.com/crowi/crowi/blob/eecf2bc821098d2516b58104fe88fae81497d3ea/client/components/Notification/Notification.tsx
  102. const RenderInAppNotificationList = () => {
  103. console.log('notificationsHoge', notifications);
  104. if (notifications.length === 0) {
  105. return <RenderEmptyInAppNotification />;
  106. }
  107. const notificationList = notifications.map((notification: IInAppNotification) => {
  108. return (
  109. <InAppNotification key={notification._id} notification={notification} onClick={notificationClickHandler} />
  110. );
  111. });
  112. return <>{notificationList}</>;
  113. };
  114. const InAppNotificationContents = (): JSX.Element => {
  115. // if (isLoaded === false) {
  116. // return <RenderUnLoadedInAppNotification />;
  117. // }
  118. return <RenderInAppNotificationList />;
  119. };
  120. return (
  121. <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
  122. <DropdownToggle tag="a" className="nav-link">
  123. <i className="icon-bell mr-2"></i>
  124. {badge}
  125. </DropdownToggle>
  126. <DropdownMenu right>
  127. <InAppNotificationContents />
  128. <DropdownItem divider />
  129. {/* TODO: Able to show all notifications by GW-7534 */}
  130. <a>See All</a>
  131. </DropdownMenu>
  132. </Dropdown>
  133. );
  134. };
  135. /**
  136. * Wrapper component for using unstated
  137. */
  138. const InAppNotificationDropdownWrapper = withUnstatedContainers(InAppNotificationDropdown, [AppContainer, SocketIoContainer]);
  139. InAppNotificationDropdown.propTypes = {
  140. me: PropTypes.string,
  141. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  142. socketIoContainer: PropTypes.instanceOf(SocketIoContainer).isRequired,
  143. };
  144. export default InAppNotificationDropdownWrapper;