Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Add reactions dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
simobot committed Mar 14, 2022
1 parent d7a7478 commit 54bdf28
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
@import "./views/dialogs/_ModalWidgetDialog.scss";
@import "./views/dialogs/_NewSessionReviewDialog.scss";
@import "./views/dialogs/_PollCreateDialog.scss";
@import "./views/dialogs/_ReactionsDialog.scss";
@import "./views/dialogs/_RegistrationEmailPromptDialog.scss";
@import "./views/dialogs/_RoomSettingsDialog.scss";
@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
Expand Down
67 changes: 67 additions & 0 deletions res/css/views/dialogs/_ReactionsDialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.mx_ReactionsDialog {
width: 520px;
color: $primary-content;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
min-height: 0;
height: 80vh;

.mx_ReactionsWrapper {
display: flex;
flex-direction: row;

> .mx_EmojiList {
margin-right: 1em;
padding-left: 1em;
padding-right: 1em;
}

> ul {
list-style-type: none;
}

.mx_SenderList {
padding: 0;
li {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
}
}

.mx_EmojiFilterButton {
display: inline-flex;
line-height: $font-20px;
margin-right: 6px;
margin-bottom: 0.5em;
padding: 1px 6px;
border: 1px solid $message-action-bar-border-color;
border-radius: 10px;
background-color: $header-panel-bg-color;
cursor: pointer;
user-select: none;
vertical-align: middle;

&:hover {
border-color: $reaction-row-button-hover-border-color;
}

&.mx_ReactionsRowButton_selected {
background-color: $reaction-row-button-selected-bg-color;
border-color: $accent;
}

&.mx_AccessibleButton_disabled {
cursor: not-allowed;
}

.mx_ReactionsRowButton_content {
max-width: 100px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-right: 4px;
}
}
}
112 changes: 112 additions & 0 deletions src/components/views/dialogs/ReactionsDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react';
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Relations } from 'matrix-js-sdk/src/models/relations';

import { _t } from '../../../languageHandler';
import { IDialogProps } from "./IDialogProps";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import BaseDialog from "./BaseDialog";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import AccessibleButton from '../elements/AccessibleButton';

interface IProps extends IDialogProps {
mxEvent: MatrixEvent;
reactions: Relations;
}

interface IState {
filteredEmoji: string|null;
allAnnotations: any[];
}

@replaceableComponent("views.dialogs.ReactionsDialog")
export default class ReactionsDialog extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
}

state = {
filteredEmoji: null,
allAnnotations: [],
};

componentDidMount() {
this.setState({ allAnnotations: this.getAllAnnotations() });
}

private sortAnnotations(arr1, arr2) {
return arr2[1].size - arr1[1].size;
}

private getAllAnnotations() {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.mxEvent.getRoomId());
const reactions = this.props.reactions;
const sortedAnnotations = reactions.getSortedAnnotationsByKey()
.sort(this.sortAnnotations);
const senders = [];
for (const reaction of sortedAnnotations) {
const emoji = reaction[0];
const reactionEvents = reaction[1];
for (const reactionEvent of reactionEvents) {
const member = room.getMember(reactionEvent.getSender());
const name = member ? member.name : reactionEvent.getSender();
senders.push([emoji, name]);
}
}
return senders;
}

private getFilteredAnnotations() {
const filterEmoji = this.state.filteredEmoji;
return this.state.allAnnotations
.filter(ann => filterEmoji === null || ann[0] == filterEmoji);
}

private setFilterEmoji(emoji) {
const matchingEmoji = this.state.allAnnotations
.filter(([existingEmoji, _]) => emoji === existingEmoji);
if (matchingEmoji.length == 0) {
emoji = null;
}
this.setState({ filteredEmoji: emoji });
}

private emojiFilterButton(emoji, size) {
return (<AccessibleButton
className="mx_EmojiFilterButton"
onClick={() => this.setFilterEmoji(emoji)}
>
{ emoji } { size }
</AccessibleButton>);
}

render() {
const reactions = this.props.reactions.getSortedAnnotationsByKey()
.map(([emoji, senders]): [string, number] => [emoji, senders.size]);
const totalReactions = reactions.reduce((acc, [_, size]) => size + acc, 0);
reactions.unshift([_t('All'), totalReactions]);

const emojiList = reactions.map(([emoji, size]) =>
(<li key={emoji}>{ this.emojiFilterButton(emoji, size) }</li>));
const senderList = this.getFilteredAnnotations()
.map(([emoji, sender]) => (<li key={emoji + sender}>{ emoji }&nbsp;{ sender }</li>));
return (
<BaseDialog
className="mx_ReactionsDialog"
onFinished={this.props.onFinished}
title={_t('Reactions')}
contentId='mx_ReactionsDialog'
>
<div className="mx_ReactionsWrapper">
<ul className="mx_EmojiList">
{ emojiList }
</ul>
<ul className="mx_SenderList">
{ senderList }
</ul>
</div>
</BaseDialog>
);
}
}

0 comments on commit 54bdf28

Please sign in to comment.