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

Commit 1c67033

Browse files
authored
Highlight my vote even if it was made on another device (#7202)
1 parent 37828ab commit 1c67033

File tree

2 files changed

+50
-23
lines changed

2 files changed

+50
-23
lines changed

src/components/views/messages/MPollBody.tsx

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
import StyledRadioButton from '../elements/StyledRadioButton';
3030
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
3131
import { Relations } from 'matrix-js-sdk/src/models/relations';
32-
import { MatrixClientPeg } from '../../../MatrixClientPeg';
32+
import MatrixClientContext from "../../../contexts/MatrixClientContext";
3333
import ErrorDialog from '../dialogs/ErrorDialog';
3434

3535
// TODO: [andyb] Use extensible events library when ready
@@ -42,20 +42,16 @@ interface IState {
4242

4343
@replaceableComponent("views.messages.MPollBody")
4444
export default class MPollBody extends React.Component<IBodyProps, IState> {
45+
static contextType = MatrixClientContext;
46+
public context!: React.ContextType<typeof MatrixClientContext>;
47+
4548
constructor(props: IBodyProps) {
4649
super(props);
4750

48-
const pollRelations = this.fetchPollRelations();
49-
let selected = null;
50-
51-
const userVotes = collectUserVotes(allVotes(pollRelations), null);
52-
const userId = MatrixClientPeg.get().getUserId();
53-
const currentVote = userVotes.get(userId);
54-
if (currentVote) {
55-
selected = currentVote.answers[0];
56-
}
57-
58-
this.state = { selected, pollRelations };
51+
this.state = {
52+
selected: null,
53+
pollRelations: this.fetchPollRelations(),
54+
};
5955

6056
this.addListeners(this.state.pollRelations);
6157
this.props.mxEvent.on("Event.relationsCreated", this.onPollRelationsCreated);
@@ -119,7 +115,8 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
119115
"rel_type": "m.reference",
120116
},
121117
};
122-
MatrixClientPeg.get().sendEvent(
118+
119+
this.context.sendEvent(
123120
this.props.mxEvent.getRoomId(),
124121
POLL_RESPONSE_EVENT_TYPE.name,
125122
responseContent,
@@ -158,12 +155,13 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
158155
}
159156

160157
/**
161-
* @returns answer-id -> number-of-votes
158+
* @returns userId -> UserVote
162159
*/
163-
private collectVotes(): Map<string, number> {
164-
return countVotes(
165-
collectUserVotes(allVotes(this.state.pollRelations), this.state.selected),
166-
this.props.mxEvent.getContent(),
160+
private collectUserVotes(): Map<string, UserVote> {
161+
return collectUserVotes(
162+
allVotes(this.state.pollRelations),
163+
this.context.getUserId(),
164+
this.state.selected,
167165
);
168166
}
169167

@@ -184,15 +182,18 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
184182
}
185183

186184
const pollId = this.props.mxEvent.getId();
187-
const votes = this.collectVotes();
185+
const userVotes = this.collectUserVotes();
186+
const votes = countVotes(userVotes, this.props.mxEvent.getContent());
188187
const totalVotes = this.totalVotes(votes);
188+
const userId = this.context.getUserId();
189+
const myVote = userVotes.get(userId)?.answers[0];
189190

190191
return <div className="mx_MPollBody">
191192
<h2>{ pollInfo.question[TEXT_NODE_TYPE] }</h2>
192193
<div className="mx_MPollBody_allOptions">
193194
{
194195
pollInfo.answers.map((answer: IPollAnswer) => {
195-
const checked = this.state.selected === answer.id;
196+
const checked = myVote === answer.id;
196197
const classNames = `mx_MPollBody_option${
197198
checked ? " mx_MPollBody_option_checked": ""
198199
}`;
@@ -207,7 +208,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
207208
<StyledRadioButton
208209
name={`poll_answer_select-${pollId}`}
209210
value={answer.id}
210-
checked={this.state.selected === answer.id}
211+
checked={checked}
211212
onChange={this.onOptionSelected}
212213
>
213214
<div className="mx_MPollBody_optionDescription">
@@ -275,6 +276,7 @@ export function allVotes(pollRelations: Relations): Array<UserVote> {
275276
*/
276277
function collectUserVotes(
277278
userResponses: Array<UserVote>,
279+
userId: string,
278280
selected?: string,
279281
): Map<string, UserVote> {
280282
const userVotes: Map<string, UserVote> = new Map();
@@ -287,8 +289,6 @@ function collectUserVotes(
287289
}
288290

289291
if (selected) {
290-
const client = MatrixClientPeg.get();
291-
const userId = client.getUserId();
292292
userVotes.set(userId, new UserVote(0, userId, [selected]));
293293
}
294294

test/components/views/messages/MPollBody-test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import { IPollAnswer, IPollContent } from "../../../../src/polls/consts";
2727
import { UserVote, allVotes } from "../../../../src/components/views/messages/MPollBody";
2828
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
2929

30+
const CHECKED = "mx_MPollBody_option_checked";
31+
3032
const _MPollBody = sdk.getComponent("views.messages.MPollBody");
3133
const MPollBody = TestUtils.wrapInMatrixClientContext(_MPollBody);
3234

@@ -142,6 +144,25 @@ describe("MPollBody", () => {
142144
expect(votesCount(body, "wings")).toBe("1 vote");
143145

144146
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe("Based on 2 votes");
147+
148+
// And my vote is highlighted
149+
expect(voteButton(body, "wings").hasClass(CHECKED)).toBe(true);
150+
expect(voteButton(body, "italian").hasClass(CHECKED)).toBe(false);
151+
});
152+
153+
it("highlights my vote even if I did it on another device", () => {
154+
// Given I voted italian
155+
const votes = [
156+
responseEvent("@me:example.com", "italian"),
157+
responseEvent("@nf:example.com", "wings"),
158+
];
159+
const body = newMPollBody(votes);
160+
161+
// But I didn't click anything locally
162+
163+
// Then my vote is highlighted, and others are not
164+
expect(voteButton(body, "italian").hasClass(CHECKED)).toBe(true);
165+
expect(voteButton(body, "wings").hasClass(CHECKED)).toBe(false);
145166
});
146167

147168
it("ignores extra answers", () => {
@@ -380,6 +401,12 @@ function clickRadio(wrapper: ReactWrapper, value: string) {
380401
wrapper.find(`StyledRadioButton[value="${value}"]`).simulate("click");
381402
}
382403

404+
function voteButton(wrapper: ReactWrapper, value: string): ReactWrapper {
405+
return wrapper.find(
406+
`div.mx_MPollBody_option`,
407+
).findWhere(w => w.key() === value);
408+
}
409+
383410
function votesCount(wrapper: ReactWrapper, value: string): string {
384411
return wrapper.find(
385412
`StyledRadioButton[value="${value}"] .mx_MPollBody_optionVoteCount`,

0 commit comments

Comments
 (0)