This is an automated email from the ASF dual-hosted git repository.

linkinstar pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 31a6fc9c367e755a282f8369d4986c640e87150f
Author: hgaol <[email protected]>
AuthorDate: Thu May 9 23:07:17 2024 +0800

    convert tooltip in backend and refactored the ReactionResp structure
---
 i18n/en_US.yaml                                    | 22 +++++---
 i18n/zh_CN.yaml                                    | 11 ++--
 .../meta_schema.go => base/constant/meta.go}       | 23 ++-------
 internal/controller/meta_controller.go             |  3 +-
 internal/schema/meta_schema.go                     | 13 +++--
 internal/service/meta/meta_service.go              | 55 ++++++++++++++------
 .../service/meta_common/meta_common_service.go     |  2 +-
 ui/src/common/interface.ts                         |  8 ++-
 .../Detail/components/Reactions/index.tsx          | 59 +++++++++++-----------
 9 files changed, 114 insertions(+), 82 deletions(-)

diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 6442818d..25f3ad04 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -18,7 +18,6 @@
 # The following fields are used for back-end
 
 backend:
-
   base:
     success:
       other: Success.
@@ -202,6 +201,9 @@ backend:
         other: The old password verification failed
       new_password_same_as_previous_setting:
         other: The new password is the same as the previous one.
+    meta:
+      object_not_found:
+        other: Meta object not found
     question:
       already_deleted:
         other: This post has been deleted.
@@ -314,7 +316,8 @@ backend:
       name:
         other: rude or abusive
       desc:
-        other: A reasonable person would find this content inappropriate for 
respectful
+        other:
+          A reasonable person would find this content inappropriate for 
respectful
           discourse.
     a_duplicate:
       name:
@@ -327,7 +330,8 @@ backend:
       name:
         other: not an answer
       desc:
-        other: This was posted as an answer, but it does not attempt to answer 
the
+        other:
+          This was posted as an answer, but it does not attempt to answer the
           question. It should possibly be an edit, a comment, another question,
           or deleted altogether.
     no_longer_needed:
@@ -388,7 +392,8 @@ backend:
         name:
           other: needs details or clarity
         desc:
-          other: This question currently includes multiple questions in one. 
It should
+          other:
+            This question currently includes multiple questions in one. It 
should
             focus on one problem only.
       other:
         name:
@@ -505,6 +510,9 @@ backend:
       other: Flagged post
     suggested_post_edit:
       other: Suggested edits
+  reaction:
+    tooltip:
+      other: "{{ .Names }} and {{ .Count }} more..."
 
 # The following fields are used for interface presentation(Front-end)
 ui:
@@ -769,7 +777,6 @@ ui:
     heart: heart
     smile: smile
     frown: frown
-    tooltip: " and {{count}} more..."
   comment:
     btn_add_comment: Add comment
     reply_to: Reply to
@@ -1446,7 +1453,6 @@ ui:
     qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log 
in.
     login_failed_email_tip: Login failed, please allow this app to access your 
email information before try again.
 
-
   admin:
     admin_header:
       title: Admin
@@ -1827,7 +1833,7 @@ ui:
         text: Choose the reputation required for the privileges
       msg:
         should_be_number: the input should be number
-        number_larger_1 : number should be equal or larger than 1
+        number_larger_1: number should be equal or larger than 1
 
   form:
     optional: (optional)
@@ -1911,7 +1917,7 @@ ui:
     post_deleted: This post has been deleted.
     post_pin: This post has been pinned.
     post_unpin: This post has been unpinned.
-    post_hide_list:  This post has been hidden from list.
+    post_hide_list: This post has been hidden from list.
     post_show_list: This post has been shown to list.
     post_reopen: This post has been reopened.
     post_list: This post has been listed.
diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml
index 56db05c2..9abddc22 100644
--- a/i18n/zh_CN.yaml
+++ b/i18n/zh_CN.yaml
@@ -200,6 +200,9 @@ backend:
         other: 旧密码验证失败。
       new_password_same_as_previous_setting:
         other: 新密码和旧密码相同。
+    meta:
+      object_not_found:
+        other: Meta 对象未找到
     question:
       already_deleted:
         other: 该帖子已被删除。
@@ -499,6 +502,9 @@ backend:
       other: 举报的帖子
     suggested_post_edit:
       other: 建议的编辑
+  reaction:
+    tooltip:
+      other: "{{ .Names }} 以及另外 {{ .Count }} 个..."
 # The following fields are used for interface presentation(Front-end)
 ui:
   how_to_format:
@@ -751,7 +757,6 @@ ui:
     heart: 爱心
     smile: 笑脸
     frown: 难过
-    tooltip: " 以及另外 {{count}} 个..."
   comment:
     btn_add_comment: 添加评论
     reply_to: 回复
@@ -1797,7 +1802,7 @@ ui:
     proposed: 提案
     question_edit: 问题编辑
     answer_edit: 回答编辑
-    tag_edit: '标签管理: 编辑标签'
+    tag_edit: "标签管理: 编辑标签"
     edit_summary: 编辑备注
     edit_question: 编辑问题
     edit_answer: 编辑回答
@@ -1826,7 +1831,7 @@ ui:
     upvote: 点赞
     accept: 采纳
     cancelled: 已取消
-    commented: '评论:'
+    commented: "评论:"
     rollback: 回滚
     edited: 最后编辑于
     answered: 回答于
diff --git a/internal/schema/meta_schema.go b/internal/base/constant/meta.go
similarity index 55%
copy from internal/schema/meta_schema.go
copy to internal/base/constant/meta.go
index 0774aca2..820572d7 100644
--- a/internal/schema/meta_schema.go
+++ b/internal/base/constant/meta.go
@@ -17,23 +17,8 @@
  * under the License.
  */
 
-package schema
+package constant
 
-type UpdateReactionReq struct {
-       ObjectID string `validate:"required" json:"object_id"`
-       Emoji    string `validate:"required,oneof=heart smile frown" 
json:"emoji"`
-       Reaction string `validate:"required,oneof=activate deactivate" 
json:"reaction"`
-       UserID   string `json:"-"`
-}
-
-type GetReactionReq struct {
-       ObjectID string `validate:"required" form:"object_id"`
-}
-
-type ReactSummaryMeta map[string][]string
-
-type ReactionResp struct {
-       // reaction summary is a map, key is emoji, value is username list
-       // such as {"heart": ["jack", "tom"], "smile": ["andy"], "frown": 
["bob"]}
-       ReactionSummary ReactSummaryMeta `json:"reaction_summary"`
-}
+const (
+       ReactionTooltipLabel = "reaction.tooltip"
+)
diff --git a/internal/controller/meta_controller.go 
b/internal/controller/meta_controller.go
index 2a9ab866..b8cef085 100644
--- a/internal/controller/meta_controller.go
+++ b/internal/controller/meta_controller.go
@@ -75,7 +75,8 @@ func (mc *MetaController) GetReaction(ctx *gin.Context) {
        if handler.BindAndCheck(ctx, req) {
                return
        }
+       req.UserID = middleware.GetLoginUserIDFromContext(ctx)
 
-       resp, err := mc.metaService.GetReactionByObjectId(ctx, req.ObjectID)
+       resp, err := mc.metaService.GetReactionByObjectId(ctx, req)
        handler.HandleResponse(ctx, err, resp)
 }
diff --git a/internal/schema/meta_schema.go b/internal/schema/meta_schema.go
index 0774aca2..d5fa46ff 100644
--- a/internal/schema/meta_schema.go
+++ b/internal/schema/meta_schema.go
@@ -28,12 +28,17 @@ type UpdateReactionReq struct {
 
 type GetReactionReq struct {
        ObjectID string `validate:"required" form:"object_id"`
+       UserID   string `json:"-"`
 }
 
-type ReactSummaryMeta map[string][]string
+type ReactionSummaryMeta map[string][]string
+
+type ReactionItem struct {
+       Count    int    `json:"count"`
+       Tooltip  string `json:"tooltip"`
+       IsActive bool   `json:"is_active"`
+}
 
 type ReactionResp struct {
-       // reaction summary is a map, key is emoji, value is username list
-       // such as {"heart": ["jack", "tom"], "smile": ["andy"], "frown": 
["bob"]}
-       ReactionSummary ReactSummaryMeta `json:"reaction_summary"`
+       ReactionSummary map[string]*ReactionItem `json:"reaction_summary"`
 }
diff --git a/internal/service/meta/meta_service.go 
b/internal/service/meta/meta_service.go
index a22e0237..33129015 100644
--- a/internal/service/meta/meta_service.go
+++ b/internal/service/meta/meta_service.go
@@ -23,9 +23,13 @@ import (
        "context"
        "encoding/json"
        "errors"
+       "strconv"
+       "strings"
 
        "github.com/apache/incubator-answer/internal/base/constant"
+       "github.com/apache/incubator-answer/internal/base/handler"
        "github.com/apache/incubator-answer/internal/base/reason"
+       "github.com/apache/incubator-answer/internal/base/translator"
        "github.com/apache/incubator-answer/internal/entity"
        "github.com/apache/incubator-answer/internal/schema"
        answercommon 
"github.com/apache/incubator-answer/internal/service/answer_common"
@@ -54,26 +58,25 @@ func NewMetaService(metaCommonService 
*metacommon.MetaCommonService, userCommon
 }
 
 // GetReactionByObjectId get reaction
-func (ms *MetaService) GetReactionByObjectId(ctx context.Context, objectID 
string) (resp *schema.ReactionResp, err error) {
-       resp = &schema.ReactionResp{}
-       reactionMeta, err := ms.metaCommonService.GetMetaByObjectIdAndKey(ctx, 
objectID, entity.ObjectReactSummaryKey)
+func (ms *MetaService) GetReactionByObjectId(ctx context.Context, req 
*schema.GetReactionReq) (resp *schema.ReactionResp, err error) {
+       reactionMeta, err := ms.metaCommonService.GetMetaByObjectIdAndKey(ctx, 
req.ObjectID, entity.ObjectReactSummaryKey)
 
        // if not exist, return nil
        if err != nil {
                var pacmanErr *myErrors.Error
                if errors.As(err, &pacmanErr) && pacmanErr.Reason == 
reason.MetaObjectNotFound {
-                       return resp, nil
+                       return nil, nil
                } else {
-                       return resp, err
+                       return nil, err
                }
        }
 
-       var reaction schema.ReactSummaryMeta
+       var reaction schema.ReactionSummaryMeta
        err = json.Unmarshal([]byte(reactionMeta.Value), &reaction)
        if err != nil {
-               return resp, err
+               return nil, err
        }
-       return ms.convertToReactionResp(ctx, reaction)
+       return ms.convertToReactionResp(ctx, req.UserID, reaction)
 }
 
 // AddOrUpdateReaction add or update reaction
@@ -104,11 +107,11 @@ func (ms *MetaService) AddOrUpdateReaction(ctx 
context.Context, req *schema.Upda
        }
 
        // add or update
-       var reaction schema.ReactSummaryMeta
+       var reaction schema.ReactionSummaryMeta
        err = ms.metaCommonService.AddOrUpdateMetaByObjectIdAndKey(ctx, 
req.ObjectID, entity.ObjectReactSummaryKey, func(meta *entity.Meta, exist bool) 
(*entity.Meta, error) {
                // if not exist, create new one
                if !exist {
-                       reaction = schema.ReactSummaryMeta{}
+                       reaction = schema.ReactionSummaryMeta{}
                } else {
                        err = json.Unmarshal([]byte(meta.Value), &reaction)
                        if err != nil {
@@ -136,7 +139,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx 
context.Context, req *schema.Upda
                return nil, 
myErrors.InternalServer(reason.DatabaseError).WithError(err)
        }
 
-       resp, err = ms.convertToReactionResp(ctx, reaction)
+       resp, err = ms.convertToReactionResp(ctx, req.UserID, reaction)
        if err != nil {
                return nil, err
        }
@@ -145,7 +148,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx 
context.Context, req *schema.Upda
 }
 
 // updateReaction update reaction
-func (ms *MetaService) updateReaction(req *schema.UpdateReactionReq, reaction 
schema.ReactSummaryMeta) {
+func (ms *MetaService) updateReaction(req *schema.UpdateReactionReq, reaction 
schema.ReactionSummaryMeta) {
        emojiUserIds, ok := reaction[req.Emoji]
 
        if !ok {
@@ -181,12 +184,25 @@ func (ms *MetaService) updateReaction(req 
*schema.UpdateReactionReq, reaction sc
        reaction[req.Emoji] = emojiUserIds
 }
 
-func (ms *MetaService) convertToReactionResp(ctx context.Context, reaction 
schema.ReactSummaryMeta) (*schema.ReactionResp, error) {
+func (ms *MetaService) convertToReactionResp(ctx context.Context, userId 
string, reaction schema.ReactionSummaryMeta) (*schema.ReactionResp, error) {
+       lang := handler.GetLangByCtx(ctx)
        resp := &schema.ReactionResp{
-               ReactionSummary: make(schema.ReactSummaryMeta),
+               ReactionSummary: make(map[string]*schema.ReactionItem),
+       }
+       isInArray := func(arr []string, target string) bool {
+               for _, str := range arr {
+                       if str == target {
+                               return true
+                       }
+               }
+               return false
        }
        // traverse map and convert to username
        for emoji, userIds := range reaction {
+               resp.ReactionSummary[emoji] = &schema.ReactionItem{
+                       Count:    len(userIds),
+                       IsActive: isInArray(userIds, userId),
+               }
                userNames := make([]string, 0)
                userBasicInfos, err := 
ms.userCommon.BatchUserBasicInfoByID(ctx, userIds)
                if err != nil {
@@ -194,9 +210,18 @@ func (ms *MetaService) convertToReactionResp(ctx 
context.Context, reaction schem
                }
                // get username
                for _, userBasicInfo := range userBasicInfos {
+                       if len(userNames) == 5 {
+                               resp.ReactionSummary[emoji].Tooltip = 
translator.TrWithData(lang, constant.ReactionTooltipLabel, map[string]string{
+                                       "Count": strconv.Itoa(len(userIds) - 5),
+                                       "Names": strings.Join(userNames, ", "),
+                               })
+                               break
+                       }
                        userNames = append(userNames, userBasicInfo.Username)
                }
-               resp.ReactionSummary[emoji] = userNames
+               if len(userIds) <= 5 {
+                       resp.ReactionSummary[emoji].Tooltip = 
strings.Join(userNames, ", ")
+               }
        }
 
        return resp, nil
diff --git a/internal/service/meta_common/meta_common_service.go 
b/internal/service/meta_common/meta_common_service.go
index d34f7d43..08065d54 100644
--- a/internal/service/meta_common/meta_common_service.go
+++ b/internal/service/meta_common/meta_common_service.go
@@ -81,7 +81,7 @@ func (ms *MetaCommonService) 
AddOrUpdateMetaByObjectIdAndKey(ctx context.Context
 func (ms *MetaCommonService) GetMetaByObjectIdAndKey(ctx context.Context, 
objectID, key string) (meta *entity.Meta, err error) {
        meta, exist, err := ms.metaRepo.GetMetaByObjectIdAndKey(ctx, objectID, 
key)
        if err != nil {
-               return
+               return nil, err
        }
        if !exist {
                return nil, myErrors.BadRequest(reason.MetaObjectNotFound)
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index d5f64f40..700746b8 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -724,5 +724,11 @@ export interface PutFlagReviewParams {
  * @description response for reaction
  */
 export interface ReactionItems {
-  reaction_summary: Record<string, string[]>;
+  reaction_summary: Record<string, ReactionItem>;
+}
+
+export interface ReactionItem {
+  count: number;
+  tooltip: string;
+  is_active: boolean;
 }
diff --git a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx 
b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx
index 0d380204..dc08cf1e 100644
--- a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx
+++ b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
 import { Icon } from '@/components';
 import { queryReactions, updateReaction } from '@/services';
 import { tryNormalLogged } from '@/utils/guard';
-import { loggedUserInfoStore } from '@/stores';
+import { ReactionItem } from '@/common/interface';
 
 interface Props {
   objectId: string;
@@ -36,9 +36,8 @@ const Index: FC<Props> = ({
   showAddCommentBtn,
   handleClickComment,
 }) => {
-  const [reactions, setReactions] = useState<Record<string, string[]>>();
+  const [reactions, setReactions] = useState<Record<string, ReactionItem>>();
   const { t } = useTranslation('translation');
-  const { username = '' } = loggedUserInfoStore((state) => state.user);
 
   useEffect(() => {
     queryReactions(objectId).then((res) => {
@@ -50,34 +49,34 @@ const Index: FC<Props> = ({
     if (!tryNormalLogged(true)) {
       return;
     }
-    let reaction = 'activate';
-    if (
-      reactions &&
-      reactions[params.emoji] &&
-      reactions[params.emoji].includes(username)
-    ) {
-      reaction = 'deactivate';
-    }
-    updateReaction({ ...params, reaction }).then((res) => {
+    updateReaction({
+      ...params,
+      reaction:
+        reactions &&
+        reactions[params.emoji] &&
+        reactions[params.emoji].is_active
+          ? 'deactivate'
+          : 'activate',
+    }).then((res) => {
       setReactions(res.reaction_summary);
     });
   };
 
-  const convertToTooltip = (names: string[]) => {
-    const n: number = Math.min(5, names.length);
-    let ret = '';
-    for (let i = 0; i < n; i += 1) {
-      if (i === n - 1) {
-        ret += names[i];
-      } else {
-        ret += `${names[i]}, `;
-      }
-    }
-    if (names.length > 5) {
-      ret += t('reaction.tooltip', { count: names.length - 5 });
-    }
-    return ret;
-  };
+  // const convertToTooltip = (names: string[]) => {
+  //   const n: number = Math.min(5, names.length);
+  //   let ret = '';
+  //   for (let i = 0; i < n; i += 1) {
+  //     if (i === n - 1) {
+  //       ret += names[i];
+  //     } else {
+  //       ret += `${names[i]}, `;
+  //     }
+  //   }
+  //   if (names.length > 5) {
+  //     ret += t('reaction.tooltip', { count: names.length - 5 });
+  //   }
+  //   return ret;
+  // };
 
   const renderTooltip = (props) => (
     <Tooltip id="reaction-button-tooltip" {...props} bsPrefix="tooltip">
@@ -120,7 +119,7 @@ const Index: FC<Props> = ({
 
       {reactions &&
         emojiMap.map((emoji) => {
-          if (!reactions[emoji.name] || reactions[emoji.name].length === 0) {
+          if (!reactions[emoji.name] || reactions[emoji.name].count === 0) {
             return null;
           }
           return (
@@ -131,7 +130,7 @@ const Index: FC<Props> = ({
                 <Tooltip>
                   <div className="text-start">
                     <b>{t(`reaction.${emoji.name}`)}</b> <br />{' '}
-                    {convertToTooltip(reactions[emoji.name])}
+                    {reactions[emoji.name].tooltip}
                   </div>
                 </Tooltip>
               }>
@@ -143,7 +142,7 @@ const Index: FC<Props> = ({
                   handleSubmit({ object_id: objectId, emoji: emoji.name })
                 }>
                 <Icon name={emoji.icon} className={emoji.className} />
-                <span className="ms-1">{reactions[emoji.name].length}</span>
+                <span className="ms-1">{reactions[emoji.name].count}</span>
               </Button>
             </OverlayTrigger>
           );

Reply via email to