Browse Source

Merge pull request #8263 from weseek/support/133923-continuation-of-the-in-app-notification-refactor

support: 133923-continuation-of-the-in-app-notification-refactor
Yuki Takei 2 years ago
parent
commit
cfc4f62367

+ 15 - 34
apps/app/src/components/InAppNotification/InAppNotificationElm.tsx

@@ -1,19 +1,13 @@
-import React, {
-  FC, useRef,
-} from 'react';
+import React, { FC } from 'react';
 
-import type { IUser, IPage, HasObjectId } from '@growi/core';
+import type { HasObjectId } from '@growi/core';
 import { UserPicture } from '@growi/ui/dist/components';
 import { DropdownItem } from 'reactstrap';
 
-import { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
 import { apiv3Post } from '~/client/util/apiv3-client';
-import { SupportedTargetModel } from '~/interfaces/activity';
 import { IInAppNotification, InAppNotificationStatuses } from '~/interfaces/in-app-notification';
 
-// Change the display for each targetmodel
-import PageModelNotification from './PageNotification/PageModelNotification';
-import UserModelNotification from './PageNotification/UserModelNotification';
+import { useModelNotification } from './PageNotification';
 
 interface Props {
   notification: IInAppNotification & HasObjectId
@@ -26,7 +20,14 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
 
   const { notification } = props;
 
-  const notificationRef = useRef<IInAppNotificationOpenable>(null);
+  const modelNotificationUtils = useModelNotification(notification);
+
+  const Notification = modelNotificationUtils?.Notification;
+  const publishOpen = modelNotificationUtils?.publishOpen;
+
+  if (Notification == null || publishOpen == null) {
+    return <></>;
+  }
 
   const clickHandler = async(notification: IInAppNotification & HasObjectId): Promise<void> => {
     if (notification.status === InAppNotificationStatuses.STATUS_UNOPENED) {
@@ -34,10 +35,7 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
       await apiv3Post('/in-app-notification/open', { id: notification._id });
     }
 
-    const currentInstance = notificationRef.current;
-    if (currentInstance != null) {
-      currentInstance.open();
-    }
+    publishOpen();
   };
 
   const renderActionUserPictures = (): JSX.Element => {
@@ -61,14 +59,6 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
 
   const isDropdownItem = props.type === 'dropdown-item';
 
-  const isPageNotification = (notification: IInAppNotification): notification is IInAppNotification<IPage> => {
-    return notification.targetModel === SupportedTargetModel.MODEL_PAGE;
-  };
-
-  const isUserNotification = (notification: IInAppNotification): notification is IInAppNotification<IUser> => {
-    return notification.targetModel === SupportedTargetModel.MODEL_USER;
-  };
-
   // determine tag
   const TagElem = isDropdownItem
     ? DropdownItem
@@ -86,18 +76,9 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
         >
         </span>
         {renderActionUserPictures()}
-        {isPageNotification(notification) && (
-          <PageModelNotification
-            ref={notificationRef}
-            notification={notification}
-          />
-        )}
-        {isUserNotification(notification) && (
-          <UserModelNotification
-            ref={notificationRef}
-            notification={notification}
-          />
-        )}
+
+        <Notification />
+
       </div>
     </TagElem>
   );

+ 2 - 11
apps/app/src/components/InAppNotification/PageNotification/ModelNotification.tsx

@@ -1,9 +1,8 @@
-import React, { FC, useImperativeHandle } from 'react';
+import React, { FC } from 'react';
 
 import type { HasObjectId } from '@growi/core';
 import { PagePathLabel } from '@growi/ui/dist/components';
 
-import type { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
 import type { IInAppNotification } from '~/interfaces/in-app-notification';
 
 import FormattedDistanceDate from '../../FormattedDistanceDate';
@@ -13,21 +12,13 @@ type Props = {
   actionMsg: string
   actionIcon: string
   actionUsers: string
-  publishOpen:() => void
-  ref: React.ForwardedRef<IInAppNotificationOpenable>
 };
 
 export const ModelNotification: FC<Props> = (props) => {
   const {
-    notification, actionMsg, actionIcon, actionUsers, publishOpen, ref,
+    notification, actionMsg, actionIcon, actionUsers,
   } = props;
 
-  useImperativeHandle(ref, () => ({
-    open() {
-      publishOpen();
-    },
-  }));
-
   return (
     <div className="p-2 overflow-hidden">
       <div className="text-truncate">

+ 34 - 25
apps/app/src/components/InAppNotification/PageNotification/PageModelNotification.tsx

@@ -1,29 +1,27 @@
 import React, {
-  forwardRef, ForwardRefRenderFunction, useCallback,
+  FC, useCallback,
 } from 'react';
 
 import type { IPage, HasObjectId } from '@growi/core';
 import { useRouter } from 'next/router';
 
-import type { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
+import { SupportedTargetModel } from '~/interfaces/activity';
 import type { IInAppNotification } from '~/interfaces/in-app-notification';
 import * as pageSerializers from '~/models/serializers/in-app-notification-snapshot/page';
 
 import { ModelNotification } from './ModelNotification';
-import { useActionMsgAndIconForPageModelNotification } from './useActionAndMsg';
+import { useActionMsgAndIconForModelNotification } from './useActionAndMsg';
 
 
-interface Props {
-  notification: IInAppNotification<IPage> & HasObjectId
+export interface ModelNotificationUtils {
+  Notification: FC
+  publishOpen: () => void
 }
 
-const PageModelNotification: ForwardRefRenderFunction<IInAppNotificationOpenable, Props> = (props: Props, ref) => {
-
-  const { notification } = props;
-
-  const { actionMsg, actionIcon } = useActionMsgAndIconForPageModelNotification(notification);
+export const usePageModelNotification = (notification: IInAppNotification & HasObjectId): ModelNotificationUtils | null => {
 
   const router = useRouter();
+  const { actionMsg, actionIcon } = useActionMsgAndIconForModelNotification(notification);
 
   const getActionUsers = useCallback(() => {
     const latestActionUsers = notification.actionUsers.slice(0, 3);
@@ -46,31 +44,42 @@ const PageModelNotification: ForwardRefRenderFunction<IInAppNotificationOpenable
     return actionedUsers;
   }, [notification.actionUsers]);
 
+  const isPageModelNotification = (notification: IInAppNotification & HasObjectId): notification is IInAppNotification<IPage> & HasObjectId => {
+    return notification.targetModel === SupportedTargetModel.MODEL_PAGE;
+  };
+
+  if (!isPageModelNotification(notification)) {
+    return null;
+  }
+
   const actionUsers = getActionUsers();
 
-  // publish open()
+  notification.parsedSnapshot = pageSerializers.parseSnapshot(notification.snapshot);
+
+  const Notification = () => {
+    return (
+      <ModelNotification
+        notification={notification}
+        actionMsg={actionMsg}
+        actionIcon={actionIcon}
+        actionUsers={actionUsers}
+      />
+    );
+  };
+
   const publishOpen = () => {
     if (notification.target != null) {
       // jump to target page
-      const targetPagePath = notification.target.path;
+      const targetPagePath = (notification.target as IPage).path;
       if (targetPagePath != null) {
         router.push(targetPagePath);
       }
     }
   };
 
-  notification.parsedSnapshot = pageSerializers.parseSnapshot(notification.snapshot);
+  return {
+    Notification,
+    publishOpen,
+  };
 
-  return (
-    <ModelNotification
-      notification={notification}
-      actionMsg={actionMsg}
-      actionIcon={actionIcon}
-      actionUsers={actionUsers}
-      publishOpen={publishOpen}
-      ref={ref}
-    />
-  );
 };
-
-export default forwardRef(PageModelNotification);

+ 30 - 26
apps/app/src/components/InAppNotification/PageNotification/UserModelNotification.tsx

@@ -1,45 +1,49 @@
-import React, {
-  forwardRef, ForwardRefRenderFunction,
-} from 'react';
+import React from 'react';
 
 import type { IUser, HasObjectId } from '@growi/core';
 import { useRouter } from 'next/router';
 
-import type { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
+import { SupportedTargetModel } from '~/interfaces/activity';
 import type { IInAppNotification } from '~/interfaces/in-app-notification';
 
 import { ModelNotification } from './ModelNotification';
-import { useActionMsgAndIconForUserModelNotification } from './useActionAndMsg';
+import { ModelNotificationUtils } from './PageModelNotification';
+import { useActionMsgAndIconForModelNotification } from './useActionAndMsg';
 
-interface Props {
-  notification: IInAppNotification<IUser> & HasObjectId
-}
 
-const UserModelNotification: ForwardRefRenderFunction<IInAppNotificationOpenable, Props> = (props: Props, ref) => {
+export const useUserModelNotification = (notification: IInAppNotification & HasObjectId): ModelNotificationUtils | null => {
 
-  const { notification } = props;
+  const { actionMsg, actionIcon } = useActionMsgAndIconForModelNotification(notification);
+  const router = useRouter();
 
-  const { actionMsg, actionIcon } = useActionMsgAndIconForUserModelNotification(notification);
+  const isUserModelNotification = (notification: IInAppNotification & HasObjectId): notification is IInAppNotification<IUser> & HasObjectId => {
+    return notification.targetModel === SupportedTargetModel.MODEL_USER;
+  };
 
-  const router = useRouter();
+  if (!isUserModelNotification(notification)) {
+    return null;
+  }
+
+  const actionUsers = notification.target.username;
+
+  const Notification = () => {
+    return (
+      <ModelNotification
+        notification={notification}
+        actionMsg={actionMsg}
+        actionIcon={actionIcon}
+        actionUsers={actionUsers}
+      />
+    );
+  };
 
-  // publish open()
   const publishOpen = () => {
     router.push('/admin/users');
   };
 
-  const actionUsers = notification.target.username;
+  return {
+    Notification,
+    publishOpen,
+  };
 
-  return (
-    <ModelNotification
-      notification={notification}
-      actionMsg={actionMsg}
-      actionIcon={actionIcon}
-      actionUsers={actionUsers}
-      publishOpen={publishOpen}
-      ref={ref}
-    />
-  );
 };
-
-export default forwardRef(UserModelNotification);

+ 19 - 0
apps/app/src/components/InAppNotification/PageNotification/index.tsx

@@ -0,0 +1,19 @@
+import type { HasObjectId } from '@growi/core';
+
+import type { IInAppNotification } from '~/interfaces/in-app-notification';
+
+
+import { usePageModelNotification, type ModelNotificationUtils } from './PageModelNotification';
+import { useUserModelNotification } from './UserModelNotification';
+
+
+export const useModelNotification = (notification: IInAppNotification & HasObjectId): ModelNotificationUtils | null => {
+
+  const pageModelNotificationUtils = usePageModelNotification(notification);
+  const userModelNotificationUtils = useUserModelNotification(notification);
+
+  const modelNotificationUtils = pageModelNotificationUtils ?? userModelNotificationUtils;
+
+
+  return modelNotificationUtils;
+};

+ 2 - 19
apps/app/src/components/InAppNotification/PageNotification/useActionAndMsg.ts

@@ -1,4 +1,4 @@
-import type { IUser, IPage, HasObjectId } from '@growi/core';
+import type { HasObjectId } from '@growi/core';
 
 import { SupportedAction } from '~/interfaces/activity';
 import type { IInAppNotification } from '~/interfaces/in-app-notification';
@@ -8,7 +8,7 @@ export type ActionMsgAndIconType = {
   actionIcon: string
 }
 
-export const useActionMsgAndIconForPageModelNotification = (notification: IInAppNotification<IPage> & HasObjectId): ActionMsgAndIconType => {
+export const useActionMsgAndIconForModelNotification = (notification: IInAppNotification & HasObjectId): ActionMsgAndIconType => {
   const actionType: string = notification.action;
   let actionMsg: string;
   let actionIcon: string;
@@ -66,23 +66,6 @@ export const useActionMsgAndIconForPageModelNotification = (notification: IInApp
       actionMsg = 'commented on';
       actionIcon = 'icon-bubble';
       break;
-    default:
-      actionMsg = '';
-      actionIcon = '';
-  }
-
-  return {
-    actionMsg,
-    actionIcon,
-  };
-};
-
-export const useActionMsgAndIconForUserModelNotification = (notification: IInAppNotification<IUser> & HasObjectId): ActionMsgAndIconType => {
-  const actionType: string = notification.action;
-  let actionMsg: string;
-  let actionIcon: string;
-
-  switch (actionType) {
     case SupportedAction.ACTION_USER_REGISTRATION_APPROVAL_REQUEST:
       actionMsg = 'requested registration approval';
       actionIcon = 'icon-bubble';