InAppNotificationDropdown.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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 { withUnstatedContainers } from '../UnstatedUtils';
  8. import { InAppNotification as IInAppNotification } from '../../interfaces/in-app-notification';
  9. // import DropdownMenu from './InAppNotificationDropdown/DropdownMenu';
  10. // import Crowi from 'client/util/Crowi'
  11. // import { Notification } from 'client/types/crowi'
  12. import { InAppNotification } from './InAppNotification';
  13. import SocketIoContainer from '../../client/services/SocketIoContainer';
  14. const InAppNotificationDropdown: FC = (props) => {
  15. const [count, setCount] = useState(0);
  16. const [isLoaded, setIsLoaded] = useState(false);
  17. const [notifications, setNotifications] = useState<IInAppNotification[]>([
  18. {
  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. ]);
  30. const [isOpen, setIsOpen] = useState(false);
  31. useEffect(() => {
  32. initializeSocket(props);
  33. fetchNotificationList(props);
  34. // fetchNotificationStatus();
  35. }, []);
  36. const initializeSocket = (props) => {
  37. console.log(props);
  38. const socket = props.socketIoContainer.getSocket();
  39. socket.on('comment updated', (data: { user: string }) => {
  40. // eslint-disable-next-line no-console
  41. console.log('socketData', data);
  42. if (props.me === data.user) {
  43. // TODO: Fetch notification status by #78563
  44. // fetchNotificationList();
  45. // TODO: Fetch notification list by #78557
  46. // fetchNotificationStatus();
  47. }
  48. });
  49. };
  50. /**
  51. * TODO: Fetch notification status by #78563
  52. */
  53. // async fetchNotificationStatus() {
  54. // try {
  55. // const { count = null } = await this.props.crowi.apiGet('/notification.status');
  56. // if (count !== null && count !== this.state.count) {
  57. // this.setState({ count });
  58. // }
  59. // }
  60. // catch (err) {
  61. // // TODO: error handling
  62. // }
  63. // }
  64. const updateNotificationStatus = () => {
  65. try {
  66. // await this.props.crowi.apiPost('/notification.read');
  67. setCount(0);
  68. }
  69. catch (err) {
  70. // TODO: error handling
  71. }
  72. };
  73. /**
  74. * TODO: Fetch notification list by GW-7473
  75. */
  76. const fetchNotificationList = async(props) => {
  77. console.log('propsappContainerHoge', props.appContainer);
  78. const limit = 6;
  79. try {
  80. const notifications = await props.appContainer.apiv3Get('/in-app-notification/list', { limit });
  81. console.log('notificationsHoge', notifications);
  82. // setNotifications(notifications);
  83. // setIsLoaded(true);
  84. }
  85. catch (err) {
  86. // TODO: error handling
  87. }
  88. };
  89. const toggleDropdownHandler = () => {
  90. if (isOpen === false && count > 0) {
  91. updateNotificationStatus();
  92. }
  93. setIsOpen(!isOpen);
  94. };
  95. /**
  96. * TODO: Jump to the page by clicking on the notification by GW-7472
  97. */
  98. const notificationClickHandler = async(notification: Notification) => {
  99. try {
  100. // await this.props.crowi.apiPost('/notification.open', { id: notification._id });
  101. // jump to target page
  102. // window.location.href = notification.target.path;
  103. }
  104. catch (err) {
  105. // TODO: error handling
  106. }
  107. };
  108. const badge = count > 0 ? <span className="badge badge-pill badge-danger notification-badge">{count}</span> : '';
  109. const RenderUnLoadedInAppNotification = (): JSX.Element => {
  110. return (
  111. <i className="fa fa-spinner"></i>
  112. );
  113. };
  114. const RenderEmptyInAppNotification = (): JSX.Element => {
  115. return (
  116. // TODO: apply i18n by #78569
  117. <>You had no notifications, yet.</>
  118. );
  119. };
  120. // TODO: improve renderInAppNotificationList by GW-7535
  121. // refer to https://github.com/crowi/crowi/blob/eecf2bc821098d2516b58104fe88fae81497d3ea/client/components/Notification/Notification.tsx
  122. const RenderInAppNotificationList = () => {
  123. console.log('notificationsHoge', notifications);
  124. if (notifications.length === 0) {
  125. return <RenderEmptyInAppNotification />;
  126. }
  127. const notificationList = notifications.map((notification: IInAppNotification) => {
  128. return (
  129. <InAppNotification key={notification._id} notification={notification} onClick={notificationClickHandler} />
  130. );
  131. });
  132. return <>{notificationList}</>;
  133. };
  134. const InAppNotificationContents = (): JSX.Element => {
  135. // if (isLoaded === false) {
  136. // return <RenderUnLoadedInAppNotification />;
  137. // }
  138. return <RenderInAppNotificationList />;
  139. };
  140. return (
  141. <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
  142. <DropdownToggle tag="a" className="nav-link">
  143. <i className="icon-bell mr-2"></i>
  144. {badge}
  145. </DropdownToggle>
  146. <DropdownMenu right>
  147. <InAppNotificationContents />
  148. <DropdownItem divider />
  149. {/* TODO: Able to show all notifications by GW-7534 */}
  150. <a>See All</a>
  151. </DropdownMenu>
  152. </Dropdown>
  153. );
  154. };
  155. /**
  156. * Wrapper component for using unstated
  157. */
  158. const InAppNotificationDropdownWrapper = withUnstatedContainers(InAppNotificationDropdown, [AppContainer, SocketIoContainer]);
  159. InAppNotificationDropdown.propTypes = {
  160. me: PropTypes.string,
  161. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  162. socketIoContainer: PropTypes.instanceOf(SocketIoContainer).isRequired,
  163. };
  164. export default InAppNotificationDropdownWrapper;