Przeglądaj źródła

Merge pull request #9124 from weseek/fix/138463-153969-fix-notification-count-badge

fix: Notification count badge
Yuki Takei 1 rok temu
rodzic
commit
67c9467b00

+ 0 - 19
apps/app/src/client/components/InAppNotification/InAppNotificationDropdown.tsx

@@ -6,19 +6,11 @@ import {
   Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
 } from 'reactstrap';
 
-
-import { apiv3Post } from '~/client/util/apiv3-client';
-import { toastError } from '~/client/util/toastr';
 import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
 import { useDefaultSocket } from '~/stores/socket-io';
-import loggerFactory from '~/utils/logger';
 
 import InAppNotificationList from './InAppNotificationList';
 
-
-const logger = loggerFactory('growi:InAppNotificationDropdown');
-
-
 export const InAppNotificationDropdown = (): JSX.Element => {
   const { t } = useTranslation('commons');
 
@@ -36,16 +28,6 @@ export const InAppNotificationDropdown = (): JSX.Element => {
   const buttonRef = useRef(null);
   useRipple(buttonRef, { rippleColor: 'rgba(255, 255, 255, 0.3)' });
 
-  const updateNotificationStatus = async() => {
-    try {
-      await apiv3Post('/in-app-notification/read');
-    }
-    catch (err) {
-      toastError(err);
-      logger.error(err);
-    }
-  };
-
   useEffect(() => {
     if (socket != null) {
       socket.on('notificationUpdated', () => {
@@ -62,7 +44,6 @@ export const InAppNotificationDropdown = (): JSX.Element => {
 
   const toggleDropdownHandler = async() => {
     if (!isOpen && inAppNotificationUnreadStatusCount != null && inAppNotificationUnreadStatusCount > 0) {
-      await updateNotificationStatus();
       mutateInAppNotificationUnreadStatusCount();
     }
 

+ 7 - 2
apps/app/src/client/components/InAppNotification/InAppNotificationElm.tsx

@@ -1,10 +1,13 @@
-import React, { FC } from 'react';
+import type { FC } from 'react';
+import React from 'react';
 
 import type { HasObjectId } from '@growi/core';
 import { UserPicture } from '@growi/ui/dist/components';
 
 import { apiv3Post } from '~/client/util/apiv3-client';
-import { IInAppNotification, InAppNotificationStatuses } from '~/interfaces/in-app-notification';
+import type { IInAppNotification } from '~/interfaces/in-app-notification';
+import { InAppNotificationStatuses } from '~/interfaces/in-app-notification';
+import { useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
 
 import { useModelNotification } from './PageNotification';
 
@@ -21,6 +24,7 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
 
   const Notification = modelNotificationUtils?.Notification;
   const publishOpen = modelNotificationUtils?.publishOpen;
+  const { mutate: mutateNotificationCount } = useSWRxInAppNotificationStatus();
 
   if (Notification == null || publishOpen == null) {
     return <></>;
@@ -31,6 +35,7 @@ const InAppNotificationElm: FC<Props> = (props: Props) => {
       // set notification status "OPEND"
       await apiv3Post('/in-app-notification/open', { id: notification._id });
       onUnopenedNotificationOpend?.();
+      mutateNotificationCount();
     }
 
     publishOpen();

+ 4 - 22
apps/app/src/client/components/InAppNotification/InAppNotificationPage.tsx

@@ -1,46 +1,26 @@
 import type { FC } from 'react';
-import React, { useState, useEffect, useCallback } from 'react';
+import React, { useState } from 'react';
 
 import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
-import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
+import { apiv3Put } from '~/client/util/apiv3-client';
 import { InAppNotificationStatuses } from '~/interfaces/in-app-notification';
 import { useShowPageLimitationXL } from '~/stores-universal/context';
 import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
-import loggerFactory from '~/utils/logger';
 
 import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
 import PaginationWrapper from '../PaginationWrapper';
 
 import InAppNotificationList from './InAppNotificationList';
 
-
-const logger = loggerFactory('growi:InAppNotificationPage');
-
-
 export const InAppNotificationPage: FC = () => {
   const { t } = useTranslation('commons');
-  const { mutate } = useSWRxInAppNotificationStatus();
 
   const { data: showPageLimitationXL } = useShowPageLimitationXL();
 
   const limit = showPageLimitationXL != null ? showPageLimitationXL : 20;
 
-  const updateNotificationStatus = useCallback(async() => {
-    try {
-      await apiv3Post('/in-app-notification/read');
-      mutate();
-    }
-    catch (err) {
-      logger.error(err);
-    }
-  }, [mutate]);
-
-  useEffect(() => {
-    updateNotificationStatus();
-  }, [updateNotificationStatus]);
-
   const InAppNotificationCategoryByStatus = (status?: InAppNotificationStatuses) => {
     const [activePage, setActivePage] = useState(1);
     const offset = (activePage - 1) * limit;
@@ -56,6 +36,7 @@ export const InAppNotificationPage: FC = () => {
 
     const { data: notificationData, mutate: mutateNotificationData } = useSWRxInAppNotifications(limit, offset, categoryStatus);
     const { mutate: mutateAllNotificationData } = useSWRxInAppNotifications(limit, offset, undefined);
+    const { mutate: mutateNotificationCount } = useSWRxInAppNotificationStatus();
 
     const setAllNotificationPageNumber = (selectedPageNumber): void => {
       setActivePage(selectedPageNumber);
@@ -78,6 +59,7 @@ export const InAppNotificationPage: FC = () => {
       mutateNotificationData();
       // mutate notification statuses in 'ALL' Category
       mutateAllNotificationData();
+      mutateNotificationCount();
     };
 
 

+ 1 - 17
apps/app/src/client/components/Sidebar/InAppNotification/PrimaryItemForNotification.tsx

@@ -1,15 +1,11 @@
 import { memo, useCallback, useEffect } from 'react';
 
-import { apiv3Post } from '~/client/util/apiv3-client';
 import { SidebarContentsType } from '~/interfaces/ui';
 import { useSWRxInAppNotificationStatus } from '~/stores/in-app-notification';
 import { useDefaultSocket } from '~/stores/socket-io';
-import loggerFactory from '~/utils/logger';
 
 import { PrimaryItem, type Props } from '../SidebarNav/PrimaryItem';
 
-const logger = loggerFactory('growi:PrimaryItemsForNotification');
-
 type PrimaryItemForNotificationProps = Omit<Props, 'onClick' | 'label' | 'iconName' | 'contents' | 'badgeContents' >
 
 // TODO(after v7 release): https://redmine.weseek.co.jp/issues/138463
@@ -22,20 +18,9 @@ export const PrimaryItemForNotification = memo((props: PrimaryItemForNotificatio
 
   const badgeContents = notificationCount != null && notificationCount > 0 ? notificationCount : undefined;
 
-  const updateNotificationStatus = useCallback(async() => {
-    try {
-      await apiv3Post('/in-app-notification/read');
-      mutateNotificationCount();
-    }
-    catch (err) {
-      logger.error(err);
-    }
-  }, [mutateNotificationCount]);
-
   const itemHoverHandler = useCallback((contents: SidebarContentsType) => {
     onHover?.(contents);
-    updateNotificationStatus();
-  }, [onHover, updateNotificationStatus]);
+  }, [onHover]);
 
   useEffect(() => {
     if (socket != null) {
@@ -57,7 +42,6 @@ export const PrimaryItemForNotification = memo((props: PrimaryItemForNotificatio
       label="In-App Notification"
       iconName="notifications"
       badgeContents={badgeContents}
-      onClick={updateNotificationStatus}
       onHover={itemHoverHandler}
     />
   );

+ 1 - 2
apps/app/src/interfaces/in-app-notification.ts

@@ -1,9 +1,8 @@
 import type { IUser } from '@growi/core';
 
-import { SupportedTargetModelType, SupportedActionType } from './activity';
+import type { SupportedTargetModelType, SupportedActionType } from './activity';
 
 export enum InAppNotificationStatuses {
-  STATUS_UNREAD = 'UNREAD',
   STATUS_UNOPENED = 'UNOPENED',
   STATUS_OPENED = 'OPENED',
 }

+ 27 - 0
apps/app/src/migrations/20240924181317-changed-status-in-inappnotifications-from-unread-to-unopened.js

@@ -0,0 +1,27 @@
+import loggerFactory from '~/utils/logger';
+
+const logger = loggerFactory('growi:changed-status-in-inappnotifications-from-unread-to-unopened');
+
+module.exports = {
+  async up(db) {
+    logger.info('Apply migration');
+
+    const unreadInAppnotifications = await db.collection('inappnotifications');
+    await unreadInAppnotifications.updateMany(
+      { status: { $eq: 'UNREAD' } },
+      [
+        {
+          $set: {
+            status: 'UNOPENED',
+          },
+        },
+      ],
+    );
+
+    logger.info('Migration has successfully applied');
+  },
+
+  async down() {
+    // No rollback
+  },
+};

+ 2 - 6
apps/app/src/server/models/in-app-notification.ts

@@ -10,7 +10,7 @@ import { getOrCreateModel } from '../util/mongoose-utils';
 import type { ActivityDocument } from './activity';
 
 
-const { STATUS_UNREAD, STATUS_UNOPENED, STATUS_OPENED } = InAppNotificationStatuses;
+const { STATUS_UNOPENED, STATUS_OPENED } = InAppNotificationStatuses;
 
 export interface InAppNotificationDocument extends Document {
   _id: Types.ObjectId
@@ -31,7 +31,6 @@ export interface InAppNotificationModel extends Model<InAppNotificationDocument>
   open(user, id: Types.ObjectId): Promise<InAppNotificationDocument | null>
   read(user) /* : Promise<Query<any>> */
 
-  STATUS_UNREAD: string
   STATUS_UNOPENED: string
   STATUS_OPENED: string
 }
@@ -66,7 +65,7 @@ const inAppNotificationSchema = new Schema<InAppNotificationDocument, InAppNotif
   ],
   status: {
     type: String,
-    default: STATUS_UNREAD,
+    default: STATUS_UNOPENED,
     enum: InAppNotificationStatuses,
     index: true,
     required: true,
@@ -95,9 +94,6 @@ inAppNotificationSchema.index({
 inAppNotificationSchema.statics.STATUS_UNOPENED = function() {
   return STATUS_UNOPENED;
 };
-inAppNotificationSchema.statics.STATUS_UNREAD = function() {
-  return STATUS_UNREAD;
-};
 inAppNotificationSchema.statics.STATUS_OPENED = function() {
   return STATUS_OPENED;
 };

+ 0 - 12
apps/app/src/server/routes/apiv3/in-app-notification.ts

@@ -93,18 +93,6 @@ module.exports = (crowi) => {
     }
   });
 
-  router.post('/read', accessTokenParser, loginRequiredStrictly, async(req: CrowiRequest, res: ApiV3Response) => {
-    const user = req.user;
-
-    try {
-      await inAppNotificationService.read(user);
-      return res.apiv3();
-    }
-    catch (err) {
-      return res.apiv3Err(err);
-    }
-  });
-
   router.post('/open', accessTokenParser, loginRequiredStrictly, async(req: CrowiRequest, res: ApiV3Response) => {
     // user must be set by loginRequiredStrictly
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion

+ 3 - 11
apps/app/src/server/service/in-app-notification.ts

@@ -25,7 +25,7 @@ import { preNotifyService, type PreNotify } from './pre-notify';
 import { RoomPrefix, getRoomNameWithId } from './socket-io/helper';
 
 
-const { STATUS_UNREAD, STATUS_UNOPENED, STATUS_OPENED } = InAppNotificationStatuses;
+const { STATUS_UNOPENED, STATUS_OPENED } = InAppNotificationStatuses;
 
 const logger = loggerFactory('growi:service:inAppNotification');
 
@@ -93,7 +93,7 @@ export default class InAppNotificationService {
         targetModel,
         target,
         action,
-        status: STATUS_UNREAD,
+        status: STATUS_UNOPENED,
         createdAt: now,
         snapshot,
         $addToSet: { activities: activityId },
@@ -147,14 +147,6 @@ export default class InAppNotificationService {
     }
   };
 
-  read = async function(user: Types.ObjectId): Promise<void> {
-    const query = { user, status: STATUS_UNREAD };
-    const parameters = { status: STATUS_UNOPENED };
-    await InAppNotification.updateMany(query, parameters);
-
-    return;
-  };
-
   open = async function(user: IUser & HasObjectId, id: Types.ObjectId): Promise<void> {
     const query = { _id: id, user: user._id };
     const parameters = { status: STATUS_OPENED };
@@ -173,7 +165,7 @@ export default class InAppNotificationService {
   };
 
   getUnreadCountByUser = async function(user: Types.ObjectId): Promise<number| undefined> {
-    const query = { user, status: STATUS_UNREAD };
+    const query = { user, status: STATUS_UNOPENED };
 
     try {
       const count = await InAppNotification.countDocuments(query);