Просмотр исходного кода

Merge pull request #6520 from weseek/feat/103609-rendering-all-in-app-notifications

feat: Rendering all in app notifications
Shun Miyazawa 3 лет назад
Родитель
Сommit
b8ad0c76b6

+ 15 - 21
packages/app/src/components/InAppNotification/InAppNotificationPage.tsx

@@ -3,31 +3,30 @@ import React, {
 } from 'react';
 } from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
-import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../UnstatedUtils';
-import InAppNotificationList from './InAppNotificationList';
+
+import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
+import { InAppNotificationStatuses } from '~/interfaces/in-app-notification';
+import { useShowPageLimitationXL } from '~/stores/context';
+import loggerFactory from '~/utils/logger';
+
 import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '../../stores/in-app-notification';
 import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '../../stores/in-app-notification';
-import PaginationWrapper from '../PaginationWrapper';
 import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
 import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
-import { InAppNotificationStatuses } from '~/interfaces/in-app-notification';
-import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
+import PaginationWrapper from '../PaginationWrapper';
 
 
-import loggerFactory from '~/utils/logger';
+import InAppNotificationList from './InAppNotificationList';
 
 
-const logger = loggerFactory('growi:InAppNotificationPage');
 
 
+const logger = loggerFactory('growi:InAppNotificationPage');
 
 
-type Props = {
-  appContainer: AppContainer
-}
 
 
-const InAppNotificationPageBody: FC<Props> = (props) => {
-  const { appContainer } = props;
-  const limit = appContainer.config.pageLimitationXL;
+export const InAppNotificationPage: FC = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const { mutate } = useSWRxInAppNotificationStatus();
   const { mutate } = useSWRxInAppNotificationStatus();
 
 
+  const { data: showPageLimitationXL } = useShowPageLimitationXL();
+
+  const limit = showPageLimitationXL != null ? showPageLimitationXL : 20;
+
   const updateNotificationStatus = useCallback(async() => {
   const updateNotificationStatus = useCallback(async() => {
     try {
     try {
       await apiv3Post('/in-app-notification/read');
       await apiv3Post('/in-app-notification/read');
@@ -143,9 +142,4 @@ const InAppNotificationPageBody: FC<Props> = (props) => {
   );
   );
 };
 };
 
 
-const InAppNotificationPage = withUnstatedContainers(InAppNotificationPageBody, [AppContainer]);
-export default InAppNotificationPage;
-
-InAppNotificationPageBody.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-};
+InAppNotificationPage.displayName = 'InAppNotificationPage';

+ 52 - 17
packages/app/src/pages/me.page.tsx → packages/app/src/pages/me/[[...path]].page.tsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useMemo } from 'react';
 
 
 import {
 import {
   IUser, IUserHasId,
   IUser, IUserHasId,
@@ -12,27 +12,25 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
 
 
+import { BasicLayout } from '~/components/Layout/BasicLayout';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { ISidebarConfig } from '~/interfaces/sidebar-config';
 import { ISidebarConfig } from '~/interfaces/sidebar-config';
 import { IUserUISettings } from '~/interfaces/user-ui-settings';
 import { IUserUISettings } from '~/interfaces/user-ui-settings';
 import { UserUISettingsModel } from '~/server/models/user-ui-settings';
 import { UserUISettingsModel } from '~/server/models/user-ui-settings';
-import {
-  usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed, useCurrentSidebarContents, useCurrentProductNavWidth,
-} from '~/stores/ui';
-import loggerFactory from '~/utils/logger';
-
-
-import { BasicLayout } from '../components/Layout/BasicLayout';
 import {
 import {
   useCurrentUser,
   useCurrentUser,
   useIsSearchServiceConfigured, useIsSearchServiceReachable,
   useIsSearchServiceConfigured, useIsSearchServiceReachable,
   useCsrfToken, useIsSearchScopeChildrenAsDefault,
   useCsrfToken, useIsSearchScopeChildrenAsDefault,
-  useRegistrationWhiteList,
-} from '../stores/context';
+  useRegistrationWhiteList, useShowPageLimitationXL,
+} from '~/stores/context';
+import {
+  usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed, useCurrentSidebarContents, useCurrentProductNavWidth,
+} from '~/stores/ui';
+import loggerFactory from '~/utils/logger';
 
 
 import {
 import {
   CommonProps, getNextI18NextConfig, getServerSideCommonProps, useCustomTitle,
   CommonProps, getNextI18NextConfig, getServerSideCommonProps, useCustomTitle,
-} from './utils/commons';
+} from '../utils/commons';
 
 
 
 
 const logger = loggerFactory('growi:pages:me');
 const logger = loggerFactory('growi:pages:me');
@@ -44,16 +42,55 @@ type Props = CommonProps & {
   isSearchScopeChildrenAsDefault: boolean,
   isSearchScopeChildrenAsDefault: boolean,
   userUISettings?: IUserUISettings
   userUISettings?: IUserUISettings
   sidebarConfig: ISidebarConfig,
   sidebarConfig: ISidebarConfig,
+  showPageLimitationXL: number,
 
 
   // config
   // config
   registrationWhiteList: string[],
   registrationWhiteList: string[],
 };
 };
 
 
+const PersonalSettings = dynamic(() => import('~/components/Me/PersonalSettings'), { ssr: false });
+const MyDraftList = dynamic(() => import('~/components/MyDraftList/MyDraftList'), { ssr: false });
+const InAppNotificationPage = dynamic(
+  () => import('~/components/InAppNotification/InAppNotificationPage').then(mod => mod.InAppNotificationPage), { ssr: false },
+);
+
 const MePage: NextPage<Props> = (props: Props) => {
 const MePage: NextPage<Props> = (props: Props) => {
+  const router = useRouter();
+  const { t } = useTranslation();
+  const { path } = router.query;
+  const pagePathKeys: string[] = Array.isArray(path) ? path : ['personal-settings'];
+
+  const mePagesMap = useMemo(() => {
+    return {
+      'personal-settings': {
+        title: t('User Settings'),
+        component: <PersonalSettings />,
+      },
+      drafts: {
+        title: t('My Drafts'),
+        component: <MyDraftList />,
+      },
+      'all-in-app-notifications': {
+        title: t('in_app_notification.notification_list'),
+        component: <InAppNotificationPage />,
+      },
+    };
+  }, [t]);
+
+  const getTargetPageToRender = (pagesMap, keys): {title: string, component: JSX.Element} => {
+    return keys.reduce((pagesMap, key) => {
+      return pagesMap[key];
+    }, pagesMap);
+  };
+
+  const targetPage = getTargetPageToRender(mePagesMap, pagePathKeys);
+
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
   useRegistrationWhiteList(props.registrationWhiteList);
   useRegistrationWhiteList(props.registrationWhiteList);
 
 
+  useShowPageLimitationXL(props.showPageLimitationXL);
+
   // commons
   // commons
   useCsrfToken(props.csrfToken);
   useCsrfToken(props.csrfToken);
 
 
@@ -68,9 +105,6 @@ const MePage: NextPage<Props> = (props: Props) => {
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
-  const { t } = useTranslation();
-
-  const PersonalSettings = dynamic(() => import('~/components/Me/PersonalSettings'), { ssr: false });
 
 
   return (
   return (
     <>
     <>
@@ -78,7 +112,7 @@ const MePage: NextPage<Props> = (props: Props) => {
 
 
         <header className="py-3">
         <header className="py-3">
           <div className="container-fluid">
           <div className="container-fluid">
-            <h1 className="title">{t('User Settings')}</h1>
+            <h1 className="title">{ targetPage.title }</h1>
           </div>
           </div>
         </header>
         </header>
 
 
@@ -86,7 +120,7 @@ const MePage: NextPage<Props> = (props: Props) => {
 
 
         <div id="main" className='main'>
         <div id="main" className='main'>
           <div id="content-main" className="content-main grw-container-convertible">
           <div id="content-main" className="content-main grw-container-convertible">
-            <PersonalSettings />
+            {targetPage.component}
           </div>
           </div>
         </div>
         </div>
 
 
@@ -120,6 +154,8 @@ async function injectServerConfigurations(context: GetServerSidePropsContext, pr
 
 
   props.registrationWhiteList = configManager.getConfig('crowi', 'security:registrationWhiteList');
   props.registrationWhiteList = configManager.getConfig('crowi', 'security:registrationWhiteList');
 
 
+  props.showPageLimitationXL = crowi.configManager.getConfig('crowi', 'customize:showPageLimitationXL');
+
   props.sidebarConfig = {
   props.sidebarConfig = {
     isSidebarDrawerMode: configManager.getConfig('crowi', 'customize:isSidebarDrawerMode'),
     isSidebarDrawerMode: configManager.getConfig('crowi', 'customize:isSidebarDrawerMode'),
     isSidebarClosedAtDockMode: configManager.getConfig('crowi', 'customize:isSidebarClosedAtDockMode'),
     isSidebarClosedAtDockMode: configManager.getConfig('crowi', 'customize:isSidebarClosedAtDockMode'),
@@ -143,7 +179,6 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
 
 
   const result = await getServerSideCommonProps(context);
   const result = await getServerSideCommonProps(context);
 
 
-
   // check for presence
   // check for presence
   // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
   // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
   if (!('props' in result)) {
   if (!('props' in result)) {

+ 5 - 5
packages/app/src/server/routes/index.js

@@ -207,13 +207,13 @@ module.exports = function(crowi, app) {
   // app.get('/tags'                     , loginRequired, tag.showPage);
   // app.get('/tags'                     , loginRequired, tag.showPage);
   app.get('/tags', loginRequired, next.delegateToNext);
   app.get('/tags', loginRequired, next.delegateToNext);
 
 
-  app.get('/me'                                 , loginRequiredStrictly, injectUserUISettings, next.delegateToNext);
+  app.get('/me/*'                                 , loginRequiredStrictly, injectUserUISettings, next.delegateToNext);
   // external-accounts
   // external-accounts
   // my in-app-notifications
   // my in-app-notifications
-  app.get('/me/all-in-app-notifications'   , loginRequiredStrictly, allInAppNotifications.list);
-  app.get('/me/external-accounts'               , loginRequiredStrictly, injectUserUISettings, me.externalAccounts.list);
-  // my drafts
-  app.get('/me/drafts'                          , loginRequiredStrictly, injectUserUISettings, me.drafts.list);
+  // app.get('/me/all-in-app-notifications'   , loginRequiredStrictly, allInAppNotifications.list);
+  // app.get('/me/external-accounts'               , loginRequiredStrictly, injectUserUISettings, me.externalAccounts.list);
+  // // my drafts
+  // app.get('/me/drafts'                          , loginRequiredStrictly, injectUserUISettings, me.drafts.list);
 
 
   app.get('/attachment/:id([0-9a-z]{24})' , certifySharedFile , loginRequired, attachment.api.get);
   app.get('/attachment/:id([0-9a-z]{24})' , certifySharedFile , loginRequired, attachment.api.get);
   app.get('/attachment/profile/:id([0-9a-z]{24})' , loginRequired, attachment.api.get);
   app.get('/attachment/profile/:id([0-9a-z]{24})' , loginRequired, attachment.api.get);

+ 4 - 0
packages/app/src/stores/context.tsx

@@ -255,6 +255,10 @@ export const useIsUploadableFile = (initialData?: boolean): SWRResponse<boolean,
   return useStaticSWR('isUploadableFile', initialData);
   return useStaticSWR('isUploadableFile', initialData);
 };
 };
 
 
+export const useShowPageLimitationXL = (initialData?: number): SWRResponse<number, Error> => {
+  return useStaticSWR('showPageLimitationXL', initialData);
+};
+
 /** **********************************************************
 /** **********************************************************
  *                     Computed contexts
  *                     Computed contexts
  *********************************************************** */
  *********************************************************** */