WNomunomu 2 лет назад
Родитель
Сommit
48c2ec422b

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

@@ -2,7 +2,7 @@ import React, {
   FC, useRef,
 } from 'react';
 
-import type { HasObjectId } from '@growi/core';
+import type { IUser, IPage, HasObjectId } from '@growi/core';
 import { UserPicture } from '@growi/ui/dist/components';
 import { DropdownItem } from 'reactstrap';
 
@@ -16,7 +16,7 @@ import PageModelNotification from './PageNotification/PageModelNotification';
 import UserModelNotification from './PageNotification/UserModelNotification';
 
 interface Props {
-  notification: IInAppNotification & HasObjectId
+  notification: IInAppNotification<IUser | IPage> & HasObjectId
   elemClassName?: string,
   type?: 'button' | 'dropdown-item',
 }
@@ -28,7 +28,7 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
 
   const notificationRef = useRef<IInAppNotificationOpenable>(null);
 
-  const clickHandler = async(notification: IInAppNotification & HasObjectId): Promise<void> => {
+  const clickHandler = async(notification: IInAppNotification<IUser | IPage> & HasObjectId): Promise<void> => {
     if (notification.status === InAppNotificationStatuses.STATUS_UNOPENED) {
       // set notification status "OPEND"
       await apiv3Post('/in-app-notification/open', { id: notification._id });
@@ -40,31 +40,6 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
     }
   };
 
-  const getActionUsers = () => {
-    if (notification.targetModel === SupportedTargetModel.MODEL_USER) {
-      return notification.target.username;
-    }
-
-    const latestActionUsers = notification.actionUsers.slice(0, 3);
-    const latestUsers = latestActionUsers.map((user) => {
-      return `@${user.name}`;
-    });
-
-    let actionedUsers = '';
-    const latestUsersCount = latestUsers.length;
-    if (latestUsersCount === 1) {
-      actionedUsers = latestUsers[0];
-    }
-    else if (notification.actionUsers.length >= 4) {
-      actionedUsers = `${latestUsers.slice(0, 2).join(', ')} and ${notification.actionUsers.length - 2} others`;
-    }
-    else {
-      actionedUsers = latestUsers.join(', ');
-    }
-
-    return actionedUsers;
-  };
-
   const renderActionUserPictures = (): JSX.Element => {
     const actionUsers = notification.actionUsers;
 
@@ -84,10 +59,16 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
     );
   };
 
-  const actionUsers = getActionUsers();
-
   const isDropdownItem = props.type === 'dropdown-item';
 
+  const isPageNotification = (notification: IInAppNotification<IUser | IPage>): notification is IInAppNotification<IPage> => {
+    return notification.targetModel === SupportedTargetModel.MODEL_PAGE;
+  };
+
+  const isUserNotification = (notification: IInAppNotification<IUser | IPage>): notification is IInAppNotification<IUser> => {
+    return notification.targetModel === SupportedTargetModel.MODEL_USER;
+  };
+
   // determine tag
   const TagElem = isDropdownItem
     ? DropdownItem
@@ -105,18 +86,16 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
         >
         </span>
         {renderActionUserPictures()}
-        {notification.targetModel === SupportedTargetModel.MODEL_PAGE && (
+        {isPageNotification(notification) && (
           <PageModelNotification
             ref={notificationRef}
             notification={notification}
-            actionUsers={actionUsers}
           />
         )}
-        {notification.targetModel === SupportedTargetModel.MODEL_USER && (
+        {isUserNotification(notification) && (
           <UserModelNotification
             ref={notificationRef}
             notification={notification}
-            actionUsers={actionUsers}
           />
         )}
       </div>

+ 3 - 3
apps/app/src/components/InAppNotification/InAppNotificationList.tsx

@@ -1,6 +1,6 @@
 import React, { FC } from 'react';
 
-import type { HasObjectId } from '@growi/core';
+import type { IUser, IPage, HasObjectId } from '@growi/core';
 
 import type { IInAppNotification, PaginateResult } from '~/interfaces/in-app-notification';
 
@@ -8,7 +8,7 @@ import InAppNotificationElm from './InAppNotificationElm';
 
 
 type Props = {
-  inAppNotificationData?: PaginateResult<IInAppNotification>,
+  inAppNotificationData?: PaginateResult<IInAppNotification<IUser | IPage>>,
   elemClassName?: string,
   type?: 'button' | 'dropdown-item',
 };
@@ -30,7 +30,7 @@ const InAppNotificationList: FC<Props> = (props: Props) => {
 
   return (
     <>
-      { notifications.map((notification: IInAppNotification & HasObjectId) => {
+      { notifications.map((notification: IInAppNotification<IUser | IPage> & HasObjectId) => {
         return (
           <InAppNotificationElm key={notification._id} notification={notification} type={props.type} elemClassName={props.elemClassName} />
         );

+ 5 - 3
apps/app/src/components/InAppNotification/PageNotification/ModelNotification.tsx

@@ -1,6 +1,6 @@
 import React, { FC, useImperativeHandle } from 'react';
 
-import type { HasObjectId } from '@growi/core';
+import type { IUser, IPage, HasObjectId } from '@growi/core';
 import { PagePathLabel } from '@growi/ui/dist/components';
 
 import type { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
@@ -9,7 +9,7 @@ import type { IInAppNotification } from '~/interfaces/in-app-notification';
 import FormattedDistanceDate from '../../FormattedDistanceDate';
 
 type Props = {
-  notification: IInAppNotification & HasObjectId
+  notification: IInAppNotification<IUser | IPage> & HasObjectId
   actionMsg: string
   actionIcon: string
   actionUsers: string
@@ -31,7 +31,9 @@ export const ModelNotification: FC<Props> = (props) => {
   return (
     <div className="p-2 overflow-hidden">
       <div className="text-truncate">
-        <b>{actionUsers}</b> {actionMsg} <PagePathLabel path={notification.parsedSnapshot?.path ?? ''} />
+        <b>{actionUsers}</b>
+        {actionMsg}
+        <PagePathLabel path={notification.parsedSnapshot?.path ?? ''} />
       </div>
       <i className={`${actionIcon} me-2`} />
       <FormattedDistanceDate

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

@@ -1,4 +1,4 @@
-import type { HasObjectId } from '@growi/core';
+import type { IUser, IPage, 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 & HasObjectId): ActionMsgAndIconType => {
+export const useActionMsgAndIconForPageModelNotification = (notification: IInAppNotification<IPage> & HasObjectId): ActionMsgAndIconType => {
   const actionType: string = notification.action;
   let actionMsg: string;
   let actionIcon: string;
@@ -77,7 +77,7 @@ export const useActionMsgAndIconForPageModelNotification = (notification: IInApp
   };
 };
 
-export const useActionMsgAndIconForUserModelNotification = (notification: IInAppNotification & HasObjectId): ActionMsgAndIconType => {
+export const useActionMsgAndIconForUserModelNotification = (notification: IInAppNotification<IUser> & HasObjectId): ActionMsgAndIconType => {
   const actionType: string = notification.action;
   let actionMsg: string;
   let actionIcon: string;

+ 5 - 2
apps/app/src/server/routes/apiv3/in-app-notification.ts

@@ -1,6 +1,9 @@
+import type { IUser, IPage } from '@growi/core';
+
 import { SupportedAction } from '~/interfaces/activity';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 
+
 import { IInAppNotification } from '../../../interfaces/in-app-notification';
 
 const express = require('express');
@@ -48,12 +51,12 @@ module.exports = (crowi) => {
       return activities.map(({ user }) => user).filter((user, i, self) => self.indexOf(user) === i);
     };
 
-    const serializedDocs: Array<IInAppNotification> = paginationResult.docs.map((doc) => {
+    const serializedDocs: Array<IInAppNotification<IUser | IPage>> = paginationResult.docs.map((doc) => {
       if (doc.user != null && doc.user instanceof User) {
         doc.user = serializeUserSecurely(doc.user);
       }
       // To add a new property into mongoose doc, need to change the format of doc to an object
-      const docObj: IInAppNotification = doc.toObject();
+      const docObj: IInAppNotification<IUser | IPage> = doc.toObject();
       const actionUsersNew = getActionUsersFromActivities(doc.activities);
 
       const serializedActionUsers = actionUsersNew.map((actionUser) => {

+ 9 - 12
apps/app/src/stores/in-app-notification.ts

@@ -1,8 +1,9 @@
+import type { IUser, IPage } from '@growi/core';
 import useSWR, { SWRConfiguration, SWRResponse } from 'swr';
 
+
 import { SupportedTargetModel } from '~/interfaces/activity';
 import type { InAppNotificationStatuses, IInAppNotification, PaginateResult } from '~/interfaces/in-app-notification';
-import * as pageSerializers from '~/models/serializers/in-app-notification-snapshot/page';
 import * as userSerializers from '~/models/serializers/in-app-notification-snapshot/user';
 import loggerFactory from '~/utils/logger';
 
@@ -10,29 +11,25 @@ import { apiv3Get } from '../client/util/apiv3-client';
 
 const logger = loggerFactory('growi:cli:InAppNotification');
 
-type inAppNotificationPaginateResult = PaginateResult<IInAppNotification>
+type inAppNotificationPaginateResult = PaginateResult<IInAppNotification<IUser | IPage>>
 
 export const useSWRxInAppNotifications = (
     limit: number,
     offset?: number,
     status?: InAppNotificationStatuses,
     config?: SWRConfiguration,
-): SWRResponse<PaginateResult<IInAppNotification>, Error> => {
+): SWRResponse<PaginateResult<IInAppNotification<IUser | IPage>>, Error> => {
   return useSWR(
     ['/in-app-notification/list', limit, offset, status],
     ([endpoint]) => apiv3Get(endpoint, { limit, offset, status }).then((response) => {
       const inAppNotificationPaginateResult = response.data as inAppNotificationPaginateResult;
       inAppNotificationPaginateResult.docs.forEach((doc) => {
         try {
-          switch (doc.targetModel) {
-            case SupportedTargetModel.MODEL_PAGE:
-              doc.parsedSnapshot = pageSerializers.parseSnapshot(doc.snapshot);
-              break;
-            case SupportedTargetModel.MODEL_USER:
-              doc.parsedSnapshot = userSerializers.parseSnapshot(doc.snapshot);
-              break;
-            default:
-              throw new Error(`No serializer found for targetModel: ${doc.targetModel}`);
+          if (doc.targetModel === SupportedTargetModel.MODEL_USER) {
+            doc.parsedSnapshot = userSerializers.parseSnapshot(doc.snapshot);
+          }
+          else {
+            throw new Error(`No serializer found for targetModel: ${doc.targetModel}`);
           }
         }
         catch (err) {