Added reset button

This commit is contained in:
Jim Martens 2023-08-12 13:01:27 +02:00
parent d4d7c9de99
commit 800b7536e8
10 changed files with 135 additions and 46 deletions

View File

@ -8,7 +8,8 @@
<ng-container *ngIf="(viewModel$ | async) as data; else spinner">
<app-election [viewModel]="data" (valueChanges)="onValueChanges($event)"
[electedCandidates]="electedCandidates$ | async"
(calculate)="onCalculate($event)"></app-election>
(calculate)="onCalculate($event)"
(reset)="onReset()"></app-election>
</ng-container>
</div>
</div>

View File

@ -11,7 +11,7 @@ import {
loadElectionResultAction,
loadPartiesAction,
loadSingleElectionAction,
modifyElectionResultAction
modifyElectionResultAction, resetElectionResult
} from "../store/elections.actions";
import {DEFAULT_RESULT, ElectionResult} from "../model/election-result";
import {FormElectionResult} from "../model/form-election-result";
@ -111,4 +111,8 @@ export class ElectionContainerComponent implements OnInit {
onCalculate(event: ElectionResult) {
this.store.dispatch(calculateAction({payload: event}));
}
onReset() {
this.store.dispatch(resetElectionResult());
}
}

View File

@ -2,11 +2,14 @@
<app-election-result [electedCandidates]="electedCandidates" [parties]="viewModel.parties"></app-election-result>
<button class="mt-2" mat-raised-button i18n #calculateButton (keyup.enter)="onCalculate()" (click)="onCalculate()">
<mat-spinner class="spinner" *ngIf="showSpinner"></mat-spinner>
Calculate
</button>
<div class="row">
<button class="mt-2" mat-raised-button i18n="@@button.calculate" #calculateButton (keyup.enter)="onCalculate()" (click)="onCalculate()">
<mat-spinner class="spinner" *ngIf="showSpinner"></mat-spinner>
Calculate
</button>
<button class="mt-2" mat-raised-button i18n="@@button.reset" (keyup.enter)="onReset()" (click)="onReset()">Reset</button>
</div>
<form [formGroup]="form">
<mat-tab-group>

View File

@ -9,3 +9,7 @@
.mt-2 {
margin-top: 2em;
}
.row {
@include mixins.justifyContent(space-between);
}

View File

@ -14,7 +14,7 @@ import {ElectionResult} from "../model/election-result";
import {FormElectionResult} from "../model/form-election-result";
import {ElectedCandidates} from "../model/elected-candidates";
import {mapConstituencyResultsForm, mapOverallResultsForm} from "../store/elections.reducer";
import {debounceTime, distinctUntilChanged} from "rxjs";
import {debounceTime, distinctUntilChanged, filter} from "rxjs";
@Component({
selector: 'app-election',
@ -34,6 +34,8 @@ export class ElectionComponent implements OnInit {
readonly valueChanges: EventEmitter<FormElectionResult> = new EventEmitter<FormElectionResult>();
@Output()
readonly calculate: EventEmitter<ElectionResult> = new EventEmitter<ElectionResult>();
@Output()
readonly reset: EventEmitter<boolean> = new EventEmitter<boolean>();
constructor(private fb: FormBuilder) {
this.overallResults = this.fb.group({});
@ -82,6 +84,7 @@ export class ElectionComponent implements OnInit {
})
this.constituencyToId = constituencyToId;
this.constituencyNumberToName = constituencyNumberToName;
this.updateForm(data.electionResult);
}
ngOnInit() {
@ -133,6 +136,40 @@ export class ElectionComponent implements OnInit {
this.calculate.emit(electionResult);
}
onReset() {
this.reset.emit(true);
}
private updateForm(electionResult: ModifiedElectionResult) {
for (const votingResult of electionResult.overallResults) {
const formGroup = this.overallResults.get(votingResult.partyAbbreviation);
formGroup?.get('votesOnNomination')?.setValue(votingResult.votesOnNomination, { emitEvent: false });
formGroup?.get('votesThroughHealing')?.setValue(votingResult.votesThroughHealing, { emitEvent: false });
const votesPerPosition = formGroup?.get('votesPerPosition');
const {map, entries} = this.buildVotesPerPosition(votingResult);
for (const number of entries) {
votesPerPosition?.get(number)?.setValue(map.get(number) || 0, { emitEvent: false });
}
}
for (const constituencyNumber of electionResult.constituencyResults.keys()) {
const constituency = this.constituencyToId.get(+constituencyNumber);
const votingResults = electionResult.constituencyResults.get(constituencyNumber);
if (constituency == null || votingResults == null) {
continue;
}
const constituencyFormGroup = this.constituencyResults.get(constituency.name);
for (const votingResult of votingResults) {
const formGroup = constituencyFormGroup?.get(votingResult.partyAbbreviation);
const votesPerPosition = formGroup?.get('votesPerPosition');
for (const number in votingResult.votesPerPosition) {
votesPerPosition?.get(number)?.setValue(votingResult.votesPerPosition[number], { emitEvent: false });
}
}
}
}
private setUpForm(election: Election, electionResult: ModifiedElectionResult) {
this.overallResults = this.fb.group({});
this.constituencyResults = this.fb.group({});
@ -150,15 +187,7 @@ export class ElectionComponent implements OnInit {
partyAbbreviation: this.fb.control<string>(votingResult.partyAbbreviation),
nominationName: this.fb.control<string>(votingResult.nominationName),
});
const map = new Map<string, number>();
for (const number in votingResult.votesPerPosition) {
map.set(number, votingResult.votesPerPosition[number]);
}
const entries = [...map.entries()]
.sort((a, b) => {
return +a[0] - +b[0];
})
.map(entry => entry[0]);
const {map, entries} = this.buildVotesPerPosition(votingResult);
for (const number of entries) {
votesPerPosition.addControl(number, this.fb.control<number>(map.get(number) || 0));
}
@ -193,13 +222,14 @@ export class ElectionComponent implements OnInit {
}
this.form.valueChanges.pipe(
debounceTime(1000),
distinctUntilChanged()
distinctUntilChanged(),
).subscribe({
next: (value: {
overallResults: { [name: string]: VotingResult },
constituencyResults: { [name: string]: { [name: string]: VotingResult } }
}) => {
const modifiedValue: FormElectionResult = {...value,
const modifiedValue: FormElectionResult = {
...value,
constituencyResults: {}
};
for (const name in value.constituencyResults) {
@ -217,4 +247,17 @@ export class ElectionComponent implements OnInit {
}
});
}
private buildVotesPerPosition(votingResult: VotingResult) {
const map = new Map<string, number>();
for (const number in votingResult.votesPerPosition) {
map.set(number, votingResult.votesPerPosition[number]);
}
const entries = [...map.entries()]
.sort((a, b) => {
return +a[0] - +b[0];
})
.map(entry => entry[0]);
return {map, entries};
}
}

View File

@ -22,6 +22,8 @@ export enum ActionTypes {
Calculate = '[Elections] Calculate',
CalculateFinished = '[Elections] Calculate Finished',
ResetElectionResult = '[Elections] Reset Election Result',
}
export const loadAllElectionsAction = createAction(
@ -77,3 +79,7 @@ export const calculateFinishedAction = createAction(
ActionTypes.CalculateFinished,
props<{payload: ElectedCandidates}>()
);
export const resetElectionResult = createAction(
ActionTypes.ResetElectionResult
);

View File

@ -5,7 +5,7 @@ import {
loadElectionResultFinishedAction,
loadPartiesFinishedAction,
loadSingleElectionFinishedAction,
modifyElectionResultAction
modifyElectionResultAction, resetElectionResult
} from "./elections.actions";
import {createReducer, on} from "@ngrx/store";
import {DEFAULT_RESULT, ElectionResult} from "../model/election-result";
@ -73,7 +73,17 @@ export const electionsReducer = createReducer(
action) => ({
...state,
electedCandidates: {...action.payload}
}))
})),
on(resetElectionResult, (state, action) => ({
...state,
modifiedElectionResult: {
constituencyResults: mapConstituencyResults(state.originalElectionResult.constituencyResults),
electionName: state.originalElectionResult.electionName,
overallResults: state.originalElectionResult.overallResults.map(votingResult => {
return {...votingResult}
})
}
})),
);
function mapConstituencyResults(results: { [name: string]: VotingResult[] }): { [name: string]: VotingResult[] } {

View File

@ -202,14 +202,20 @@
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="1566538032864437775" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate
</source>
<target><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Berechne
</target>
<trans-unit id="button.calculate" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate </source>
<target><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Berechne </target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">6,8</context>
<context context-type="linenumber">7,9</context>
</context-group>
</trans-unit>
<trans-unit id="button.reset" datatype="html">
<source>Reset</source>
<target>Zurücksetzen</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit id="2620368114367873419" datatype="html">
@ -217,7 +223,7 @@
<target>Bezirksergebnisse</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">13</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="5278344113066375587" datatype="html">
@ -225,7 +231,7 @@
<target>Listenstimmen</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">23</context>
</context-group>
</trans-unit>
<trans-unit id="652158218369589359" datatype="html">
@ -233,7 +239,7 @@
<target>Stimmen durch Heilungsregel</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">25</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="4355395580941190554" datatype="html">
@ -241,7 +247,7 @@
<target>Wahlkreisergebnisse</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="8889535199141263248" datatype="html">

View File

@ -180,40 +180,46 @@
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="1566538032864437775" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate
</source>
<trans-unit id="button.calculate" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">6,8</context>
<context context-type="linenumber">7,9</context>
</context-group>
</trans-unit>
<trans-unit id="button.reset" datatype="html">
<source>Reset</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit id="2620368114367873419" datatype="html">
<source>Overall results</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">13</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="5278344113066375587" datatype="html">
<source>Votes on nomination</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">23</context>
</context-group>
</trans-unit>
<trans-unit id="652158218369589359" datatype="html">
<source>Votes through healing</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">25</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="4355395580941190554" datatype="html">
<source>Constituency results</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="8889535199141263248" datatype="html">

View File

@ -180,40 +180,46 @@
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="1566538032864437775" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate
</source>
<trans-unit id="button.calculate" datatype="html">
<source><x id="START_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;mat-spinner class=&quot;spinner&quot; *ngIf=&quot;showSpinner&quot;&gt;"/><x id="CLOSE_TAG_MAT_SPINNER" ctype="x-mat_spinner" equiv-text="&lt;/mat-spinner&gt;"/> Calculate </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">6,8</context>
<context context-type="linenumber">7,9</context>
</context-group>
</trans-unit>
<trans-unit id="button.reset" datatype="html">
<source>Reset</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit id="2620368114367873419" datatype="html">
<source>Overall results</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">13</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="5278344113066375587" datatype="html">
<source>Votes on nomination</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">23</context>
</context-group>
</trans-unit>
<trans-unit id="652158218369589359" datatype="html">
<source>Votes through healing</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">25</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="4355395580941190554" datatype="html">
<source>Constituency results</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/elections/election/election.component.html</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="8889535199141263248" datatype="html">