Browse Source

Merge pull request #4444 from weseek/feat/77832-get-subscription-on-client-side

Feat/77832 get subscription on client side
Yuki Takei 4 years ago
parent
commit
6c622c7f15

+ 24 - 26
packages/app/src/components/Navbar/SubNavButtons.jsx

@@ -10,34 +10,32 @@ import LikeButton from '../LikeButton';
 import SubscribeButton from '../SubscribeButton';
 import SubscribeButton from '../SubscribeButton';
 import PageManagement from '../Page/PageManagement';
 import PageManagement from '../Page/PageManagement';
 
 
-const SubnavButtons = (props) => {
-  const {
-    appContainer, navigationContainer, pageContainer, isCompactMode,
-  } = props;
-
-  /* eslint-enable react/prop-types */
-
-  /* eslint-disable react/prop-types */
-  const PageReactionButtons = ({ pageContainer }) => {
-
-    return (
-      <>
-        <span>
-          <SubscribeButton pageId={pageContainer.state.pageId} />
-        </span>
-        {pageContainer.isAbleToShowLikeButton && (
-          <span>
-            <LikeButton />
-          </span>
-        )}
+/* eslint-disable react/prop-types */
+const PageReactionButtons = ({ pageContainer }) => {
+  return (
+    <>
+      <span>
+        <SubscribeButton pageId={pageContainer.state.pageId} />
+      </span>
+      {pageContainer.isAbleToShowLikeButton && (
         <span>
         <span>
-          <BookmarkButton />
+          <LikeButton />
         </span>
         </span>
+      )}
+      <span>
+        <BookmarkButton />
+      </span>
+
+    </>
+  );
+};
+/* eslint-disable react/prop-types */
 
 
-      </>
-    );
-  };
-  /* eslint-enable react/prop-types */
+
+const SubnavButtons = (props) => {
+  const {
+    navigationContainer, pageContainer, isCompactMode,
+  } = props;
 
 
   const { editorMode } = navigationContainer.state;
   const { editorMode } = navigationContainer.state;
   const isViewMode = editorMode === 'view';
   const isViewMode = editorMode === 'view';
@@ -46,7 +44,7 @@ const SubnavButtons = (props) => {
     <>
     <>
       {isViewMode && (
       {isViewMode && (
         <>
         <>
-          { pageContainer.isAbleToShowPageReactionButtons && <PageReactionButtons appContainer={appContainer} pageContainer={pageContainer} /> }
+          { pageContainer.isAbleToShowPageReactionButtons && <PageReactionButtons pageContainer={pageContainer} /> }
           { pageContainer.isAbleToShowPageManagement && <PageManagement isCompactMode={isCompactMode} /> }
           { pageContainer.isAbleToShowPageManagement && <PageManagement isCompactMode={isCompactMode} /> }
         </>
         </>
       )}
       )}

+ 36 - 7
packages/app/src/components/SubscribeButton.tsx

@@ -1,4 +1,6 @@
-import React, { useState, FC } from 'react';
+import React, {
+  FC, useState, useCallback, useEffect,
+} from 'react';
 
 
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
 import { UncontrolledTooltip } from 'reactstrap';
@@ -13,11 +15,14 @@ type Props = {
   pageId: string,
   pageId: string,
 };
 };
 
 
-const SubscruibeButton: FC<Props> = (props: Props) => {
+const SubscribeButton: FC<Props> = (props: Props) => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
   const { appContainer, pageId } = props;
   const { appContainer, pageId } = props;
-  const [isSubscribing, setIsSubscribing] = useState(false);
+  const [isSubscribing, setIsSubscribing] = useState<boolean | null>(null);
+
+  const buttonClass = `${isSubscribing ? 'active' : ''} ${appContainer.isGuestUser ? 'disabled' : ''}`;
+  const iconClass = isSubscribing || isSubscribing == null ? 'fa fa-eye' : 'fa fa-eye-slash';
 
 
   const handleClick = async() => {
   const handleClick = async() => {
     if (appContainer.isGuestUser) {
     if (appContainer.isGuestUser) {
@@ -36,15 +41,39 @@ const SubscruibeButton: FC<Props> = (props: Props) => {
     }
     }
   };
   };
 
 
+  const fetchSubscriptionStatus = useCallback(async() => {
+    if (appContainer.isGuestUser) {
+      return;
+    }
+
+    try {
+      const res = await appContainer.apiv3Get('page/subscribe', { pageId });
+      const { subscribing } = res.data;
+      if (subscribing == null) {
+        setIsSubscribing(null);
+      }
+      else {
+        setIsSubscribing(subscribing);
+      }
+    }
+    catch (err) {
+      toastError(err);
+    }
+  }, [appContainer, pageId]);
+
+  useEffect(() => {
+    fetchSubscriptionStatus();
+  }, [fetchSubscriptionStatus]);
+
   return (
   return (
     <>
     <>
       <button
       <button
         type="button"
         type="button"
         id="subscribe-button"
         id="subscribe-button"
         onClick={handleClick}
         onClick={handleClick}
-        className={`btn btn-subscribe border-0 ${isSubscribing ? 'active' : ''}  ${appContainer.isGuestUser ? 'disabled' : ''}`}
+        className={`btn btn-subscribe border-0 ${buttonClass}`}
       >
       >
-        <i className={isSubscribing ? 'fa fa-eye' : 'fa fa-eye-slash'}></i>
+        <i className={iconClass}></i>
       </button>
       </button>
 
 
       {appContainer.isGuestUser && (
       {appContainer.isGuestUser && (
@@ -60,5 +89,5 @@ const SubscruibeButton: FC<Props> = (props: Props) => {
 /**
 /**
  * Wrapper component for using unstated
  * Wrapper component for using unstated
  */
  */
-const SubscruibeButtonWrapper = withUnstatedContainers(SubscruibeButton, [AppContainer, PageContainer]);
-export default SubscruibeButtonWrapper;
+const SubscribeButtonWrapper = withUnstatedContainers(SubscribeButton, [AppContainer, PageContainer]);
+export default SubscribeButtonWrapper;

+ 50 - 3
packages/app/src/server/routes/apiv3/page.js

@@ -166,6 +166,9 @@ module.exports = (crowi) => {
       body('pageId').isString(),
       body('pageId').isString(),
       body('status').isBoolean(),
       body('status').isBoolean(),
     ],
     ],
+    subscribeStatus: [
+      query('pageId').isString(),
+    ],
   };
   };
 
 
   /**
   /**
@@ -475,8 +478,8 @@ module.exports = (crowi) => {
    *      put:
    *      put:
    *        tags: [Page]
    *        tags: [Page]
    *        summary: /page/subscribe
    *        summary: /page/subscribe
-   *        description: Update subscribe status
-   *        operationId: updateSubscribeStatus
+   *        description: Update subscription status
+   *        operationId: updateSubscriptionStatus
    *        requestBody:
    *        requestBody:
    *          content:
    *          content:
    *            application/json:
    *            application/json:
@@ -486,7 +489,7 @@ module.exports = (crowi) => {
    *                    $ref: '#/components/schemas/Page/properties/_id'
    *                    $ref: '#/components/schemas/Page/properties/_id'
    *        responses:
    *        responses:
    *          200:
    *          200:
-   *            description: Succeeded to update subscribe status.
+   *            description: Succeeded to update subscription status.
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
@@ -508,5 +511,49 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /page/subscribe:
+   *      get:
+   *        tags: [Page]
+   *        summary: /page/subscribe
+   *        description: Get subscription status
+   *        operationId: getSubscriptionStatus
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  pageId:
+   *                    $ref: '#/components/schemas/Page/properties/_id'
+   *        responses:
+   *          200:
+   *            description: Succeeded to get subscription status.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/Page'
+   *          500:
+   *            description: Internal server error.
+   */
+  router.get('/subscribe', loginRequiredStrictly, validator.subscribeStatus, apiV3FormValidator, async(req, res) => {
+    const { pageId } = req.query;
+    const userId = req.user._id;
+
+    const page = await Page.findById(pageId);
+    if (!page) throw new Error('Page not found');
+
+    try {
+      const subscription = await Subscription.findByUserIdAndTargetId(userId, pageId);
+      const subscribing = subscription ? subscription.isSubscribing() : null;
+      return res.apiv3({ subscribing });
+    }
+    catch (err) {
+      logger.error('Failed to ge subscribe status', err);
+      return res.apiv3(err, 500);
+    }
+  });
+
   return router;
   return router;
 };
 };