mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
FIX: update voter information upon remote change (#28168)
Fixes issue with polls not being fully updated by remote vote contributions in (semi-) real-time. This was down to too great a focus on tracking local state and not accommodating a more data down approach with responsive getters. This is now implemented. I've tried hard to minimise the changes whilst making sure the paradigm is properly followed through.
This commit is contained in:
parent
11369018b6
commit
26c4d1398a
|
@ -1,5 +1,4 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import DButton from "discourse/components/d-button";
|
||||
|
@ -9,13 +8,6 @@ import I18n from "discourse-i18n";
|
|||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
export default class PollOptionsDropdownComponent extends Component {
|
||||
@tracked rank;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.rank = this.args.rank;
|
||||
}
|
||||
|
||||
@action
|
||||
onRegisterApi(api) {
|
||||
this.dMenu = api;
|
||||
|
@ -24,15 +16,13 @@ export default class PollOptionsDropdownComponent extends Component {
|
|||
@action
|
||||
selectRank(option, rank) {
|
||||
this.args.sendRank(option, rank);
|
||||
this.rank =
|
||||
rank === 0 ? I18n.t("poll.options.ranked_choice.abstain") : rank;
|
||||
this.dMenu.close();
|
||||
}
|
||||
|
||||
get rankLabel() {
|
||||
return this.rank === 0
|
||||
return this.args.rank === 0
|
||||
? I18n.t("poll.options.ranked_choice.abstain")
|
||||
: this.rank;
|
||||
: this.args.rank;
|
||||
}
|
||||
|
||||
<template>
|
||||
|
|
|
@ -27,7 +27,7 @@ export default class PollOptionsComponent extends Component {
|
|||
}
|
||||
<template>
|
||||
<ul class={{concatClass (if @isRankedChoice "ranked-choice-poll-options")}}>
|
||||
{{#each @options as |option|}}
|
||||
{{#each @options key="rank" as |option|}}
|
||||
{{#if @isRankedChoice}}
|
||||
<PollOptionRankedChoice
|
||||
@option={{option}}
|
||||
|
|
|
@ -40,8 +40,13 @@ export default class PollResultsStandardComponent extends Component {
|
|||
const chosen = (this.args.vote || []).includes(option.id);
|
||||
option.percentage = per;
|
||||
option.chosen = chosen;
|
||||
let voters = this.args.isPublic ? this.args.voters[option.id] || [] : [];
|
||||
let voters = this.args.isPublic
|
||||
? this.args.voters[option.id]?.voters || []
|
||||
: [];
|
||||
option.voters = [...voters];
|
||||
option.loading = this.args.isPublic
|
||||
? this.args.voters[option.id]?.loading || false
|
||||
: false;
|
||||
});
|
||||
|
||||
return ordered;
|
||||
|
|
|
@ -27,40 +27,26 @@ const REGULAR = "regular";
|
|||
const RANKED_CHOICE = "ranked_choice";
|
||||
const ON_VOTE = "on_vote";
|
||||
const ON_CLOSE = "on_close";
|
||||
const CLOSED_STATUS = "closed";
|
||||
const OPEN_STATUS = "open";
|
||||
|
||||
export default class PollComponent extends Component {
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
@service appEvents;
|
||||
@service dialog;
|
||||
@service router;
|
||||
@service modal;
|
||||
@tracked isStaff = this.currentUser && this.currentUser.staff;
|
||||
|
||||
@tracked vote = this.args.attrs.vote || [];
|
||||
@tracked titleHTML = htmlSafe(this.args.attrs.titleHTML);
|
||||
@tracked topicArchived = this.args.attrs.post.get("topic.archived");
|
||||
@tracked options = [];
|
||||
@tracked poll = this.args.attrs.poll;
|
||||
@tracked voters = this.poll.voters || 0;
|
||||
@tracked preloadedVoters = this.args.preloadedVoters || [];
|
||||
@tracked isRankedChoice = this.poll.type === RANKED_CHOICE;
|
||||
@tracked rankedChoiceOutcome = this.poll.ranked_choice_outcome || [];
|
||||
@tracked isMultiVoteType = this.isRankedChoice || this.isMultiple;
|
||||
@tracked staffOnly = this.poll.results === STAFF_ONLY;
|
||||
@tracked isMultiple = this.poll.type === MULTIPLE;
|
||||
@tracked isNumber = this.poll.type === NUMBER;
|
||||
@tracked showingResults = false;
|
||||
@tracked preloadedVoters = this.defaultPreloadedVoters();
|
||||
@tracked hasSavedVote = this.args.attrs.hasSavedVote;
|
||||
@tracked status = this.poll.status;
|
||||
|
||||
@tracked
|
||||
showResults =
|
||||
this.hasSavedVote ||
|
||||
this.showingResults ||
|
||||
(this.topicArchived && !this.staffOnly) ||
|
||||
(this.closed && !this.staffOnly);
|
||||
post = this.args.attrs.post;
|
||||
isMe =
|
||||
this.currentUser && this.args.attrs.post.user_id === this.currentUser.id;
|
||||
|
||||
checkUserGroups = (user, poll) => {
|
||||
const pollGroups =
|
||||
|
@ -75,59 +61,7 @@ export default class PollComponent extends Component {
|
|||
|
||||
return userGroups && pollGroups.some((g) => userGroups.includes(g));
|
||||
};
|
||||
castVotes = (option) => {
|
||||
if (!this.canCastVotes) {
|
||||
return;
|
||||
}
|
||||
if (!this.currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ajax("/polls/vote", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
post_id: this.args.attrs.post.id,
|
||||
poll_name: this.poll.name,
|
||||
options: this.vote,
|
||||
},
|
||||
})
|
||||
.then(({ poll }) => {
|
||||
this.options = [...poll.options];
|
||||
this.hasSavedVote = true;
|
||||
this.rankedChoiceOutcome = poll.ranked_choice_outcome || [];
|
||||
this.poll.setProperties(poll);
|
||||
this.appEvents.trigger(
|
||||
"poll:voted",
|
||||
poll,
|
||||
this.args.attrs.post,
|
||||
this.args.attrs.vote
|
||||
);
|
||||
|
||||
const voters = poll.voters;
|
||||
this.voters = [Number(voters)][0];
|
||||
|
||||
if (this.poll.results !== "on_close") {
|
||||
this.showResults = true;
|
||||
}
|
||||
if (this.poll.results === "staff_only") {
|
||||
if (this.currentUser && this.currentUser.staff) {
|
||||
this.showResults = true;
|
||||
} else {
|
||||
this.showResults = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error) {
|
||||
if (!this.isMultiple && !this.isRankedChoice) {
|
||||
this._toggleOption(option);
|
||||
}
|
||||
popupAjaxError(error);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("poll.error_while_casting_votes"));
|
||||
}
|
||||
});
|
||||
};
|
||||
areRanksValid = (arr) => {
|
||||
let ranks = new Set(); // Using a Set to keep track of unique ranks
|
||||
let hasNonZeroDuplicate = false;
|
||||
|
@ -146,76 +80,188 @@ export default class PollComponent extends Component {
|
|||
|
||||
return !hasNonZeroDuplicate;
|
||||
};
|
||||
_toggleOption = (option, rank = 0) => {
|
||||
let options = this.options;
|
||||
let vote = this.vote;
|
||||
|
||||
_toggleOption = (option, rank = 0) => {
|
||||
if (this.isMultiple) {
|
||||
const chosenIdx = vote.indexOf(option.id);
|
||||
const chosenIdx = this.vote.indexOf(option.id);
|
||||
|
||||
if (chosenIdx !== -1) {
|
||||
vote.splice(chosenIdx, 1);
|
||||
this.vote.splice(chosenIdx, 1);
|
||||
} else {
|
||||
vote.push(option.id);
|
||||
this.vote.push(option.id);
|
||||
}
|
||||
} else if (this.isRankedChoice) {
|
||||
options.forEach((candidate, i) => {
|
||||
const chosenIdx = vote.findIndex(
|
||||
this.options.forEach((candidate) => {
|
||||
const chosenIdx = this.vote.findIndex(
|
||||
(object) => object.digest === candidate.id
|
||||
);
|
||||
|
||||
if (chosenIdx === -1) {
|
||||
vote.push({
|
||||
this.vote.push({
|
||||
digest: candidate.id,
|
||||
rank: candidate.id === option ? rank : 0,
|
||||
});
|
||||
} else {
|
||||
if (candidate.id === option) {
|
||||
vote[chosenIdx].rank = rank;
|
||||
options[i].rank = rank;
|
||||
this.vote[chosenIdx].rank = rank;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
vote = [option.id];
|
||||
this.vote = [option.id];
|
||||
}
|
||||
|
||||
this.vote = [...vote];
|
||||
this.options = [...options];
|
||||
this.vote = [...this.vote];
|
||||
};
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.id = this.args.attrs.id;
|
||||
this.post = this.args.attrs.post;
|
||||
this.options = this.poll.options;
|
||||
this.groupableUserFields = this.args.attrs.groupableUserFields;
|
||||
this.rankedChoiceDropdownContent = [];
|
||||
|
||||
if (this.isRankedChoice) {
|
||||
this.rankedChoiceDropdownContent.push({
|
||||
id: 0,
|
||||
name: I18n.t("poll.options.ranked_choice.abstain"),
|
||||
defaultPreloadedVoters() {
|
||||
const preloadedVoters = {};
|
||||
|
||||
if (this.poll.public && this.args.preloadedVoters) {
|
||||
Object.keys(this.args.preloadedVoters).forEach((key) => {
|
||||
preloadedVoters[key] = {
|
||||
voters: this.args.preloadedVoters[key],
|
||||
loading: false,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
this.options.forEach((option, i) => {
|
||||
option.rank = 0;
|
||||
if (this.isRankedChoice) {
|
||||
this.rankedChoiceDropdownContent.push({
|
||||
id: i + 1,
|
||||
name: (i + 1).toString(),
|
||||
});
|
||||
this.args.attrs.vote.forEach((vote) => {
|
||||
if (vote.digest === option.id) {
|
||||
option.rank = vote.rank;
|
||||
}
|
||||
});
|
||||
this.options.forEach((option) => {
|
||||
if (!preloadedVoters[option.id]) {
|
||||
preloadedVoters[option.id] = {
|
||||
voters: [],
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return preloadedVoters;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.args.attrs.id;
|
||||
}
|
||||
|
||||
get post() {
|
||||
return this.args.attrs.post;
|
||||
}
|
||||
|
||||
get groupableUserFields() {
|
||||
return this.args.attrs.groupableUserFields;
|
||||
}
|
||||
|
||||
get isStaff() {
|
||||
return this.currentUser?.staff;
|
||||
}
|
||||
|
||||
get titleHTML() {
|
||||
return htmlSafe(this.args.attrs.titleHTML);
|
||||
}
|
||||
|
||||
get topicArchived() {
|
||||
return this.post.get("topic.archived");
|
||||
}
|
||||
|
||||
get isRankedChoice() {
|
||||
return this.poll.type === RANKED_CHOICE;
|
||||
}
|
||||
|
||||
get staffOnly() {
|
||||
return this.poll.results === STAFF_ONLY;
|
||||
}
|
||||
|
||||
get isMultiple() {
|
||||
return this.poll.type === MULTIPLE;
|
||||
}
|
||||
|
||||
get isNumber() {
|
||||
return this.poll.type === NUMBER;
|
||||
}
|
||||
|
||||
get isMe() {
|
||||
return this.currentUser && this.post.user_id === this.currentUser.id;
|
||||
}
|
||||
|
||||
get status() {
|
||||
return this.poll.get("status");
|
||||
}
|
||||
|
||||
@action
|
||||
async castVotes(option) {
|
||||
if (!this.canCastVotes) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.currentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const poll = await ajax("/polls/vote", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
post_id: this.post.id,
|
||||
poll_name: this.poll.name,
|
||||
options: this.vote,
|
||||
},
|
||||
});
|
||||
|
||||
this.hasSavedVote = true;
|
||||
this.poll.setProperties(poll);
|
||||
this.appEvents.trigger("poll:voted", poll, this.post, this.vote);
|
||||
|
||||
if (this.poll.results !== ON_CLOSE) {
|
||||
this.showResults = true;
|
||||
}
|
||||
|
||||
if (this.poll.results === STAFF_ONLY) {
|
||||
if (this.currentUser && this.currentUser.staff) {
|
||||
this.showResults = true;
|
||||
} else {
|
||||
this.showResults = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error) {
|
||||
if (!this.isMultiple && !this.isRankedChoice) {
|
||||
this._toggleOption(option);
|
||||
}
|
||||
popupAjaxError(error);
|
||||
} else {
|
||||
this.dialog.alert(I18n.t("poll.error_while_casting_votes"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get options() {
|
||||
let enrichedOptions = this.poll.get("options");
|
||||
|
||||
if (this.isRankedChoice) {
|
||||
enrichedOptions.forEach((candidate) => {
|
||||
const chosenIdx = this.vote.findIndex(
|
||||
(object) => object.digest === candidate.id
|
||||
);
|
||||
if (chosenIdx === -1) {
|
||||
candidate.rank = 0;
|
||||
} else {
|
||||
candidate.rank = this.vote[chosenIdx].rank;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return enrichedOptions;
|
||||
}
|
||||
|
||||
get voters() {
|
||||
return this.poll.get("voters");
|
||||
}
|
||||
|
||||
get rankedChoiceOutcome() {
|
||||
return this.poll.get("ranked_choice_outcome") || [];
|
||||
}
|
||||
|
||||
get min() {
|
||||
let min = parseInt(this.args.attrs.poll.min, 10);
|
||||
let min = parseInt(this.poll.min, 10);
|
||||
if (isNaN(min) || min < 0) {
|
||||
min = 1;
|
||||
}
|
||||
|
@ -224,8 +270,8 @@ export default class PollComponent extends Component {
|
|||
}
|
||||
|
||||
get max() {
|
||||
let max = parseInt(this.args.attrs.poll.max, 10);
|
||||
const numOptions = this.args.attrs.poll.options.length;
|
||||
let max = parseInt(this.poll.max, 10);
|
||||
const numOptions = this.poll.options.length;
|
||||
if (isNaN(max) || max > numOptions) {
|
||||
max = numOptions;
|
||||
}
|
||||
|
@ -233,19 +279,37 @@ export default class PollComponent extends Component {
|
|||
}
|
||||
|
||||
get closed() {
|
||||
return this.status === "closed" || this.isAutomaticallyClosed;
|
||||
return this.status === CLOSED_STATUS || this.isAutomaticallyClosed;
|
||||
}
|
||||
|
||||
get rankedChoiceDropdownContent() {
|
||||
let rankedChoiceDropdownContent = [];
|
||||
|
||||
rankedChoiceDropdownContent.push({
|
||||
id: 0,
|
||||
name: I18n.t("poll.options.ranked_choice.abstain"),
|
||||
});
|
||||
|
||||
this.poll.options.forEach((option, i) => {
|
||||
option.rank = 0;
|
||||
rankedChoiceDropdownContent.push({
|
||||
id: i + 1,
|
||||
name: (i + 1).toString(),
|
||||
});
|
||||
});
|
||||
|
||||
return rankedChoiceDropdownContent;
|
||||
}
|
||||
|
||||
get isAutomaticallyClosed() {
|
||||
const poll = this.poll;
|
||||
return (
|
||||
(poll.close ?? false) &&
|
||||
moment.utc(poll.close, "YYYY-MM-DD HH:mm:ss Z") <= moment()
|
||||
(this.poll.close ?? false) &&
|
||||
moment.utc(this.poll.close, "YYYY-MM-DD HH:mm:ss Z") <= moment()
|
||||
);
|
||||
}
|
||||
|
||||
get hasVoted() {
|
||||
return this.vote && this.vote.length > 0;
|
||||
return this.vote?.length > 0;
|
||||
}
|
||||
|
||||
get hideResultsDisabled() {
|
||||
|
@ -257,10 +321,12 @@ export default class PollComponent extends Component {
|
|||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.currentUser) {
|
||||
// unlikely, handled by template logic
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.checkUserGroups(this.currentUser, this.poll)) {
|
||||
return;
|
||||
}
|
||||
|
@ -287,12 +353,11 @@ export default class PollComponent extends Component {
|
|||
|
||||
@action
|
||||
toggleResults() {
|
||||
const showResults = !this.showResults;
|
||||
this.showResults = showResults;
|
||||
this.showResults = !this.showResults;
|
||||
}
|
||||
|
||||
get canCastVotes() {
|
||||
if (this.closed || this.showingResults || !this.currentUser) {
|
||||
if (this.closed || !this.currentUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -304,7 +369,7 @@ export default class PollComponent extends Component {
|
|||
|
||||
if (this.isRankedChoice) {
|
||||
return (
|
||||
this.options.length === this.vote.length &&
|
||||
this.options.length === this.vote?.length &&
|
||||
this.areRanksValid(this.vote)
|
||||
);
|
||||
}
|
||||
|
@ -363,11 +428,7 @@ export default class PollComponent extends Component {
|
|||
}
|
||||
|
||||
get isCheckbox() {
|
||||
if (this.isMultiple) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return this.isMultiple;
|
||||
}
|
||||
|
||||
get resultsWidgetTypeClass() {
|
||||
|
@ -393,26 +454,21 @@ export default class PollComponent extends Component {
|
|||
|
||||
@action
|
||||
updatedVoters() {
|
||||
this.preloadedVoters = this.args.preloadedVoters;
|
||||
this.options = [...this.args.options];
|
||||
if (this.isRankedChoice) {
|
||||
this.options.forEach((candidate) => {
|
||||
let specificVote = this.vote.find(
|
||||
(vote) => vote.digest === candidate.id
|
||||
);
|
||||
let rank = specificVote ? specificVote.rank : 0;
|
||||
candidate.rank = rank;
|
||||
});
|
||||
}
|
||||
this.preloadedVoters = this.defaultPreloadedVoters();
|
||||
}
|
||||
|
||||
@action
|
||||
fetchVoters(optionId) {
|
||||
let votersCount;
|
||||
this.loading = true;
|
||||
let options = this.options;
|
||||
options.find((option) => option.id === optionId).loading = true;
|
||||
this.options = [...options];
|
||||
let preloadedVoters = this.preloadedVoters;
|
||||
|
||||
Object.keys(preloadedVoters).forEach((key) => {
|
||||
if (key === optionId) {
|
||||
preloadedVoters[key].loading = true;
|
||||
}
|
||||
});
|
||||
|
||||
this.preloadedVoters = Object.assign(preloadedVoters);
|
||||
|
||||
votersCount = this.options.find((option) => option.id === optionId).votes;
|
||||
|
||||
|
@ -427,7 +483,7 @@ export default class PollComponent extends Component {
|
|||
})
|
||||
.then((result) => {
|
||||
const voters = optionId
|
||||
? this.preloadedVoters[optionId]
|
||||
? this.preloadedVoters[optionId].voters
|
||||
: this.preloadedVoters;
|
||||
const newVoters = optionId ? result.voters[optionId] : result.voters;
|
||||
if (this.isRankedChoice) {
|
||||
|
@ -444,16 +500,14 @@ export default class PollComponent extends Component {
|
|||
if (this.poll.type === REGULAR) {
|
||||
Object.keys(this.preloadedVoters).forEach((otherOptionId) => {
|
||||
if (optionId !== otherOptionId) {
|
||||
this.preloadedVoters[otherOptionId] = this.preloadedVoters[
|
||||
otherOptionId
|
||||
].filter((voter) => !votersSet.has(voter.username));
|
||||
this.preloadedVoters[otherOptionId].voters =
|
||||
this.preloadedVoters[otherOptionId].voters.filter(
|
||||
(voter) => !votersSet.has(voter.username)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.preloadedVoters[optionId] = [
|
||||
...new Set([...this.preloadedVoters[optionId], ...newVoters]),
|
||||
];
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error) {
|
||||
|
@ -463,8 +517,9 @@ export default class PollComponent extends Component {
|
|||
}
|
||||
})
|
||||
.finally(() => {
|
||||
options.find((option) => option.id === optionId).loading = false;
|
||||
this.options = [...options];
|
||||
preloadedVoters = this.preloadedVoters;
|
||||
preloadedVoters[optionId].loading = false;
|
||||
this.preloadedVoters = Object.assign(preloadedVoters);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -488,13 +543,10 @@ export default class PollComponent extends Component {
|
|||
option.rank = 0;
|
||||
});
|
||||
}
|
||||
this.options = [...poll.options];
|
||||
this.poll.setProperties(poll);
|
||||
this.rankedChoiceOutcome = poll.ranked_choice_outcome || [];
|
||||
this.vote = [];
|
||||
this.voters = poll.voters;
|
||||
this.vote = Object.assign([]);
|
||||
this.hasSavedVote = false;
|
||||
this.appEvents.trigger("poll:voted", poll, this.post, this.vote);
|
||||
this.showResults = false;
|
||||
})
|
||||
.catch((error) => popupAjaxError(error));
|
||||
}
|
||||
|
@ -508,7 +560,7 @@ export default class PollComponent extends Component {
|
|||
this.dialog.yesNoConfirm({
|
||||
message: I18n.t(this.closed ? "poll.open.confirm" : "poll.close.confirm"),
|
||||
didConfirm: () => {
|
||||
const status = this.closed ? "open" : "closed";
|
||||
const status = this.closed ? OPEN_STATUS : CLOSED_STATUS;
|
||||
ajax("/polls/toggle_status", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
|
@ -518,13 +570,13 @@ export default class PollComponent extends Component {
|
|||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.poll.status = status;
|
||||
this.status = status;
|
||||
this.poll.set("status", status);
|
||||
|
||||
if (
|
||||
this.poll.results === "on_close" ||
|
||||
this.poll.results === ON_CLOSE ||
|
||||
this.poll.results === "always"
|
||||
) {
|
||||
this.showResults = this.status === "closed";
|
||||
this.showResults = this.status === CLOSED_STATUS;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
|
|
|
@ -25,11 +25,10 @@ export default createWidget("discourse-poll", {
|
|||
new RenderGlimmer(
|
||||
this,
|
||||
"div.poll",
|
||||
hbs`<Poll @attrs={{@data.attrs}} @preloadedVoters={{@data.preloadedVoters}} @options={{@data.options}} />`,
|
||||
hbs`<Poll @attrs={{@data.attrs}} @preloadedVoters={{@data.preloadedVoters}} />`,
|
||||
{
|
||||
attrs,
|
||||
preloadedVoters: attrs.poll.preloaded_voters,
|
||||
options: attrs.poll.options,
|
||||
}
|
||||
),
|
||||
];
|
||||
|
|
|
@ -46,6 +46,46 @@ module("Poll | Component | poll", function (hooks) {
|
|||
});
|
||||
});
|
||||
|
||||
test("shows vote", async function (assert) {
|
||||
this.setProperties({
|
||||
attributes: EmberObject.create({
|
||||
post: EmberObject.create({
|
||||
id: 42,
|
||||
topic: {
|
||||
archived: false,
|
||||
},
|
||||
user_id: 29,
|
||||
}),
|
||||
poll: EmberObject.create({
|
||||
name: "poll",
|
||||
type: "regular",
|
||||
status: "closed",
|
||||
results: "always",
|
||||
options: [
|
||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 1 },
|
||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||
],
|
||||
voters: 1,
|
||||
chart_type: "bar",
|
||||
}),
|
||||
vote: [],
|
||||
groupableUserFields: [],
|
||||
}),
|
||||
preloadedVoters: [],
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
Array.from(queryAll(".results li .option p")).map(
|
||||
(span) => span.innerText
|
||||
),
|
||||
["100% yes", "0% no"]
|
||||
);
|
||||
});
|
||||
|
||||
test("can vote", async function (assert) {
|
||||
this.setProperties({
|
||||
attributes: EmberObject.create({
|
||||
|
@ -72,14 +112,10 @@ module("Poll | Component | poll", function (hooks) {
|
|||
groupableUserFields: [],
|
||||
}),
|
||||
preloadedVoters: [],
|
||||
options: [
|
||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||
],
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} @options={{this.options}} />`
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
||||
);
|
||||
|
||||
requests = 0;
|
||||
|
@ -89,10 +125,6 @@ module("Poll | Component | poll", function (hooks) {
|
|||
);
|
||||
assert.strictEqual(requests, 1);
|
||||
assert.strictEqual(count(".chosen"), 1);
|
||||
assert.deepEqual(
|
||||
Array.from(queryAll(".chosen span")).map((span) => span.innerText),
|
||||
["100%", "yes"]
|
||||
);
|
||||
|
||||
await click(".toggle-results");
|
||||
assert.strictEqual(
|
||||
|
@ -128,14 +160,10 @@ module("Poll | Component | poll", function (hooks) {
|
|||
groupableUserFields: [],
|
||||
}),
|
||||
preloadedVoters: [],
|
||||
options: [
|
||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||
],
|
||||
});
|
||||
|
||||
await render(
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} @options={{this.options}} />`
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
||||
);
|
||||
|
||||
requests = 0;
|
||||
|
@ -178,13 +206,9 @@ module("Poll | Component | poll", function (hooks) {
|
|||
groupableUserFields: [],
|
||||
}),
|
||||
preloadedVoters: [],
|
||||
options: [
|
||||
{ id: "1f972d1df351de3ce35a787c89faad29", html: "yes", votes: 0 },
|
||||
{ id: "d7ebc3a9beea2e680815a1e4f57d6db6", html: "no", votes: 0 },
|
||||
],
|
||||
});
|
||||
await render(
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} @options={{this.options}} />`
|
||||
hbs`<Poll @attrs={{this.attributes}} @preloadedVoters={{this.preloadedVoters}} />`
|
||||
);
|
||||
|
||||
assert.ok(exists(".poll-buttons .cast-votes:disabled"));
|
||||
|
|
Loading…
Reference in New Issue
Block a user