Passed
Pull Request — master (#1)
by Muhammad Dyas
02:04
created

src/helpers/vote.ts   A

Complexity

Total Complexity 12
Complexity/F 3

Size

Lines of Code 125
Function Count 4

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 12
eloc 60
mnd 8
bc 8
fnc 4
dl 0
loc 125
bpm 2
cpm 3
noi 0
c 0
b 0
f 0
rs 10

4 Functions

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