show reactions per user, allow only one reaction per message per user

This commit is contained in:
marlon-erler
2026-04-11 17:47:24 +00:00
parent a29cd023d5
commit cad4ebfdd4
8 changed files with 130 additions and 176 deletions
+2 -2
View File
@@ -733,7 +733,7 @@ body[showing-chat] #chat-page-wrapper {
display: none !important; display: none !important;
overflow: hidden; overflow: hidden;
} }
.message-bubble > .message-reaction-row:has(button:not([zero])) { .message-bubble > .message-reaction-row:has(button:not([count="0"])) {
display: grid !important; display: grid !important;
} }
.message-bubble > .message-reaction-row button { .message-bubble > .message-reaction-row button {
@@ -745,7 +745,7 @@ body[showing-chat] #chat-page-wrapper {
flex: 1 !important; flex: 1 !important;
animation: slide-up var(--animation-duration); animation: slide-up var(--animation-duration);
} }
.message-bubble > .message-reaction-row button[zero] { .message-bubble > .message-reaction-row button[count="0"] {
display: none; display: none;
} }
.message-reaction-row { .message-reaction-row {
+56 -87
View File
@@ -1498,11 +1498,7 @@
const fileContent = FileModel2.createFileContent(v4_default(), "reaction"); const fileContent = FileModel2.createFileContent(v4_default(), "reaction");
const reaction = { const reaction = {
...fileContent, ...fileContent,
fileId: _ChatModel.createMessageReactionId( fileId: _ChatModel.createMessageReactionId(messageId, sender),
messageId,
content,
sender
),
messageId, messageId,
sender, sender,
content, content,
@@ -1512,24 +1508,11 @@
}; };
} }
static { static {
this.createMessageReactionId = (messageId, content, sender) => { this.createMessageReactionId = (messageId, sender) => {
return messageId + sender + reactionStringMap[content]; return messageId + sender;
}; };
} }
}; };
var ReactionSymbols = /* @__PURE__ */ ((ReactionSymbols2) => {
ReactionSymbols2["ThumbsUp"] = "\u{1F44D}";
ReactionSymbols2["Check"] = "\u2705";
ReactionSymbols2["Stop"] = "\u{1F6D1}";
ReactionSymbols2["Attention"] = "\u2757\uFE0F";
ReactionSymbols2["DoubleAttention"] = "\u203C\uFE0F";
ReactionSymbols2["Question"] = "\u2753";
return ReactionSymbols2;
})(ReactionSymbols || {});
var reactionStringMap = {};
Object.entries(ReactionSymbols).forEach((value) => {
reactionStringMap[value[1]] = value[0];
});
var ChatInfoReference = { var ChatInfoReference = {
dataVersion: DATA_VERSION, dataVersion: DATA_VERSION,
primaryChannel: "", primaryChannel: "",
@@ -2038,35 +2021,39 @@
this.status = new State( this.status = new State(
void 0 void 0
); );
this.reactionsThumbsUp = new MapState(); this.allReactions = new MapState();
this.reactionsCheck = new MapState(); this.userReaction = new State(void 0);
this.reactionsStop = new MapState(); this.reactionsThumbsUp = MapState;
this.reactionsAttention = new MapState(); this.reactionsCheck = MapState;
this.reactionsDoubleAttention = new MapState(); this.reactionsStop = MapState;
this.reactionsQuestion = new MapState(); this.reactionsAttention = MapState;
this.reactionsThumbsUpCount = createProxyState( this.reactionsDoubleAttention = MapState;
[this.reactionsThumbsUp], this.reactionsQuestion = MapState;
() => this.reactionsThumbsUp.value.size this.generateReactionCountProxyState = (content) => {
return createProxyState(
[this.allReactions],
() => [...this.allReactions.value.values()].filter(
(x) => x.content == content
).length
);
};
this.reactionsThumbsUpCount = this.generateReactionCountProxyState(
"\u{1F44D}" /* ThumbsUp */
); );
this.reactionsCheckCount = createProxyState( this.reactionsCheckCount = this.generateReactionCountProxyState(
[this.reactionsCheck], "\u2705" /* Check */
() => this.reactionsCheck.value.size
); );
this.reactionsStopCount = createProxyState( this.reactionsStopCount = this.generateReactionCountProxyState(
[this.reactionsStop], "\u{1F6D1}" /* Stop */
() => this.reactionsStop.value.size
); );
this.reactionsAttentionCount = createProxyState( this.reactionsAttentionCount = this.generateReactionCountProxyState(
[this.reactionsAttention], "\u2757\uFE0F" /* Attention */
() => this.reactionsAttention.value.size
); );
this.reactionsDoubleAttentionCount = createProxyState( this.reactionsDoubleAttentionCount = this.generateReactionCountProxyState(
[this.reactionsDoubleAttention], "\u203C\uFE0F" /* DoubleAttention */
() => this.reactionsDoubleAttention.value.size
); );
this.reactionsQuestionCount = createProxyState( this.reactionsQuestionCount = this.generateReactionCountProxyState(
[this.reactionsQuestion], "\u2753" /* Question */
() => this.reactionsQuestion.value.size
); );
// state // state
this.isPresentingInfoModal = new State(false); this.isPresentingInfoModal = new State(false);
@@ -2089,27 +2076,13 @@
}; };
// reactions // reactions
this.handleReaction = (reaction) => { this.handleReaction = (reaction) => {
function setReaction(mapState) { if (reaction.isDeleting) {
if (reaction.isDeleting) { this.allReactions.remove(reaction.sender);
mapState.remove(reaction.sender); } else {
} else { this.allReactions.set(reaction.sender, reaction);
mapState.set(reaction.sender, reaction);
}
}
switch (reaction.content) {
case "\u{1F44D}" /* ThumbsUp */:
return setReaction(this.reactionsThumbsUp);
case "\u2705" /* Check */:
return setReaction(this.reactionsCheck);
case "\u{1F6D1}" /* Stop */:
return setReaction(this.reactionsStop);
case "\u2757\uFE0F" /* Attention */:
return setReaction(this.reactionsAttention);
case "\u203C\uFE0F" /* DoubleAttention */:
return setReaction(this.reactionsDoubleAttention);
case "\u2753" /* Question */:
return setReaction(this.reactionsQuestion);
} }
if (reaction.sender != this.coreViewModel.settingsModel.username) return;
this.userReaction.value = reaction.isDeleting ? void 0 : reaction.content;
}; };
this.sendReaction = (content, isDeleting) => { this.sendReaction = (content, isDeleting) => {
this.messagePageViewModel.sendReaction( this.messagePageViewModel.sendReaction(
@@ -3434,60 +3407,42 @@
function MessageReactionButton(coreViewModel2, chatMessageViewModel, content) { function MessageReactionButton(coreViewModel2, chatMessageViewModel, content) {
let audioLabel; let audioLabel;
let count; let count;
let reactionState; let isActive = createProxyState([chatMessageViewModel.userReaction], () => chatMessageViewModel.userReaction.value == content);
let isActive = new State(false);
let isZero = new State(true);
function sendReaction() { function sendReaction() {
chatMessageViewModel.sendReaction(content, isActive.value); chatMessageViewModel.sendReaction(content, isActive.value);
} }
function getUsername() {
return chatMessageViewModel.messagePageViewModel.chatViewModel.settingsViewModel.username.value;
}
function checkIsHighlighted() {
return reactionState.value.has(getUsername());
}
switch (content) { switch (content) {
case "\u{1F44D}" /* ThumbsUp */: { case "\u{1F44D}" /* ThumbsUp */: {
audioLabel = coreViewModel2.translations.chatPage.message.thumbsUpReaction; audioLabel = coreViewModel2.translations.chatPage.message.thumbsUpReaction;
count = chatMessageViewModel.reactionsThumbsUpCount; count = chatMessageViewModel.reactionsThumbsUpCount;
reactionState = chatMessageViewModel.reactionsThumbsUp;
break; break;
} }
case "\u2705" /* Check */: { case "\u2705" /* Check */: {
audioLabel = coreViewModel2.translations.chatPage.message.checkReaction; audioLabel = coreViewModel2.translations.chatPage.message.checkReaction;
count = chatMessageViewModel.reactionsCheckCount; count = chatMessageViewModel.reactionsCheckCount;
reactionState = chatMessageViewModel.reactionsCheck;
break; break;
} }
case "\u{1F6D1}" /* Stop */: { case "\u{1F6D1}" /* Stop */: {
audioLabel = coreViewModel2.translations.chatPage.message.stopReaction; audioLabel = coreViewModel2.translations.chatPage.message.stopReaction;
count = chatMessageViewModel.reactionsStopCount; count = chatMessageViewModel.reactionsStopCount;
reactionState = chatMessageViewModel.reactionsStop;
break; break;
} }
case "\u2757\uFE0F" /* Attention */: { case "\u2757\uFE0F" /* Attention */: {
audioLabel = coreViewModel2.translations.chatPage.message.attentionReaction; audioLabel = coreViewModel2.translations.chatPage.message.attentionReaction;
count = chatMessageViewModel.reactionsAttentionCount; count = chatMessageViewModel.reactionsAttentionCount;
reactionState = chatMessageViewModel.reactionsAttention;
break; break;
} }
case "\u203C\uFE0F" /* DoubleAttention */: { case "\u203C\uFE0F" /* DoubleAttention */: {
audioLabel = coreViewModel2.translations.chatPage.message.doubleAttentionReaction; audioLabel = coreViewModel2.translations.chatPage.message.doubleAttentionReaction;
count = chatMessageViewModel.reactionsDoubleAttentionCount; count = chatMessageViewModel.reactionsDoubleAttentionCount;
reactionState = chatMessageViewModel.reactionsDoubleAttention;
break; break;
} }
case "\u2753" /* Question */: { case "\u2753" /* Question */: {
audioLabel = coreViewModel2.translations.chatPage.message.questionReaction; audioLabel = coreViewModel2.translations.chatPage.message.questionReaction;
count = chatMessageViewModel.reactionsQuestionCount; count = chatMessageViewModel.reactionsQuestionCount;
reactionState = chatMessageViewModel.reactionsQuestion;
break; break;
} }
} }
reactionState.subscribe(() => {
isActive.value = checkIsHighlighted();
isZero.value = reactionState.value.size == 0;
});
return /* @__PURE__ */ createElement( return /* @__PURE__ */ createElement(
"button", "button",
{ {
@@ -3495,7 +3450,7 @@
"on:click": sendReaction, "on:click": sendReaction,
"aria-label": audioLabel, "aria-label": audioLabel,
"toggle:selected": isActive, "toggle:selected": isActive,
"toggle:zero": isZero "set:count": count
}, },
content, content,
/* @__PURE__ */ createElement("span", { "subscribe:innerText": count }) /* @__PURE__ */ createElement("span", { "subscribe:innerText": count })
@@ -3542,6 +3497,11 @@
return /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icon), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, label), /* @__PURE__ */ createElement("b", { class: "break-word", "subscribe:innerText": contentState }))); return /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, icon), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, label), /* @__PURE__ */ createElement("b", { class: "break-word", "subscribe:innerText": contentState })));
} }
// src/View/Components/messageReactionEntry.tsx
function MessageReactionEntry(reaction) {
return /* @__PURE__ */ createElement("div", { class: "tile flex-row" }, /* @__PURE__ */ createElement("span", { class: "flex width-100" }, reaction.sender), /* @__PURE__ */ createElement("span", null, reaction.content));
}
// src/View/Modals/chatMessageInfoModal.tsx // src/View/Modals/chatMessageInfoModal.tsx
function ChatMessageInfoModal(coreViewModel2, chatMessageViewModel) { function ChatMessageInfoModal(coreViewModel2, chatMessageViewModel) {
return /* @__PURE__ */ createElement( return /* @__PURE__ */ createElement(
@@ -3566,10 +3526,19 @@
"description", "description",
coreViewModel2.translations.chatPage.message.messageContent, coreViewModel2.translations.chatPage.message.messageContent,
chatMessageViewModel.body chatMessageViewModel.body
)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.copyMessage }, coreViewModel2.translations.chatPage.message.copyMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "content_copy")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.resendMessage }, coreViewModel2.translations.chatPage.message.resendMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "redo")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.decryptMessage }, coreViewModel2.translations.chatPage.message.decryptMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "key"))), /* @__PURE__ */ createElement("hr", null), MessageReactionButtonRow( )), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.copyMessage }, coreViewModel2.translations.chatPage.message.copyMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "content_copy")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.resendMessage }, coreViewModel2.translations.chatPage.message.resendMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "redo")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.decryptMessage }, coreViewModel2.translations.chatPage.message.decryptMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "key"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, MessageReactionButtonRow(
coreViewModel2, coreViewModel2,
chatMessageViewModel chatMessageViewModel
)), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.hideInfoModal }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))) ), /* @__PURE__ */ createElement(
"div",
{
class: "flex-column gap",
"children:append": [
chatMessageViewModel.allReactions,
MessageReactionEntry
]
}
))), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.hideInfoModal }, coreViewModel2.translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close")))
); );
} }
@@ -5623,7 +5592,7 @@
this.connectionModel = connectionModel2; this.connectionModel = connectionModel2;
this.chatListModel = chatListModel2; this.chatListModel = chatListModel2;
this.fileTransferModel = fileTransferModel2; this.fileTransferModel = fileTransferModel2;
this.BUILD = "Build 26.04.10.A"; this.BUILD = "Build 26.04.10.B";
// DRAG & DROP // DRAG & DROP
this.draggedObject = new State(void 0); this.draggedObject = new State(void 0);
// SUGGESTIONS // SUGGESTIONS
+2 -12
View File
@@ -416,11 +416,7 @@ export default class ChatModel {
const fileContent = FileModel.createFileContent(v4(), "reaction"); const fileContent = FileModel.createFileContent(v4(), "reaction");
const reaction: ChatMessageReaction = { const reaction: ChatMessageReaction = {
...fileContent, ...fileContent,
fileId: ChatModel.createMessageReactionId( fileId: ChatModel.createMessageReactionId(messageId, sender),
messageId,
content,
sender,
),
messageId, messageId,
sender, sender,
@@ -432,10 +428,9 @@ export default class ChatModel {
static createMessageReactionId = ( static createMessageReactionId = (
messageId: string, messageId: string,
content: ReactionSymbols,
sender: string, sender: string,
): string => { ): string => {
return messageId + sender + reactionStringMap[content]; return messageId + sender;
}; };
} }
@@ -449,11 +444,6 @@ export enum ReactionSymbols {
Question = "❓", Question = "❓",
} }
const reactionStringMap: { [key: ReactionSymbols | string]: string } = {};
Object.entries(ReactionSymbols).forEach((value) => {
reactionStringMap[value[1]] = value[0];
});
export interface ChatInfo extends ValidObject { export interface ChatInfo extends ValidObject {
primaryChannel: string; primaryChannel: string;
secondaryChannels: string[]; secondaryChannels: string[];
+2 -2
View File
@@ -181,7 +181,7 @@
overflow: hidden; overflow: hidden;
} }
.message-bubble > .message-reaction-row:has(button:not([zero])) { .message-bubble > .message-reaction-row:has(button:not([count="0"])) {
display: grid !important; display: grid !important;
} }
@@ -195,7 +195,7 @@
animation: slide-up var(--animation-duration); animation: slide-up var(--animation-duration);
} }
.message-bubble > .message-reaction-row button[zero] { .message-bubble > .message-reaction-row button[count="0"] {
display: none; display: none;
} }
+2 -24
View File
@@ -13,50 +13,35 @@ export function MessageReactionButton(
) { ) {
let audioLabel: string; let audioLabel: string;
let count: React.State<number>; let count: React.State<number>;
let reactionState: React.MapState<ChatMessageReaction>; let isActive = React.createProxyState([chatMessageViewModel.userReaction], (() => chatMessageViewModel.userReaction.value == content))
let isActive = new React.State(false);
let isZero = new React.State(true);
function sendReaction() { function sendReaction() {
chatMessageViewModel.sendReaction(content, isActive.value); chatMessageViewModel.sendReaction(content, isActive.value);
} }
function getUsername(): string {
return chatMessageViewModel.messagePageViewModel.chatViewModel
.settingsViewModel.username.value;
}
function checkIsHighlighted(): boolean {
return reactionState.value.has(getUsername());
}
switch (content) { switch (content) {
case ReactionSymbols.ThumbsUp: { case ReactionSymbols.ThumbsUp: {
audioLabel = audioLabel =
coreViewModel.translations.chatPage.message.thumbsUpReaction; coreViewModel.translations.chatPage.message.thumbsUpReaction;
count = chatMessageViewModel.reactionsThumbsUpCount; count = chatMessageViewModel.reactionsThumbsUpCount;
reactionState = chatMessageViewModel.reactionsThumbsUp;
break; break;
} }
case ReactionSymbols.Check: { case ReactionSymbols.Check: {
audioLabel = audioLabel =
coreViewModel.translations.chatPage.message.checkReaction; coreViewModel.translations.chatPage.message.checkReaction;
count = chatMessageViewModel.reactionsCheckCount; count = chatMessageViewModel.reactionsCheckCount;
reactionState = chatMessageViewModel.reactionsCheck;
break; break;
} }
case ReactionSymbols.Stop: { case ReactionSymbols.Stop: {
audioLabel = audioLabel =
coreViewModel.translations.chatPage.message.stopReaction; coreViewModel.translations.chatPage.message.stopReaction;
count = chatMessageViewModel.reactionsStopCount; count = chatMessageViewModel.reactionsStopCount;
reactionState = chatMessageViewModel.reactionsStop;
break; break;
} }
case ReactionSymbols.Attention: { case ReactionSymbols.Attention: {
audioLabel = audioLabel =
coreViewModel.translations.chatPage.message.attentionReaction; coreViewModel.translations.chatPage.message.attentionReaction;
count = chatMessageViewModel.reactionsAttentionCount; count = chatMessageViewModel.reactionsAttentionCount;
reactionState = chatMessageViewModel.reactionsAttention;
break; break;
} }
case ReactionSymbols.DoubleAttention: { case ReactionSymbols.DoubleAttention: {
@@ -64,30 +49,23 @@ export function MessageReactionButton(
coreViewModel.translations.chatPage.message coreViewModel.translations.chatPage.message
.doubleAttentionReaction; .doubleAttentionReaction;
count = chatMessageViewModel.reactionsDoubleAttentionCount; count = chatMessageViewModel.reactionsDoubleAttentionCount;
reactionState = chatMessageViewModel.reactionsDoubleAttention;
break; break;
} }
case ReactionSymbols.Question: { case ReactionSymbols.Question: {
audioLabel = audioLabel =
coreViewModel.translations.chatPage.message.questionReaction; coreViewModel.translations.chatPage.message.questionReaction;
count = chatMessageViewModel.reactionsQuestionCount; count = chatMessageViewModel.reactionsQuestionCount;
reactionState = chatMessageViewModel.reactionsQuestion;
break; break;
} }
} }
reactionState.subscribe(() => {
isActive.value = checkIsHighlighted();
isZero.value = reactionState.value.size == 0;
});
return ( return (
<button <button
class="flex" class="flex"
on:click={sendReaction} on:click={sendReaction}
aria-label={audioLabel} aria-label={audioLabel}
toggle:selected={isActive} toggle:selected={isActive}
toggle:zero={isZero} set:count={count}
> >
{content} {content}
<span subscribe:innerText={count}></span> <span subscribe:innerText={count}></span>
@@ -0,0 +1,13 @@
import * as React from "bloatless-react";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { ChatMessageReaction } from "../../Model/Chat/chatModel";
export function MessageReactionEntry(reaction: ChatMessageReaction) {
return (
<div class="tile flex-row">
<span class="flex width-100">{reaction.sender}</span>
<span>{reaction.content}</span>
</div>
);
}
+15 -4
View File
@@ -4,6 +4,7 @@ import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
import { MessageReactionButtonRow } from "../Components/messageReactionButtonRow"; import { MessageReactionButtonRow } from "../Components/messageReactionButtonRow";
import { InfoTile } from "../Components/infoTile"; import { InfoTile } from "../Components/infoTile";
import CoreViewModel from "../../ViewModel/Global/coreViewModel"; import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import { MessageReactionEntry } from "../Components/messageReactionEntry";
export function ChatMessageInfoModal( export function ChatMessageInfoModal(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
@@ -76,10 +77,20 @@ export function ChatMessageInfoModal(
<hr></hr> <hr></hr>
{MessageReactionButtonRow( <div class="flex-column gap">
coreViewModel, {MessageReactionButtonRow(
chatMessageViewModel, coreViewModel,
)} chatMessageViewModel,
)}
<div
class="flex-column gap"
children:append={[
chatMessageViewModel.allReactions,
MessageReactionEntry,
]}
></div>
</div>
</main> </main>
<button on:click={chatMessageViewModel.hideInfoModal}> <button on:click={chatMessageViewModel.hideInfoModal}>
{coreViewModel.translations.general.closeButton} {coreViewModel.translations.general.closeButton}
+38 -45
View File
@@ -3,7 +3,6 @@ import * as React from "bloatless-react";
import { import {
ChatMessage, ChatMessage,
ChatMessageReaction, ChatMessageReaction,
ChatMessageReactionReference,
ChatMessageStatuses, ChatMessageStatuses,
ReactionSymbols, ReactionSymbols,
} from "../../Model/Chat/chatModel"; } from "../../Model/Chat/chatModel";
@@ -23,36 +22,44 @@ export default class ChatMessageViewModel {
); );
sentByUser: boolean; sentByUser: boolean;
reactionsThumbsUp = new React.MapState<ChatMessageReaction>(); allReactions = new React.MapState<ChatMessageReaction>();
reactionsCheck = new React.MapState<ChatMessageReaction>(); userReaction = new React.State<ReactionSymbols | string | undefined>(undefined);
reactionsStop = new React.MapState<ChatMessageReaction>(); reactionsThumbsUp = React.MapState<ChatMessageReaction>;
reactionsAttention = new React.MapState<ChatMessageReaction>(); reactionsCheck = React.MapState<ChatMessageReaction>;
reactionsDoubleAttention = new React.MapState<ChatMessageReaction>(); reactionsStop = React.MapState<ChatMessageReaction>;
reactionsQuestion = new React.MapState<ChatMessageReaction>(); reactionsAttention = React.MapState<ChatMessageReaction>;
reactionsDoubleAttention = React.MapState<ChatMessageReaction>;
reactionsQuestion = React.MapState<ChatMessageReaction>;
reactionsThumbsUpCount = React.createProxyState( generateReactionCountProxyState = (
[this.reactionsThumbsUp], content: ReactionSymbols,
() => this.reactionsThumbsUp.value.size, ): React.State<number> => {
return React.createProxyState(
[this.allReactions],
() =>
[...this.allReactions.value.values()].filter(
(x) => x.content == content,
).length,
);
};
reactionsThumbsUpCount = this.generateReactionCountProxyState(
ReactionSymbols.ThumbsUp,
); );
reactionsCheckCount = React.createProxyState( reactionsCheckCount = this.generateReactionCountProxyState(
[this.reactionsCheck], ReactionSymbols.Check,
() => this.reactionsCheck.value.size,
); );
reactionsStopCount = React.createProxyState( reactionsStopCount = this.generateReactionCountProxyState(
[this.reactionsStop], ReactionSymbols.Stop,
() => this.reactionsStop.value.size,
); );
reactionsAttentionCount = React.createProxyState( reactionsAttentionCount = this.generateReactionCountProxyState(
[this.reactionsAttention], ReactionSymbols.Attention,
() => this.reactionsAttention.value.size,
); );
reactionsDoubleAttentionCount = React.createProxyState( reactionsDoubleAttentionCount = this.generateReactionCountProxyState(
[this.reactionsDoubleAttention], ReactionSymbols.DoubleAttention,
() => this.reactionsDoubleAttention.value.size,
); );
reactionsQuestionCount = React.createProxyState( reactionsQuestionCount = this.generateReactionCountProxyState(
[this.reactionsQuestion], ReactionSymbols.Question,
() => this.reactionsQuestion.value.size,
); );
// state // state
@@ -80,28 +87,14 @@ export default class ChatMessageViewModel {
// reactions // reactions
handleReaction = (reaction: ChatMessageReaction): void => { handleReaction = (reaction: ChatMessageReaction): void => {
function setReaction(mapState: React.MapState<any>) { if (reaction.isDeleting) {
if (reaction.isDeleting) { this.allReactions.remove(reaction.sender);
mapState.remove(reaction.sender); } else {
} else { this.allReactions.set(reaction.sender, reaction);
mapState.set(reaction.sender, reaction);
}
} }
switch (reaction.content) { if (reaction.sender != this.coreViewModel.settingsModel.username) return;
case ReactionSymbols.ThumbsUp: this.userReaction.value = reaction.isDeleting ? undefined : reaction.content;
return setReaction(this.reactionsThumbsUp);
case ReactionSymbols.Check:
return setReaction(this.reactionsCheck);
case ReactionSymbols.Stop:
return setReaction(this.reactionsStop);
case ReactionSymbols.Attention:
return setReaction(this.reactionsAttention);
case ReactionSymbols.DoubleAttention:
return setReaction(this.reactionsDoubleAttention);
case ReactionSymbols.Question:
return setReaction(this.reactionsQuestion);
}
}; };
sendReaction = (content: ReactionSymbols, isDeleting: boolean): void => { sendReaction = (content: ReactionSymbols, isDeleting: boolean): void => {