Преглед изворни кода

Merge pull request #4642 from weseek/imprv/80107-add-pagination-to-allInAppNotifications

Imprv/80107 add pagination to all in app notifications
Yuki Takei пре 4 година
родитељ
комит
9857d5c7f6

+ 33 - 4
packages/app/src/components/InAppNotification/AllInAppNotifications.tsx

@@ -1,15 +1,44 @@
-import React, { FC } from 'react';
+import React, { FC, useState } from 'react';
 
 import InAppNotificationList from './InAppNotificationList';
 import { useSWRxInAppNotifications } from '../../stores/in-app-notification';
+import PaginationWrapper from '../PaginationWrapper';
 
 
 const AllInAppNotifications: FC = () => {
-  const limit = 6;
-  const { data: inAppNotificationData } = useSWRxInAppNotifications(limit);
+  const [activePage, setActivePage] = useState(1);
+  const [offset, setOffset] = useState(0);
+  const limit = 10;
+  const { data: inAppNotificationData } = useSWRxInAppNotifications(limit, offset);
+
+  if (inAppNotificationData == null) {
+    return (
+      <div className="wiki">
+        <div className="text-muted text-center">
+          <i className="fa fa-2x fa-spinner fa-pulse mr-1"></i>
+        </div>
+      </div>
+    );
+  }
+
+  const setPageNumber = (selectedPageNumber): void => {
+    setActivePage(selectedPageNumber);
+    const offset = (selectedPageNumber - 1) * limit;
+    setOffset(offset);
+  };
 
   return (
-    <InAppNotificationList inAppNotificationData={inAppNotificationData} />
+    <>
+      <InAppNotificationList inAppNotificationData={inAppNotificationData} />
+      <PaginationWrapper
+        activePage={activePage}
+        changePage={setPageNumber}
+        totalItemsCount={inAppNotificationData.totalDocs}
+        pagingLimit={inAppNotificationData.limit}
+        align="center"
+        size="sm"
+      />
+    </>
   );
 };
 

+ 0 - 1
packages/app/src/components/InAppNotification/InAppNotificationDropdown.tsx

@@ -72,7 +72,6 @@ const InAppNotificationDropdown: FC<Props> = (props: Props) => {
 
   const badge = count > 0 ? <span className="badge badge-pill badge-danger grw-notification-badge">{count}</span> : '';
 
-
   return (
     <Dropdown className="notification-wrapper" isOpen={isOpen} toggle={toggleDropdownHandler}>
       <DropdownToggle tag="a">

+ 23 - 29
packages/app/src/components/PaginationWrapper.jsx → packages/app/src/components/PaginationWrapper.tsx

@@ -1,18 +1,21 @@
-import React, { useCallback, useMemo } from 'react';
-import PropTypes from 'prop-types';
+import React, {
+  FC, memo, useCallback, useMemo,
+} from 'react';
 
 import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
 
-/**
- *
- * @author Mikitaka Itizawa <itizawa@weseek.co.jp>
- *
- * @export
- * @class PaginationWrapper
- * @extends {React.Component}
- */
 
-const PaginationWrapper = React.memo((props) => {
+type Props = {
+  activePage: number,
+  changePage?: (number) => void,
+  totalItemsCount: number,
+  pagingLimit?: number,
+  align?: string,
+  size?: string,
+};
+
+
+const PaginationWrapper: FC<Props> = memo((props: Props) => {
   const {
     activePage, changePage, totalItemsCount, pagingLimit, align,
   } = props;
@@ -59,14 +62,14 @@ const PaginationWrapper = React.memo((props) => {
    * this function set << & <
    */
   const generateFirstPrev = useCallback(() => {
-    const paginationItems = [];
+    const paginationItems: JSX.Element[] = [];
     if (activePage !== 1) {
       paginationItems.push(
         <PaginationItem key="painationItemFirst">
-          <PaginationLink first onClick={() => { return changePage(1) }} />
+          <PaginationLink first onClick={() => { return changePage != null && changePage(1) }} />
         </PaginationItem>,
         <PaginationItem key="painationItemPrevious">
-          <PaginationLink previous onClick={() => { return changePage(activePage - 1) }} />
+          <PaginationLink previous onClick={() => { return changePage != null && changePage(activePage - 1) }} />
         </PaginationItem>,
       );
     }
@@ -89,11 +92,11 @@ const PaginationWrapper = React.memo((props) => {
    * this function set  numbers
    */
   const generatePaginations = useCallback(() => {
-    const paginationItems = [];
+    const paginationItems: JSX.Element[] = [];
     for (let number = paginationStart; number <= maxViewPageNum; number++) {
       paginationItems.push(
         <PaginationItem key={`paginationItem-${number}`} active={number === activePage}>
-          <PaginationLink onClick={() => { return changePage(number) }}>
+          <PaginationLink onClick={() => { return changePage != null && changePage(number) }}>
             {number}
           </PaginationLink>
         </PaginationItem>,
@@ -108,14 +111,14 @@ const PaginationWrapper = React.memo((props) => {
    * this function set > & >>
    */
   const generateNextLast = useCallback(() => {
-    const paginationItems = [];
+    const paginationItems: JSX.Element[] = [];
     if (totalPage !== activePage) {
       paginationItems.push(
         <PaginationItem key="painationItemNext">
-          <PaginationLink next onClick={() => { return changePage(activePage + 1) }} />
+          <PaginationLink next onClick={() => { return changePage != null && changePage(activePage + 1) }} />
         </PaginationItem>,
         <PaginationItem key="painationItemLast">
-          <PaginationLink last onClick={() => { return changePage(totalPage) }} />
+          <PaginationLink last onClick={() => { return changePage != null && changePage(totalPage) }} />
         </PaginationItem>,
       );
     }
@@ -133,7 +136,7 @@ const PaginationWrapper = React.memo((props) => {
   }, [activePage, changePage, totalPage]);
 
   const getListClassName = useMemo(() => {
-    const listClassNames = [];
+    const listClassNames: string[] = [];
 
     if (align === 'center') {
       listClassNames.push('justify-content-center');
@@ -157,15 +160,6 @@ const PaginationWrapper = React.memo((props) => {
 
 });
 
-PaginationWrapper.propTypes = {
-  activePage: PropTypes.number.isRequired,
-  changePage: PropTypes.func.isRequired,
-  totalItemsCount: PropTypes.number.isRequired,
-  pagingLimit: PropTypes.number,
-  align: PropTypes.string,
-  size: PropTypes.string,
-};
-
 PaginationWrapper.defaultProps = {
   align: 'left',
   size: 'md',

+ 1 - 5
packages/app/src/server/models/in-app-notification.ts

@@ -4,13 +4,9 @@ import {
 import mongoosePaginate from 'mongoose-paginate-v2';
 
 import { getOrCreateModel } from '@growi/core';
-import Activity, { ActivityDocument } from './activity';
+import { ActivityDocument } from './activity';
 import ActivityDefine from '../util/activityDefine';
 
-import loggerFactory from '../../utils/logger';
-
-const logger = loggerFactory('growi:models:inAppNotification');
-
 export const STATUS_UNREAD = 'UNREAD';
 export const STATUS_UNOPENED = 'UNOPENED';
 export const STATUS_OPENED = 'OPENED';

+ 7 - 6
packages/app/src/server/routes/apiv3/in-app-notification.ts

@@ -17,19 +17,20 @@ module.exports = (crowi) => {
   router.get('/list', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const user = req.user;
 
-    let limit = 10;
-    if (req.query.limit) {
-      limit = parseInt(req.query.limit, 10);
-    }
+    const limit = parseInt(req.query.limit) || 10;
 
     let offset = 0;
     if (req.query.offset) {
       offset = parseInt(req.query.offset, 10);
     }
 
-    const requestLimit = limit + 1;
+    const queryOptions = {
+      offset,
+      limit,
+    };
+
 
-    const paginationResult = await inAppNotificationService.getLatestNotificationsByUser(user._id, requestLimit, offset);
+    const paginationResult = await inAppNotificationService.getLatestNotificationsByUser(user._id, queryOptions);
 
 
     const getActionUsersFromActivities = function(activities) {

+ 9 - 3
packages/app/src/server/service/in-app-notification.ts

@@ -1,9 +1,11 @@
-import { Types } from 'mongoose';
+import { Types, PaginateResult } from 'mongoose';
 import { subDays } from 'date-fns';
 import Crowi from '../crowi';
 import {
   InAppNotification, STATUS_UNREAD, STATUS_UNOPENED, STATUS_OPENED,
+  InAppNotificationDocument,
 } from '~/server/models/in-app-notification';
+
 import { ActivityDocument } from '~/server/models/activity';
 import InAppNotificationSettings from '~/server/models/in-app-notification-settings';
 import Subscription, { STATUS_SUBSCRIBE } from '~/server/models/subscription';
@@ -81,15 +83,19 @@ export default class InAppNotificationService {
     return;
   }
 
-  getLatestNotificationsByUser = async(userId, limitNum, offset) => {
+  getLatestNotificationsByUser = async(
+      userId: Types.ObjectId,
+      queryOptions: {offset: number, limit: number},
+  ): Promise<PaginateResult<InAppNotificationDocument>> => {
+    const { limit, offset } = queryOptions;
 
     try {
       const paginationResult = await InAppNotification.paginate(
         { user: userId },
         {
           sort: { createdAt: -1 },
+          limit,
           offset,
-          limit: limitNum || 10,
           populate: [
             { path: 'user' },
             { path: 'target' },

+ 3 - 3
packages/app/src/stores/in-app-notification.ts

@@ -7,11 +7,11 @@ import { IInAppNotification } from '../interfaces/in-app-notification';
 
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
 export const useSWRxInAppNotifications = <Data, Error>(
-  // TODO: apply pagination by 80107
   limit: number,
+  offset?: number,
 ): SWRResponse<PaginateResult<IInAppNotification>, Error> => {
   return useSWR(
-    '/in-app-notification/list',
-    endpoint => apiv3Get(endpoint, { limit }).then(response => response.data),
+    ['/in-app-notification/list', limit, offset],
+    endpoint => apiv3Get(endpoint, { limit, offset }).then(response => response.data),
   );
 };