Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Message reactions POC #445

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 131 additions & 19 deletions demo/src/components/MessageComponent/MessageComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Message } from '@ably/chat';
import { Message, MessageReactionMode } from '@ably/chat';
import React, { useCallback } from 'react';
import clsx from 'clsx';
import { FaPencil, FaTrash } from 'react-icons/fa6';
Expand All @@ -10,6 +10,10 @@ interface MessageProps {
onMessageUpdate?(message: Message): void;

onMessageDelete?(msg: Message): void;

onAddReaction?(message: Message, reaction: string, score?: number, mode?: MessageReactionMode): void;

onRemoveReaction?(message: Message, reaction: string): void;
}

const shortDateTimeFormatter = new Intl.DateTimeFormat('default', {
Expand Down Expand Up @@ -37,6 +41,8 @@ export const MessageComponent: React.FC<MessageProps> = ({
message,
onMessageUpdate,
onMessageDelete,
onAddReaction,
onRemoveReaction,
}) => {
const handleMessageUpdate = useCallback(
(e: React.UIEvent) => {
Expand All @@ -54,6 +60,127 @@ export const MessageComponent: React.FC<MessageProps> = ({
[message, onMessageDelete],
);

const currentReactions = message.reactions;
const reactionsWithCounts = ['👍', '🚀', '🔥', '❤️'].map((emoji) => {
const data = currentReactions.get(emoji);

const clientIdArr : {clientId : string, total: number, score : number}[] = [];
if (data?.clientIds) {
for (let clientId in data.clientIds) {
clientIdArr.push({ clientId, score: data.clientIds[clientId].score, total: data.clientIds[clientId].total });
}
}
if (data) {
console.log("for emoji", emoji, "data", data, "clientIdArr", clientIdArr);
}

return { emoji, data, clientIdArr };
})

const messageReactionsUI = (
<div className="message-reactions">
{reactionsWithCounts.map((rwc) => (
<div
className={"message-reaction "+(self ? "message-reaction-self" : "message-reaction-other")}
key={rwc.emoji}
>
<a href="#" onClick={(e) => {
e.preventDefault();
onAddReaction?.(message, rwc.emoji, 1, MessageReactionMode.Add);
}}>{rwc.emoji}</a>
{rwc.data?.score && rwc.data?.score > 0 ? "(" + rwc.data.score + ")" : ""}
<div className="message-reaction-menu">
<ul>
<li><a href="#" onClick={(e) => {
e.preventDefault();
onAddReaction?.(message, rwc.emoji, 1, MessageReactionMode.Add);
}}>Add {rwc.emoji} reaction (default)</a></li>

<li><a href="#" onClick={(e) => {
e.preventDefault();
onAddReaction?.(message, rwc.emoji, 1, MessageReactionMode.Unique);
}}>Add unique {rwc.emoji} reaction</a></li>

<li><a href="#" onClick={(e) => {
e.preventDefault();
onAddReaction?.(message, rwc.emoji, 1, MessageReactionMode.Replace);
}}>Replace {rwc.emoji} reaction</a></li>


<li><a href="#" onClick={(e) => {
e.preventDefault();
let scoreStr = prompt("Enter score");
if (!scoreStr) return;
let score = parseInt(scoreStr);
if (!score || score <= 0) return;
onAddReaction?.(message, rwc.emoji, score, MessageReactionMode.Add);
}}>Add {rwc.emoji} reaction with score</a></li>

<li><a href="#" onClick={(e) => {
e.preventDefault();
let scoreStr = prompt("Enter score");
if (!scoreStr) return;
let score = parseInt(scoreStr);
if (!score || score <= 0) return;
onAddReaction?.(message, rwc.emoji, score, MessageReactionMode.Unique);
}}>Add unique {rwc.emoji} reaction with score</a></li>

<li><a href="#" onClick={(e) => {
e.preventDefault();
let scoreStr = prompt("Enter score");
if (!scoreStr) return;
let score = parseInt(scoreStr);
if (!score || score <= 0) return;
onAddReaction?.(message, rwc.emoji, score, MessageReactionMode.Replace);
}}>Replace {rwc.emoji} reaction with score</a></li>


<li><a href="#" onClick={(e) => {
e.preventDefault();
onRemoveReaction?.(message, rwc.emoji);
}}>Remove {rwc.emoji} reaction</a></li>
</ul>
<div>
<p>
<strong>Score:</strong> {rwc.data?.score && rwc.data?.score > 0 ? "(" + rwc.data.score + ")" : "-"}.
<strong>Total:</strong> {rwc.data?.total && rwc.data?.total > 0 ? "(" + rwc.data.total + ")" : "-"}.
</p>
{rwc.clientIdArr.length > 0 ? (
<ul>
{rwc.clientIdArr.map((clientIdData) => (
<li key={clientIdData.clientId}>
<strong>{clientIdData.clientId}</strong> - Score: {clientIdData.score} - Total: {clientIdData.total}
</li>
))}
</ul>
) : ""}
</div>
</div>
</div>
))}
</div>
);
const messageActionsUI = (
<div
className="buttons"
role="group"
aria-label="Message actions"
>
{!self && <>{messageReactionsUI} | </>}
<FaPencil
className="cursor-pointer text-gray-100 m-1 hover:text-gray-500 inline-block"
onClick={handleMessageUpdate}
aria-label="Edit message"
></FaPencil>
<FaTrash
className="cursor-pointer text-red-500 m-1 hover:text-red-700 inline-block"
onClick={handleMessageDelete}
aria-label="Delete message"
/>
{self && <> | {messageReactionsUI} </>}
</div>
);

return (
<div className="chat-message">
<div className={clsx('flex items-end', { ['justify-end']: self, ['justify-start']: !self })}>
Expand Down Expand Up @@ -85,28 +212,13 @@ export const MessageComponent: React.FC<MessageProps> = ({
</div>
<div
className={clsx('px-4 py-2 rounded-lg inline-block', {
['rounded-br bg-blue-600 text-white']: self,
['rounded-bl justify-start bg-gray-300 text-gray-600']: !self,
['rounded-br bg-blue-600 text-white ml-4']: self,
['rounded-bl justify-start bg-gray-300 text-gray-600 mr-4']: !self,
})}
>
{message.text}
</div>
<div
className="buttons"
role="group"
aria-label="Message actions"
>
<FaPencil
className="cursor-pointer text-gray-100 m-1 hover:text-gray-500 inline-block"
onClick={handleMessageUpdate}
aria-label="Edit message"
></FaPencil>
<FaTrash
className="cursor-pointer text-red-500 m-1 hover:text-red-700 inline-block"
onClick={handleMessageDelete}
aria-label="Delete message"
/>
</div>
{messageActionsUI}
</div>
</div>
</div>
Expand Down
Loading