diff --git a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.html b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.html index d43106454..2fd0afa15 100644 --- a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.html +++ b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.html @@ -1,5 +1,5 @@ - +

{{ pollHint }} @@ -9,9 +9,7 @@

{{ 'Available votes' | translate }}: - - {{ getVotesAvailable() }}/{{ poll.votes_amount }} - + {{ getVotesAvailable() }}/{{ poll.votes_amount }}

@@ -39,6 +37,7 @@ class="vote-button" mat-raised-button (click)="saveSingleVote(option.id, action.vote)" + [disabled]="deliveringVote" [ngClass]=" voteRequestData.votes[option.id] === action.vote || voteRequestData.votes[option.id] === 1 @@ -67,6 +66,7 @@ mat-raised-button (click)="saveGlobalVote('N')" [ngClass]="voteRequestData.global === 'N' ? 'voted-no' : ''" + [disabled]="deliveringVote" > thumb_down @@ -103,13 +103,19 @@
-
+

{{ 'Voting successful.' | translate }}
+ +
+ +
+ {{ 'Delivering vote... Please wait!' | translate }} +
diff --git a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.scss b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.scss index 18a1aa6c8..9939b32d3 100644 --- a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.scss +++ b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.scss @@ -67,3 +67,10 @@ .mat-divider-horizontal { position: initial; } + +.submit-vote-indicator { + text-align: center; + .mat-spinner { + margin: auto; + } +} diff --git a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts index 35387487c..dbd06fb54 100644 --- a/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts +++ b/client/src/app/site/assignments/components/assignment-poll-vote/assignment-poll-vote.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Title } from '@angular/platform-browser'; @@ -29,7 +29,8 @@ interface VoteActions { @Component({ selector: 'os-assignment-poll-vote', templateUrl: './assignment-poll-vote.component.html', - styleUrls: ['./assignment-poll-vote.component.scss'] + styleUrls: ['./assignment-poll-vote.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class AssignmentPollVoteComponent extends BasePollVoteComponent implements OnInit { public AssignmentPollMethod = AssignmentPollMethod; @@ -47,7 +48,8 @@ export class AssignmentPollVoteComponent extends BasePollVoteComponent { const title = this.translate.instant('Submit selection now?'); const content = this.translate.instant('Your decision cannot be changed afterwards.'); - this.promptService.open(title, content).then(confirmed => { - if (confirmed) { - this.pollRepo - .vote(this.voteRequestData, this.poll.id) - .then(() => { - this.alreadyVoted = true; - }) - .catch(this.raiseError); - } - }); + const confirmed = await this.promptService.open(title, content); + if (confirmed) { + this.deliveringVote = true; + this.cd.markForCheck(); + this.pollRepo + .vote(this.voteRequestData, this.poll.id) + .then(() => { + this.alreadyVoted = true; + }) + .catch(this.raiseError) + .finally(() => { + this.deliveringVote = false; + }); + } } public saveSingleVote(optionId: number, vote: VoteValue): void { diff --git a/client/src/app/site/assignments/components/assignment-poll/assignment-poll.component.html b/client/src/app/site/assignments/components/assignment-poll/assignment-poll.component.html index 52de11025..ba7e7fec9 100644 --- a/client/src/app/site/assignments/components/assignment-poll/assignment-poll.component.html +++ b/client/src/app/site/assignments/components/assignment-poll/assignment-poll.component.html @@ -42,10 +42,16 @@ mat-stroked-button [ngClass]="pollStateActions[poll.state].css" (click)="changeState(poll.nextState)" + [disabled]="stateChangePending" > {{ pollStateActions[poll.state].icon }} - {{ poll.nextStateActionVerbose | translate }} + + {{ poll.nextStateActionVerbose | translate }} + + + {{ 'In progress, please wait...' | translate }} +
diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.html b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.html index d80d051a0..35559d1cf 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.html +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.html @@ -2,19 +2,26 @@ -
+
{{ option.label | translate }}
+ +
+ +
+ {{ 'Delivering vote... Please wait!' | translate }} +
diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.scss b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.scss index d13eb0a9c..9f976137d 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.scss +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.scss @@ -8,6 +8,14 @@ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); } +.submit-vote-indicator { + margin-top: 1em; + text-align: center; + .mat-spinner { + margin: auto; + } +} + .vote-button { display: inline-grid; grid-gap: 1em; diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.ts b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.ts index 99095e0c0..5bee50ed2 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.ts +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll-vote/motion-poll-vote.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Title } from '@angular/platform-browser'; @@ -22,7 +22,8 @@ interface VoteOption { @Component({ selector: 'os-motion-poll-vote', templateUrl: './motion-poll-vote.component.html', - styleUrls: ['./motion-poll-vote.component.scss'] + styleUrls: ['./motion-poll-vote.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush }) export class MotionPollVoteComponent extends BasePollVoteComponent { public currentVote: VoteOption = {}; @@ -54,19 +55,28 @@ export class MotionPollVoteComponent extends BasePollVoteComponent { this.currentVote.vote = vote; const title = this.translate.instant('Submit selection now?'); const content = this.translate.instant('Your decision cannot be changed afterwards.'); - this.promptService.open(title, content).then(confirmed => { - if (confirmed) { - this.pollRepo.vote(vote, this.poll.id).catch(this.raiseError); - } - }); + const confirmed = await this.promptService.open(title, content); + + if (confirmed) { + this.deliveringVote = true; + this.cd.markForCheck(); + + this.pollRepo + .vote(vote, this.poll.id) + .catch(this.raiseError) + .finally(() => { + this.deliveringVote = false; + }); + } } } diff --git a/client/src/app/site/motions/modules/motion-poll/motion-poll/motion-poll.component.html b/client/src/app/site/motions/modules/motion-poll/motion-poll/motion-poll.component.html index 75ab8b8ad..4ee58bb67 100644 --- a/client/src/app/site/motions/modules/motion-poll/motion-poll/motion-poll.component.html +++ b/client/src/app/site/motions/modules/motion-poll/motion-poll/motion-poll.component.html @@ -42,10 +42,15 @@
-
diff --git a/client/src/app/site/polls/components/base-poll-vote.component.ts b/client/src/app/site/polls/components/base-poll-vote.component.ts index 95d8aa41f..108a93dc4 100644 --- a/client/src/app/site/polls/components/base-poll-vote.component.ts +++ b/client/src/app/site/polls/components/base-poll-vote.component.ts @@ -16,6 +16,8 @@ export abstract class BasePollVoteComponent extends Base public votingErrors = VotingError; + public deliveringVote = false; + protected user: ViewUser; public constructor( diff --git a/client/src/app/site/polls/components/base-poll.component.ts b/client/src/app/site/polls/components/base-poll.component.ts index 6ad7220ef..52d5a40ad 100644 --- a/client/src/app/site/polls/components/base-poll.component.ts +++ b/client/src/app/site/polls/components/base-poll.component.ts @@ -15,6 +15,8 @@ import { PollService } from '../services/poll.service'; import { ViewBasePoll } from '../models/view-base-poll'; export abstract class BasePollComponent extends BaseViewComponent { + public stateChangePending = false; + public chartDataSubject: BehaviorSubject = new BehaviorSubject([]); protected _poll: V; @@ -55,10 +57,22 @@ export abstract class BasePollComponent { + this.stateChangePending = false; + }); } } else { - this.repo.changePollState(this._poll).catch(this.raiseError); + this.stateChangePending = true; + this.repo + .changePollState(this._poll) + .catch(this.raiseError) + .finally(() => { + this.stateChangePending = false; + }); } } diff --git a/client/src/styles.scss b/client/src/styles.scss index 88e3415b5..37d6a1824 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -778,6 +778,17 @@ button.mat-menu-item.selected { display: none !important; /* hide scrollbars in webkit browsers */ } +.small-spinner { + // 24px is the size of a normal icon + $spinner-size: 24px; + height: $spinner-size !important; + height: $spinner-size !important; + svg { + height: $spinner-size !important; + height: $spinner-size !important; + } +} + .import-table { .table-container { width: 100%;