FIX: poll ranked choice results not showing on first vote (#28542)

Currently (for Ranked Choice only) a javascript exception is raised on very first vote, preventing the results from being rendered requiring a browser refresh (which doesn't error).

Resolves: TypeError: this.args.rankedChoiceOutcome.round_activity is undefined with simple addition of optional chaining operator.
This commit is contained in:
Robert 2024-11-05 01:29:07 +00:00 committed by GitHub
parent 40a4d55c77
commit 1aa836163e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 38 deletions

View File

@ -7,15 +7,15 @@ export default class PollResultsRankedChoiceComponent extends Component {
get rankedChoiceWinnerText() { get rankedChoiceWinnerText() {
return htmlSafe( return htmlSafe(
I18n.t("poll.ranked_choice.winner", { I18n.t("poll.ranked_choice.winner", {
count: this.args.rankedChoiceOutcome.round_activity.length, count: this.args.rankedChoiceOutcome?.round_activity?.length,
winner: this.args.rankedChoiceOutcome.winning_candidate.html, winner: this.args.rankedChoiceOutcome?.winning_candidate?.html,
}) })
); );
} }
get rankedChoiceTiedText() { get rankedChoiceTiedText() {
return I18n.t("poll.ranked_choice.tied", { return I18n.t("poll.ranked_choice.tied", {
count: this.args.rankedChoiceOutcome.round_activity.length, count: this.args.rankedChoiceOutcome?.round_activity?.length,
}); });
} }
@ -32,45 +32,49 @@ export default class PollResultsRankedChoiceComponent extends Component {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{#each @rankedChoiceOutcome.round_activity as |round|}} {{#if @rankedChoiceOutcome}}
{{#if round.majority}} {{#each @rankedChoiceOutcome.round_activity as |round|}}
<tr> {{#if round.majority}}
<td>{{round.round}}</td> <tr>
<td>{{htmlSafe round.majority.html}}</td> <td>{{round.round}}</td>
<td>{{i18n "poll.ranked_choice.none"}}</td> <td>{{htmlSafe round.majority.html}}</td>
</tr> <td>{{i18n "poll.ranked_choice.none"}}</td>
{{else}} </tr>
<tr> {{else}}
<td>{{round.round}}</td> <tr>
<td>{{i18n "poll.ranked_choice.none"}}</td> <td>{{round.round}}</td>
<td> <td>{{i18n "poll.ranked_choice.none"}}</td>
{{#each round.eliminated as |eliminated|}} <td>
{{htmlSafe eliminated.html}} {{#each round.eliminated as |eliminated|}}
{{/each}} {{htmlSafe eliminated.html}}
</td> {{/each}}
</tr> </td>
{{/if}} </tr>
{{/each}} {{/if}}
{{/each}}
{{/if}}
</tbody> </tbody>
</table> </table>
<h3 class="poll-results-ranked-choice-subtitle-outcome"> <h3 class="poll-results-ranked-choice-subtitle-outcome">
{{i18n "poll.ranked_choice.title.outcome"}} {{i18n "poll.ranked_choice.title.outcome"}}
</h3> </h3>
{{#if @rankedChoiceOutcome.tied}} {{#if @rankedChoiceOutcome}}
<span {{#if @rankedChoiceOutcome.tied}}
class="poll-results-ranked-choice-info" <span
>{{this.rankedChoiceTiedText}}</span> class="poll-results-ranked-choice-info"
<ul class="poll-results-ranked-choice-tied-candidates"> >{{this.rankedChoiceTiedText}}</span>
{{#each @rankedChoiceOutcome.tied_candidates as |tied_candidate|}} <ul class="poll-results-ranked-choice-tied-candidates">
<li class="poll-results-ranked-choice-tied-candidate">{{htmlSafe {{#each @rankedChoiceOutcome.tied_candidates as |tied_candidate|}}
tied_candidate.html <li class="poll-results-ranked-choice-tied-candidate">{{htmlSafe
}}</li> tied_candidate.html
{{/each}} }}</li>
</ul> {{/each}}
{{else}} </ul>
<span {{else}}
class="poll-results-ranked-choice-info" <span
>{{this.rankedChoiceWinnerText}}</span> class="poll-results-ranked-choice-info"
>{{this.rankedChoiceWinnerText}}</span>
{{/if}}
{{/if}} {{/if}}
</template> </template>
} }

View File

@ -272,7 +272,7 @@ export default class PollComponent extends Component {
} }
get rankedChoiceOutcome() { get rankedChoiceOutcome() {
return this.poll.ranked_choice_outcome || []; return this.poll.ranked_choice_outcome || null;
} }
get min() { get min() {

View File

@ -58,4 +58,18 @@ module("Poll | Component | poll-results-ranked-choice", function (hooks) {
"displays the winner information" "displays the winner information"
); );
}); });
test("Renders the ranked choice results component without error when outcome data is empty", async function (assert) {
this.rankedChoiceOutcome = null;
await render(
hbs`<PollResultsRankedChoice @rankedChoiceOutcome={{this.rankedChoiceOutcome}} />`
);
assert.strictEqual(
count("table.poll-results-ranked-choice tr"),
1,
"there are no rounds of ranked choice displayed, only the header"
);
});
}); });