Completed
Push — master ( 8e01eb...25ec60 )
by Muhammad Dyas
17s queued 12s
created

PollCard.isClosed   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
1
import BaseCard from './BaseCard';
2
import {ClosableType, PollState, Voter} from '../helpers/interfaces';
3
import {chat_v1 as chatV1} from 'googleapis/build/src/apis/chat/v1';
4
import {ICON_URL_48X48} from '../config/default';
5
import {progressBarText} from '../helpers/vote';
6
7
export default class PollCard extends BaseCard {
8
  private readonly state: PollState;
9
10
  constructor(state: PollState) {
11
    super();
12
    this.state = state;
13
  }
14
15
  create() {
16
    this.buildHeader();
17
    this.buildSections();
18
    this.buildButtons();
19
    this.card.name = this.getSerializedState();
20
    return this.card;
21
  }
22
23
  buildHeader() {
24
    if (this.state.topic.length > 40) {
25
      const widgetHeader = this.sectionHeader();
26
      this.card.sections!.slice().unshift(widgetHeader);
27
    } else {
28
      this.card.header = this.cardHeader();
29
    }
30
  }
31
32
  getAuthorName() {
33
    return this.state.author?.displayName ?? '';
34
  }
35
36
  getSerializedState() {
37
    return JSON.stringify(this.state);
38
  }
39
40
  cardHeader(): chatV1.Schema$GoogleAppsCardV1CardHeader {
41
    return {
42
      title: this.state.topic,
43
      subtitle: `Posted by ${this.getAuthorName()}`,
44
      imageUrl: ICON_URL_48X48,
45
      imageType: 'CIRCLE',
46
    };
47
  }
48
49
  sectionHeader(): chatV1.Schema$GoogleAppsCardV1Section {
50
    return {
51
      widgets: [
52
        {
53
          'decoratedText': {
54
            'text': this.state.topic,
55
            'wrapText': true,
56
            'bottomLabel': `Posted by ${this.getAuthorName()}`,
57
            'startIcon': {
58
              'altText': 'Absolute Poll',
59
              'iconUrl': ICON_URL_48X48,
60
              'imageType': 'SQUARE',
61
            },
62
          },
63
        },
64
      ],
65
    };
66
  }
67
68
  buildSections() {
69
    const votes: Array<Array<Voter>> = Object.values(this.state.votes ?? {});
70
    const totalVotes: number = votes.reduce((sum, vote) => sum + vote.length, 0);
71
    for (let i = 0; i < this.state.choices.length; ++i) {
72
      const creator = this.state.choiceCreator?.[i] ?? '';
73
      const section = this.choiceSection(i, totalVotes, creator);
74
      this.card.sections!.push(section);
75
    }
76
  }
77
78
  buildButtons() {
79
    const buttons = [];
80
    if (this.state.optionable) {
81
      buttons.push({
82
        'text': 'Add Option',
83
        'onClick': {
84
          'action': {
85
            'function': 'add_option_form',
86
            'interaction': 'OPEN_DIALOG',
87
            'parameters': [],
88
          },
89
        },
90
      });
91
    }
92
    const isClosable = this.state.type === undefined || this.state.type !== ClosableType.UNCLOSEABLE;
93
94
    if (isClosable) {
95
      const closeButton: chatV1.Schema$GoogleAppsCardV1Button = {
96
        'text': 'Close Poll',
97
        'onClick': {
98
          'action': {
99
            'function': 'close_poll_form',
100
            'interaction': 'OPEN_DIALOG',
101
            'parameters': [],
102
          },
103
        },
104
      };
105
      if (this.isClosed()) {
106
        closeButton.disabled = true;
107
      }
108
      buttons.push(closeButton);
109
    }
110
111
    if (buttons.length > 0) {
112
      this.card.sections!.push(
113
        {
114
          'widgets': [
115
            {
116
              'buttonList': {
117
                buttons,
118
              },
119
            },
120
          ],
121
        });
122
    }
123
  }
124
125
  choiceSection(i: number, totalVotes: number, creator = '') {
126
    if (this.state.votes === undefined) {
127
      this.state.votes = {};
128
    }
129
130
    if (this.state.votes[i] === undefined) {
131
      this.state.votes[i] = [];
132
    }
133
    const voteCount = this.state.votes[i].length;
134
    const choiceTag = this.choice(i, this.state.choices[i], voteCount, totalVotes);
135
    if (creator) {
136
      choiceTag.decoratedText!.topLabel = 'Added by ' + creator;
137
    }
138
    const section: chatV1.Schema$GoogleAppsCardV1Section = {
139
      widgets: [choiceTag],
140
    };
141
    if (this.state.votes[i].length > 0 && !this.state.anon) {
142
      section.collapsible = true;
143
      section.uncollapsibleWidgetsCount = 1;
144
      // @ts-ignore: already defined above
145
      section.widgets.push({
146
        'textParagraph': {
147
          'text': this.state.votes[i].map((u) => u.name).join(', '),
148
        },
149
      });
150
    }
151
    return section;
152
  }
153
154
  choice(index: number, text: string, voteCount: number, totalVotes: number): chatV1.Schema$GoogleAppsCardV1Widget {
155
    const progressBar = progressBarText(voteCount, totalVotes);
156
    const voteButton: chatV1.Schema$GoogleAppsCardV1Button = {
157
      text: 'vote',
158
      onClick: {
159
        action: {
160
          function: 'vote',
161
          parameters: [
162
            {
163
              key: 'index',
164
              value: index.toString(10),
165
            },
166
          ],
167
        },
168
      },
169
    };
170
171
    if (this.isClosed()) {
172
      voteButton.disabled = true;
173
    }
174
    return {
175
      decoratedText: {
176
        bottomLabel: `${progressBar} ${voteCount}`,
177
        text: text,
178
        button: voteButton,
179
      },
180
    };
181
  }
182
183
  private isClosed(): boolean {
184
    return this.state.closedTime !== undefined && this.state.closedTime <= Date.now();
185
  }
186
}
187