[WEB-4025] fix: external user comment and reaction (#7692)

* chore: reactions types updated

* fix: external user comments

* fix: external user reactions

* chore: added display name for actor

* chore: merge conflicts

* chore: updated the created_by and updated_by

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
Anmol Singh Bhatia
2025-09-09 23:50:11 +05:30
committed by GitHub
parent 260d9a053d
commit 56cd0fc445
6 changed files with 42 additions and 19 deletions

View File

@@ -667,16 +667,33 @@ class IssueReactionSerializer(BaseSerializer):
class IssueReactionLiteSerializer(DynamicBaseSerializer):
display_name = serializers.CharField(source="actor.display_name", read_only=True)
class Meta:
model = IssueReaction
fields = ["id", "actor", "issue", "reaction"]
fields = ["id", "actor", "issue", "reaction", "display_name"]
class CommentReactionSerializer(BaseSerializer):
display_name = serializers.CharField(source="actor.display_name", read_only=True)
class Meta:
model = CommentReaction
fields = "__all__"
read_only_fields = ["workspace", "project", "comment", "actor", "deleted_at"]
fields = [
"id",
"actor",
"comment",
"reaction",
"display_name",
"deleted_at",
"workspace",
"project",
"created_at",
"updated_at",
"created_by",
"updated_by",
]
read_only_fields = ["workspace", "project", "comment", "actor", "deleted_at", "created_by", "updated_by"]
class IssueVoteSerializer(BaseSerializer):

View File

@@ -2,9 +2,8 @@ import { FC, ReactNode, useRef } from "react";
import { observer } from "mobx-react";
// plane imports
import { useTranslation } from "@plane/i18n";
import { Tooltip } from "@plane/propel/tooltip";
import { TIssueComment } from "@plane/types";
import { Avatar } from "@plane/ui";
import { EIssueCommentAccessSpecifier, TIssueComment } from "@plane/types";
import { Avatar, Tooltip } from "@plane/ui";
import { calculateTimeAgo, cn, getFileURL, renderFormattedDate, renderFormattedTime } from "@plane/utils";
// hooks
import { useMember } from "@/hooks/store/use-member";
@@ -27,7 +26,13 @@ export const CommentBlock: FC<TCommentBlock> = observer((props) => {
// translation
const { t } = useTranslation();
if (!comment || !userDetails) return null;
const displayName = comment?.actor_detail?.is_bot
? comment?.actor_detail?.first_name + ` ${t("bot")}`
: (userDetails?.display_name ?? comment?.actor_detail?.display_name);
const avatarUrl = userDetails?.avatar_url ?? comment?.actor_detail?.avatar_url;
if (!comment) return null;
return (
<div
@@ -43,20 +48,15 @@ export const CommentBlock: FC<TCommentBlock> = observer((props) => {
"flex-shrink-0 relative w-7 h-6 rounded-full transition-border duration-1000 flex justify-center items-center z-[3] uppercase font-medium"
)}
>
<Avatar
size="base"
name={userDetails?.display_name}
src={getFileURL(userDetails?.avatar_url)}
className="flex-shrink-0"
/>
<Avatar size="base" name={displayName} src={getFileURL(avatarUrl)} className="flex-shrink-0" />
</div>
<div className="flex flex-col gap-3 truncate flex-grow">
<div className="flex w-full gap-2">
<div className="flex-1 flex flex-wrap items-center gap-1">
<div className="text-xs font-medium">
{comment?.actor_detail?.is_bot
? comment?.actor_detail?.first_name + ` ${t("bot")}`
: comment?.actor_detail?.display_name || userDetails.display_name}
<div className="flex items-center gap-1">
<span className="text-xs font-medium">
{`${displayName}${comment.access === EIssueCommentAccessSpecifier.EXTERNAL ? " (External User)" : ""}`}
</span>
</div>
<div className="text-xs text-custom-text-300">
commented{" "}

View File

@@ -85,7 +85,9 @@ export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props)
const reactionUsers = (reactionIds?.[reaction] || [])
.map((reactionId) => {
const reactionDetails = getCommentReactionById(reactionId);
return reactionDetails ? getUserDetails(reactionDetails.actor)?.display_name : null;
return reactionDetails
? getUserDetails(reactionDetails?.actor)?.display_name || reactionDetails?.display_name
: null;
})
.filter((displayName): displayName is string => !!displayName);
const formattedUsers = formatTextList(reactionUsers);

View File

@@ -85,7 +85,9 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
const reactionUsers = (reactionIds?.[reaction] || [])
.map((reactionId) => {
const reactionDetails = getReactionById(reactionId);
return reactionDetails ? getUserDetails(reactionDetails.actor)?.display_name : null;
return reactionDetails
? getUserDetails(reactionDetails?.actor)?.display_name || reactionDetails?.display_name
: null;
})
.filter((displayName): displayName is string => !!displayName);

View File

@@ -9,6 +9,7 @@ export type TIssueCommentReaction = {
updated_at: Date;
created_by: string;
updated_by: string;
display_name: string;
};
export type TIssueCommentReactionMap = {

View File

@@ -5,6 +5,7 @@ export type TIssueReaction = {
id: string;
issue: string;
reaction: string;
display_name: string;
};
export interface IIssuePublicReaction {