InAppNotificationElm.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import React, {
  2. FC, useRef,
  3. } from 'react';
  4. import type { IUser, IPage, HasObjectId } from '@growi/core';
  5. import { UserPicture } from '@growi/ui/dist/components';
  6. import { DropdownItem } from 'reactstrap';
  7. import { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
  8. import { apiv3Post } from '~/client/util/apiv3-client';
  9. import { SupportedTargetModel } from '~/interfaces/activity';
  10. import { IInAppNotification, InAppNotificationStatuses } from '~/interfaces/in-app-notification';
  11. // Change the display for each targetmodel
  12. import PageModelNotification from './PageNotification/PageModelNotification';
  13. import UserModelNotification from './PageNotification/UserModelNotification';
  14. interface Props {
  15. notification: IInAppNotification & HasObjectId
  16. elemClassName?: string,
  17. type?: 'button' | 'dropdown-item',
  18. }
  19. const InAppNotificationElm: FC<Props> = (props: Props) => {
  20. const { notification } = props;
  21. const notificationRef = useRef<IInAppNotificationOpenable>(null);
  22. const clickHandler = async(notification: IInAppNotification & HasObjectId): Promise<void> => {
  23. if (notification.status === InAppNotificationStatuses.STATUS_UNOPENED) {
  24. // set notification status "OPEND"
  25. await apiv3Post('/in-app-notification/open', { id: notification._id });
  26. }
  27. const currentInstance = notificationRef.current;
  28. if (currentInstance != null) {
  29. currentInstance.open();
  30. }
  31. };
  32. const renderActionUserPictures = (): JSX.Element => {
  33. const actionUsers = notification.actionUsers;
  34. if (actionUsers.length < 1) {
  35. return <></>;
  36. }
  37. if (actionUsers.length === 1) {
  38. return <UserPicture user={actionUsers[0]} size="md" noTooltip />;
  39. }
  40. return (
  41. <div className="position-relative">
  42. <UserPicture user={actionUsers[0]} size="md" noTooltip />
  43. <div className="position-absolute" style={{ top: 10, left: 10 }}>
  44. <UserPicture user={actionUsers[1]} size="md" noTooltip />
  45. </div>
  46. </div>
  47. );
  48. };
  49. const isDropdownItem = props.type === 'dropdown-item';
  50. const isPageNotification = (notification: IInAppNotification): notification is IInAppNotification<IPage> => {
  51. return notification.targetModel === SupportedTargetModel.MODEL_PAGE;
  52. };
  53. const isUserNotification = (notification: IInAppNotification): notification is IInAppNotification<IUser> => {
  54. return notification.targetModel === SupportedTargetModel.MODEL_USER;
  55. };
  56. // determine tag
  57. const TagElem = isDropdownItem
  58. ? DropdownItem
  59. // eslint-disable-next-line react/prop-types
  60. : props => <button type="button" {...props}>{props.children}</button>;
  61. return (
  62. <TagElem className={props.elemClassName} onClick={() => clickHandler(notification)}>
  63. <div className="d-flex align-items-center">
  64. <span
  65. className={`${notification.status === InAppNotificationStatuses.STATUS_UNOPENED
  66. ? 'grw-unopend-notification'
  67. : 'ms-2'
  68. } rounded-circle me-3`}
  69. >
  70. </span>
  71. {renderActionUserPictures()}
  72. {isPageNotification(notification) && (
  73. <PageModelNotification
  74. ref={notificationRef}
  75. notification={notification}
  76. />
  77. )}
  78. {isUserNotification(notification) && (
  79. <UserModelNotification
  80. ref={notificationRef}
  81. notification={notification}
  82. />
  83. )}
  84. </div>
  85. </TagElem>
  86. );
  87. };
  88. export default InAppNotificationElm;