Completed
Push — master ( 57c78c...4fcad4 )
by Muhammad Dyas
15s queued 13s
created

src/helpers/vote.ts   A

Complexity

Total Complexity 13
Complexity/F 3.25

Size

Lines of Code 134
Function Count 4

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 66
mnd 9
bc 9
fnc 4
dl 0
loc 134
rs 10
bpm 2.25
cpm 3.25
noi 0
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A vote.ts ➔ progressBarText 0 18 2
A vote.ts ➔ saveVotes 0 30 5
A vote.ts ➔ choice 0 33 1
B vote.ts ➔ choiceSection 0 39 5
1
import {chat_v1 as chatV1} from 'googleapis/build/src/apis/chat/v1';
2
import {PollState, Voter, Votes} from './interfaces';
3
4
/**
5
 * Creates a small progress bar to show percent of votes for an option. Since
6
 * width is limited, the percentage is scaled to 20 steps (5% increments).
7
 *
8
 * @param {number} choice - The choice index
9
 * @param {object} voter - The voter
10
 * @param {object} votes - Total votes cast in the poll
11
 * @param {boolean} isAnonymous - save name or not
12
 * @returns {Votes} Map of cast votes keyed by choice index
13
 */
14
export function saveVotes(choice: number, voter: Voter, votes: Votes, isAnonymous = false) {
15
  Object.keys(votes).forEach(function(choiceIndex) {
16
    if (votes[choiceIndex]) {
17
      const existed = votes[choiceIndex].findIndex((x) => x.uid === voter.uid);
18
      if (existed > -1) {
19
        votes[choiceIndex].splice(existed, 1);
20
      }
21
    }
22
  });
23
  if (isAnonymous) {
24
    delete voter.name;
25
  }
26
  if (votes[choice]) {
27
    votes[choice].push(voter);
28
  } else {
29
    votes[choice] = [voter];
30
  }
31
32
  return votes;
33
}
34
35
/**
36
 * Creates a small progress bar to show percent of votes for an option. Since
37
 * width is limited, the percentage is scaled to 20 steps (5% increments).
38
 *
39
 * @param {number} voteCount - Number of votes for this option
40
 * @param {number} totalVotes - Total votes cast in the poll
41
 * @returns {string} Text snippet with bar and vote totals
42
 */
43
export function progressBarText(voteCount: number, totalVotes: number) {
44
  if (voteCount === 0 || totalVotes === 0) {
45
    return '';
46
  }
47
48
  // For progress bar, calculate share of votes and scale it
49
  const percentage = (voteCount * 100) / totalVotes;
50
  const progress = Math.round((percentage / 100) * 35);
51
  return '█'.repeat(progress);
52
}
53
54
/**
55
 * Builds a line in the card for a single choice, including
56
 * the current totals and voting action.
57
 *
58
 * @param {number} i - Index to identify the choice
59
 * @param {object} state - Text of the choice
60
 * @param {number} totalVotes - Total votes cast in poll state
61
 * @param {string} serializedState - Serialized poll state to send in events
62
 * @param {string} creator - creator of the option
63
 * @returns {chatV1.Schema$GoogleAppsCardV1Section} card section
64
 */
65
export function choiceSection(i: number, state: PollState, totalVotes: number, serializedState: string, creator = '') {
66
  if (state.votes === undefined) {
67
    state.votes = {};
68
  }
69
70
  if (state.votes[i] === undefined) {
71
    state.votes[i] = [];
72
  }
73
  const voteCount = state.votes[i].length;
74
  const choiceTag = choice(i, state.choices[i], voteCount, totalVotes, serializedState);
75
  if (creator) {
76
    choiceTag.decoratedText!.topLabel = 'Added by ' + creator;
77
  }
78
  const section: chatV1.Schema$GoogleAppsCardV1Section = {
79
    widgets: [choiceTag],
80
  };
81
  if (state.votes[i].length > 0 && !state.anon) {
82
    section.collapsible = true;
83
    section.uncollapsibleWidgetsCount = 1;
84
    // @ts-ignore: already defined above
85
    section.widgets.push({
86
      'textParagraph': {
87
        'text': state.votes[i].map((u) => u.name).join(', '),
88
      },
89
    });
90
  }
91
  return section;
92
}
93
94
/**
95
 * Builds a line in the card for a single choice, including
96
 * the current totals and voting action.
97
 *
98
 * @param {number} index - Index to identify the choice
99
 * @param {string|undefined} text - Text of the choice
100
 * @param {number} voteCount - Current number of votes cast for this item
101
 * @param {number} totalVotes - Total votes cast in poll
102
 * @param {string} state - Serialized state to send in events
103
 * @returns {chatV1.Schema$GoogleAppsCardV1Widget} card widget
104
 */
105
function choice(
106
  index: number, text: string, voteCount: number, totalVotes: number,
107
  state: string): chatV1.Schema$GoogleAppsCardV1Widget {
108
  const progressBar = progressBarText(voteCount, totalVotes);
109
  return {
110
    decoratedText: {
111
      bottomLabel: `${progressBar} ${voteCount}`,
112
      text: text,
113
      button: {
114
        text: 'vote',
115
        onClick: {
116
          action: {
117
            function: 'vote',
118
            parameters: [
119
              {
120
                key: 'state',
121
                value: state,
122
              },
123
              {
124
                key: 'index',
125
                value: index.toString(10),
126
              },
127
            ],
128
          },
129
        },
130
      },
131
    },
132
  };
133
}
134