2018-12-21 15:05:11 +01:00
|
|
|
import { Injectable } from '@angular/core';
|
|
|
|
|
2019-03-11 09:48:20 +01:00
|
|
|
import { _ } from 'app/core/translate/translation-marker';
|
|
|
|
|
2018-12-21 15:05:11 +01:00
|
|
|
/**
|
|
|
|
* The possible keys of a poll object that represent numbers.
|
2019-04-08 10:32:18 +02:00
|
|
|
* TODO Should be 'key of MotionPoll|AssinmentPoll if type of key is number'
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
2019-04-25 16:55:52 +02:00
|
|
|
export type CalculablePollKey =
|
|
|
|
| 'votesvalid'
|
|
|
|
| 'votesinvalid'
|
|
|
|
| 'votescast'
|
|
|
|
| 'yes'
|
|
|
|
| 'no'
|
|
|
|
| 'abstain'
|
|
|
|
| 'votesno'
|
|
|
|
| 'votesabstain';
|
2018-12-21 15:05:11 +01:00
|
|
|
|
|
|
|
/**
|
2019-03-04 18:28:21 +01:00
|
|
|
* TODO: may be obsolete if the server switches to lower case only
|
|
|
|
* (lower case variants are already in CalculablePollKey)
|
|
|
|
*/
|
2019-04-08 10:32:18 +02:00
|
|
|
export type PollVoteValue = 'Yes' | 'No' | 'Abstain' | 'Votes';
|
2019-03-04 18:28:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Interface representing possible majority calculation methods. The implementing
|
|
|
|
* calc function should return an integer number that must be reached for the
|
2019-04-08 10:32:18 +02:00
|
|
|
* option to successfully fulfill the quorum, or null if disabled
|
2019-03-04 18:28:21 +01:00
|
|
|
*/
|
|
|
|
export interface MajorityMethod {
|
|
|
|
value: string;
|
|
|
|
display_name: string;
|
|
|
|
calc: (base: number) => number | null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List of available majority methods, used in motion and assignment polls
|
|
|
|
*/
|
|
|
|
export const PollMajorityMethod: MajorityMethod[] = [
|
|
|
|
{
|
|
|
|
value: 'simple_majority',
|
|
|
|
display_name: 'Simple majority',
|
2019-04-08 10:32:18 +02:00
|
|
|
calc: base => {
|
|
|
|
const q = base * 0.5;
|
|
|
|
return Number.isInteger(q) ? q + 1 : Math.ceil(q);
|
|
|
|
}
|
2019-03-04 18:28:21 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 'two-thirds_majority',
|
|
|
|
display_name: 'Two-thirds majority',
|
2019-04-08 10:32:18 +02:00
|
|
|
calc: base => {
|
|
|
|
const q = (base / 3) * 2;
|
|
|
|
return Number.isInteger(q) ? q + 1 : Math.ceil(q);
|
|
|
|
}
|
2019-03-04 18:28:21 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 'three-quarters_majority',
|
|
|
|
display_name: 'Three-quarters majority',
|
2019-04-08 10:32:18 +02:00
|
|
|
calc: base => {
|
|
|
|
const q = (base / 4) * 3;
|
|
|
|
return Number.isInteger(q) ? q + 1 : Math.ceil(q);
|
|
|
|
}
|
2019-03-04 18:28:21 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
value: 'disabled',
|
|
|
|
display_name: 'Disabled',
|
|
|
|
calc: a => null
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shared service class for polls. Used by child classes {@link MotionPollService}
|
|
|
|
* and {@link AssignmentPollService}
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
@Injectable({
|
|
|
|
providedIn: 'root'
|
|
|
|
})
|
2019-03-04 18:28:21 +01:00
|
|
|
export abstract class PollService {
|
2018-12-21 15:05:11 +01:00
|
|
|
/**
|
2019-03-04 18:28:21 +01:00
|
|
|
* The chosen and currently used base for percentage calculations. Is
|
|
|
|
* supposed to be set by a config service
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
public percentBase: string;
|
|
|
|
|
|
|
|
/**
|
2019-03-04 18:28:21 +01:00
|
|
|
* The default majority method (to be set set per config).
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
public defaultMajorityMethod: string;
|
|
|
|
|
2019-03-04 18:28:21 +01:00
|
|
|
/**
|
|
|
|
* The majority method currently in use
|
|
|
|
*/
|
|
|
|
public majorityMethod: MajorityMethod;
|
|
|
|
|
2018-12-21 15:05:11 +01:00
|
|
|
/**
|
|
|
|
* An array of value - label pairs for special value signifiers.
|
2019-03-04 18:28:21 +01:00
|
|
|
* TODO: Should be given by the server, and editable. For now they are hard
|
|
|
|
* coded
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
2019-02-06 11:52:04 +01:00
|
|
|
private _specialPollVotes: [number, string][] = [[-1, 'majority'], [-2, 'undocumented']];
|
2018-12-21 15:05:11 +01:00
|
|
|
|
|
|
|
/**
|
2019-03-04 18:28:21 +01:00
|
|
|
* getter for the special vote values
|
2018-12-21 15:05:11 +01:00
|
|
|
*
|
|
|
|
* @returns an array of special (non-positive) numbers used in polls and
|
|
|
|
* their descriptive strings
|
|
|
|
*/
|
|
|
|
public get specialPollVotes(): [number, string][] {
|
|
|
|
return this._specialPollVotes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* empty constructor
|
2019-04-08 10:32:18 +02:00
|
|
|
*
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
public constructor() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets an icon for a Poll Key
|
|
|
|
*
|
2019-04-05 16:15:21 +02:00
|
|
|
* @param key yes, no, abstain or something like that
|
2018-12-21 15:05:11 +01:00
|
|
|
* @returns a string for material-icons to represent the icon for
|
2019-04-05 16:15:21 +02:00
|
|
|
* this key(e.g. yes: positive sign, no: negative sign)
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
public getIcon(key: CalculablePollKey): string {
|
|
|
|
switch (key) {
|
|
|
|
case 'yes':
|
|
|
|
return 'thumb_up';
|
|
|
|
case 'no':
|
2019-04-25 16:55:52 +02:00
|
|
|
case 'votesno':
|
2018-12-21 15:05:11 +01:00
|
|
|
return 'thumb_down';
|
|
|
|
case 'abstain':
|
2019-04-25 16:55:52 +02:00
|
|
|
case 'votesabstain':
|
2018-12-21 15:05:11 +01:00
|
|
|
return 'not_interested';
|
2019-03-04 18:28:21 +01:00
|
|
|
// TODO case 'votescast':
|
2018-12-21 15:05:11 +01:00
|
|
|
// sum
|
|
|
|
case 'votesvalid':
|
|
|
|
return 'check';
|
|
|
|
case 'votesinvalid':
|
|
|
|
return 'cancel';
|
|
|
|
default:
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a label for a poll Key
|
|
|
|
*
|
2019-04-05 16:15:21 +02:00
|
|
|
* @param key yes, no, abstain or something like that
|
2018-12-21 15:05:11 +01:00
|
|
|
* @returns A short descriptive name for the poll keys
|
|
|
|
*/
|
2019-03-04 18:28:21 +01:00
|
|
|
public getLabel(key: CalculablePollKey | PollVoteValue): string {
|
|
|
|
switch (key.toLowerCase()) {
|
2018-12-21 15:05:11 +01:00
|
|
|
case 'yes':
|
|
|
|
return 'Yes';
|
|
|
|
case 'no':
|
2019-04-25 16:55:52 +02:00
|
|
|
case 'votesno':
|
2018-12-21 15:05:11 +01:00
|
|
|
return 'No';
|
|
|
|
case 'abstain':
|
2019-04-25 16:55:52 +02:00
|
|
|
case 'votesabstain':
|
2018-12-21 15:05:11 +01:00
|
|
|
return 'Abstain';
|
|
|
|
case 'votescast':
|
2019-03-11 09:48:20 +01:00
|
|
|
return _('Total votes cast');
|
2018-12-21 15:05:11 +01:00
|
|
|
case 'votesvalid':
|
2019-03-11 09:48:20 +01:00
|
|
|
return _('Valid votes');
|
2018-12-21 15:05:11 +01:00
|
|
|
case 'votesinvalid':
|
2019-03-11 09:48:20 +01:00
|
|
|
return _('Invalid votes');
|
2018-12-21 15:05:11 +01:00
|
|
|
default:
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* retrieve special labels for a poll value
|
|
|
|
* {@link specialPollVotes}. Positive values will return as string
|
|
|
|
* representation of themselves
|
2019-04-05 16:15:21 +02:00
|
|
|
*
|
|
|
|
* @param value check value for special numbers
|
|
|
|
* @returns the label for a non-positive value, according to
|
2018-12-21 15:05:11 +01:00
|
|
|
*/
|
|
|
|
public getSpecialLabel(value: number): string {
|
|
|
|
if (value >= 0) {
|
|
|
|
return value.toString();
|
2019-04-25 15:34:42 +02:00
|
|
|
// TODO: toLocaleString(lang); but translateService is not usable here, thus lang is not well defined
|
2018-12-21 15:05:11 +01:00
|
|
|
}
|
|
|
|
const vote = this.specialPollVotes.find(special => special[0] === value);
|
|
|
|
return vote ? vote[1] : 'Undocumented special (negative) value';
|
|
|
|
}
|
2019-03-04 18:28:21 +01:00
|
|
|
|
|
|
|
/**
|
2019-04-05 16:15:21 +02:00
|
|
|
* Get the progress bar class for a decision key
|
2019-03-04 18:28:21 +01:00
|
|
|
*
|
2019-04-05 16:15:21 +02:00
|
|
|
* @param key a calculable poll key (like yes or no)
|
2019-03-04 18:28:21 +01:00
|
|
|
* @returns a css class designing a progress bar in a color, or an empty string
|
|
|
|
*/
|
|
|
|
public getProgressBarColor(key: CalculablePollKey | PollVoteValue): string {
|
|
|
|
switch (key.toLowerCase()) {
|
|
|
|
case 'yes':
|
|
|
|
return 'progress-green';
|
|
|
|
case 'no':
|
|
|
|
return 'progress-red';
|
|
|
|
case 'abstain':
|
|
|
|
return 'progress-yellow';
|
2019-04-05 12:13:34 +02:00
|
|
|
case 'votes':
|
|
|
|
return 'progress-green';
|
2019-03-04 18:28:21 +01:00
|
|
|
default:
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
2018-12-21 15:05:11 +01:00
|
|
|
}
|