Skip to content

Commit

Permalink
Conversation - Layout Emojis on right column
Browse files Browse the repository at this point in the history
  • Loading branch information
PopDaph committed Oct 4, 2023
1 parent f6d46ef commit 229ca96
Showing 1 changed file with 109 additions and 107 deletions.
216 changes: 109 additions & 107 deletions front/components/assistant/conversation/ConversationMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import {
Avatar,
Button,
DropdownMenu,
IconButton,
PlusIcon,
} from "@dust-tt/sparkle";
import { Avatar, Button, DropdownMenu } from "@dust-tt/sparkle";
import { Emoji, EmojiMartData } from "@emoji-mart/data";
import Picker from "@emoji-mart/react";
import { FaceSmileIcon } from "@heroicons/react/24/outline";
import { ComponentType, MouseEventHandler, useEffect, useState } from "react";
import React from "react";
import { mutate } from "swr";

import { classNames } from "@app/lib/utils";
import { MessageReactionType } from "@app/types/assistant/conversation";
import { UserType, WorkspaceType } from "@app/types/user";

const MAX_REACTIONS_TO_SHOW = 15;
const MAX_MORE_REACTIONS_TO_SHOW = 9;

/**
* Parent component for both UserMessage and AgentMessage, to ensure avatar,
Expand Down Expand Up @@ -98,102 +92,138 @@ export function ConversationMessage({
});
};

// Extracting some of the emoji logic from the render function to make it more readable
const reactionUp = reactions.find((r) => r.emoji === "+1");
const hasReactedUp =
reactionUp?.users.some((u) => u.userId === user.id) ?? false;

const reactionDown = reactions.find((r) => r.emoji === "-1");
const hasReactedDown =
reactionDown?.users.some((u) => u.userId === user.id) ?? false;

const reactionLove = reactions.find((r) => r.emoji === "heart");
const hasReactedLove =
reactionLove?.users.some((u) => u.userId === user.id) ?? false;

let otherReactions = reactions.filter(
(r) => r.emoji !== "+1" && r.emoji !== "-1" && r.emoji !== "heart"
);
let hasMoreReactions = null;
if (reactions.length > MAX_REACTIONS_TO_SHOW) {
hasMoreReactions = reactions.length - MAX_REACTIONS_TO_SHOW;
reactions = reactions.slice(0, MAX_REACTIONS_TO_SHOW);
if (otherReactions.length > MAX_MORE_REACTIONS_TO_SHOW) {
hasMoreReactions = otherReactions.length - MAX_MORE_REACTIONS_TO_SHOW;
otherReactions = otherReactions.slice(0, MAX_MORE_REACTIONS_TO_SHOW);
}

return (
<div className="flex w-full flex-row gap-4">
<div className="flex-shrink-0">
<Avatar
visual={pictureUrl}
name={name || undefined}
size="md"
busy={avatarBusy}
/>
<div className="grid grid-cols-12 gap-4">
{/* COLUMN 1: AVATAR - in small size if small layout */}
<div className="col-span-1">
<div className="sm:hidden">
<Avatar
visual={pictureUrl}
name={name || undefined}
size="xs"
busy={avatarBusy}
/>
</div>
<div className="hidden sm:block">
<Avatar
visual={pictureUrl}
name={name || undefined}
size="md"
busy={avatarBusy}
/>
</div>
</div>
<div className="min-w-0 flex-grow">

{/* COLUMN 2: CONTENT */}
<div className="col-span-8">
<div className="flex flex-col gap-4">
<div className="text-sm font-medium">{name}</div>
<div className="min-w-0 break-words text-base font-normal">
{children}
</div>
<div>
{reactions.map((reaction) => {
const hasReacted =
reaction.users.find((u) => u.userId === user.id) !== undefined;
const emoji = emojiData?.emojis[reaction.emoji];
if (!emoji) {
return null;
}
return (
<React.Fragment key={reaction.emoji}>
<a
className="cursor-pointer"
onClick={async () => {
await handleEmoji({
emoji: reaction.emoji,
isToRemove: hasReacted,
});
}}
>
<Reacji
key={reaction.emoji}
count={reaction.users.length}
isHighlighted={hasReacted}
emoji={emoji}
></Reacji>
</a>
</React.Fragment>
);
})}
{hasMoreReactions && (
<span className="text-base text-xs">+{hasMoreReactions}</span>
)}
</div>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-col items-start gap-2 sm:flex-row">
{buttons &&
buttons.map((button, i) => (
<div key={`message-${messageId}-button-${i}`}>

{/* COLUMN 3: BUTTONS */}
<div className="col-span-3">
{/* COPY / RETRY */}
{buttons && (
<div className="mb-6">
<Button.List>
{buttons.map((button, i) => (
<Button
key={`message-${messageId}-button-${i}`}
variant="tertiary"
size="xs"
label={button.label}
labelVisible={false}
icon={button.icon}
onClick={button.onClick}
/>
</div>
))}
</div>
))}
</Button.List>
</div>
)}

<div className="duration-400 active:s-border-action-500 box-border inline-flex scale-100 cursor-pointer items-center gap-x-1 whitespace-nowrap rounded-full border border-structure-200 bg-structure-0 px-2 text-xs text-element-800 ">
<a
className="cursor-pointer px-1 py-1.5 hover:border-action-200 hover:bg-action-50 hover:drop-shadow-md active:scale-95 active:bg-action-100 active:drop-shadow-none"
{/* EMOJIS */}
<Button.List isWrapping={true}>
<Button
variant={hasReactedUp ? "secondary" : "tertiary"}
size="xs"
label={reactionUp ? `👍 ${reactionUp.users.length}` : "👍 "}
onClick={async () => await handleEmojiClick("+1")}
>
👍
</a>
<a
className="cursor-pointer px-1 py-1.5 hover:border-action-200 hover:bg-action-50 hover:drop-shadow-md active:scale-95 active:bg-action-100 active:drop-shadow-none"
/>
<Button
variant={hasReactedDown ? "secondary" : "tertiary"}
size="xs"
label={reactionDown ? `👎 ${reactionDown.users.length}` : `👎`}
onClick={async () => await handleEmojiClick("-1")}
>
👎
</a>
<a
className="cursor-pointer px-1 py-1.5 hover:border-action-200 hover:bg-action-50 hover:drop-shadow-md active:scale-95 active:bg-action-100 active:drop-shadow-none"
/>
<Button
variant={hasReactedLove ? "secondary" : "tertiary"}
size="xs"
label={reactionLove ? `❤️ ${reactionLove.users.length}` : "❤️ "}
onClick={async () => await handleEmojiClick("heart")}
>
❤️
</a>
/>
{otherReactions.map((reaction) => {
const hasReacted = reaction.users.some((u) => u.userId === user.id);
const emoji = emojiData?.emojis[reaction.emoji];
const nativeEmoji = emoji?.skins[0].native;
if (!nativeEmoji) {
return null;
}
return (
<Button
key={reaction.emoji}
variant={hasReacted ? "secondary" : "tertiary"}
size="xs"
label={`${nativeEmoji} ${reaction.users.length}`}
onClick={async () =>
await handleEmoji({
emoji: reaction.emoji,
isToRemove: hasReacted,
})
}
/>
);
})}
{hasMoreReactions && (
<span className="text-xs">+{hasMoreReactions}</span>
)}
</Button.List>
<div className="mt-2">
<DropdownMenu>
<DropdownMenu.Button>
<IconButton variant="tertiary" size="xs" icon={PlusIcon} />
<Button
variant="tertiary"
size="xs"
icon={FaceSmileIcon}
labelVisible={false}
label="Add another emoji"
type="menu"
/>
</DropdownMenu.Button>
<DropdownMenu.Items width={280}>
<Picker
Expand Down Expand Up @@ -222,31 +252,3 @@ export function ConversationMessage({
</div>
);
}

function Reacji({
count,
isHighlighted,
emoji,
}: {
count: number;
isHighlighted: boolean;
emoji: Emoji;
}) {
const nativeEmoji = emoji.skins[0].native;
if (!nativeEmoji) {
return null;
}
return (
<span className="whitespace-nowrap pr-2">
{nativeEmoji}&nbsp;
<span
className={classNames(
"text-xs",
isHighlighted ? "font-bold text-action-500" : ""
)}
>
{count}
</span>
</span>
);
}

0 comments on commit 229ca96

Please sign in to comment.