InAppNotificationElm.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React, { useCallback } from 'react';
  2. import { UserPicture, PagePathLabel } from '@growi/ui';
  3. import { IInAppNotification } from '~/interfaces/in-app-notification';
  4. import { HasObjectId } from '~/interfaces/has-object-id';
  5. import { apiv3Post } from '~/client/util/apiv3-client';
  6. import FormattedDistanceDate from '../FormattedDistanceDate';
  7. interface Props {
  8. notification: IInAppNotification & HasObjectId
  9. }
  10. // TODO 81946 Return to not nullable
  11. const InAppNotificationElm = (props: Props): JSX.Element | null => {
  12. const { notification } = props;
  13. const getActionUsers = () => {
  14. const latestActionUsers = notification.actionUsers.slice(0, 3);
  15. const latestUsers = latestActionUsers.map((user) => {
  16. return `@${user.name}`;
  17. });
  18. let actionedUsers = '';
  19. const latestUsersCount = latestUsers.length;
  20. if (latestUsersCount === 1) {
  21. actionedUsers = latestUsers[0];
  22. }
  23. else if (notification.actionUsers.length >= 4) {
  24. actionedUsers = `${latestUsers.slice(0, 2).join(', ')} and ${notification.actionUsers.length - 2} others`;
  25. }
  26. else {
  27. actionedUsers = latestUsers.join(', ');
  28. }
  29. return actionedUsers;
  30. };
  31. const renderActionUserPictures = (): JSX.Element => {
  32. const actionUsers = notification.actionUsers;
  33. if (actionUsers.length < 1) {
  34. return <></>;
  35. }
  36. if (actionUsers.length === 1) {
  37. return <UserPicture user={actionUsers[0]} size="md" noTooltip />;
  38. }
  39. return (
  40. <div className="position-relative">
  41. <UserPicture user={actionUsers[0]} size="md" noTooltip />
  42. <div className="position-absolute" style={{ top: 10, left: 10 }}>
  43. <UserPicture user={actionUsers[1]} size="md" noTooltip />
  44. </div>
  45. </div>
  46. );
  47. };
  48. const notificationClickHandler = useCallback(() => {
  49. // set notification status "OPEND"
  50. apiv3Post('/in-app-notification/open', { id: notification._id });
  51. // jump to target page
  52. window.location.href = notification.target.path;
  53. }, []);
  54. const actionUsers = getActionUsers();
  55. // TODO 81946 Return to not nullable
  56. const pagePath = { path: props.notification.target?.path };
  57. if (pagePath.path == null) {
  58. return null;
  59. }
  60. const actionType: string = notification.action;
  61. let actionMsg: string;
  62. let actionIcon: string;
  63. switch (actionType) {
  64. case 'PAGE_LIKE':
  65. actionMsg = 'liked';
  66. actionIcon = 'icon-like';
  67. break;
  68. case 'PAGE_UPDATE':
  69. actionMsg = 'updated on';
  70. actionIcon = 'ti-agenda';
  71. break;
  72. case 'PAGE_RENAME':
  73. actionMsg = 'renamed';
  74. actionIcon = 'icon-action-redo';
  75. break;
  76. case 'PAGE_DELETE':
  77. actionMsg = 'deleted';
  78. actionIcon = 'icon-trash';
  79. break;
  80. case 'COMMENT_CREATE':
  81. actionMsg = 'commented on';
  82. actionIcon = 'icon-bubble';
  83. break;
  84. default:
  85. actionMsg = '';
  86. actionIcon = '';
  87. }
  88. return (
  89. <div className="dropdown-item d-flex flex-row mb-3">
  90. <div className="p-2 mr-2 d-flex align-items-center">
  91. <span className={`${notification.status === 'UNOPENED' ? 'grw-unopend-notification' : 'ml-2'} rounded-circle mr-3`}></span>
  92. {renderActionUserPictures()}
  93. </div>
  94. <div className="p-2">
  95. <div onClick={notificationClickHandler}>
  96. <div>
  97. <b>{actionUsers}</b> {actionMsg} <PagePathLabel page={pagePath} />
  98. </div>
  99. <i className={`${actionIcon} mr-2`} />
  100. <FormattedDistanceDate
  101. id={notification._id}
  102. date={notification.createdAt}
  103. isShowTooltip={false}
  104. differenceForAvoidingFormat={Number.POSITIVE_INFINITY}
  105. />
  106. </div>
  107. </div>
  108. </div>
  109. );
  110. };
  111. export default InAppNotificationElm;