blob: aaa553c05aba56ca5e228aedc68db0984249ba28 [file] [log] [blame]
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +01001// Each entry includes the following information in order:
2// - ID
3// - Name (for the label in the legend)
4// - Codename
5// - Color (for the label in the legend)
6const kDataKeys = [
7 [4, 'Recommended', 'recommended', '#34A853'],
8 [6, 'Replies (not recommended)', 'replies', '#DADCE0'],
9 [5, 'Questions', 'questions', '#77909D'],
10];
11const kRoles = {
12 1: 'bronze',
13 2: 'silver',
14 3: 'gold',
15 4: 'platinum',
16 5: 'diamond',
17 10: 'community_manager',
18 20: 'community_specialist',
19 100: 'google_employee',
20 30: 'alumnus',
21};
22
23export default class PerForumStatsSection {
24 constructor(existingChartSection, profile, locale) {
25 if (typeof window.sc_renderProfileActivityChart !== 'function') {
26 console.error(
27 'PerForumStatsSection: window.sc_renderProfileActivityChart is not available.');
28 return;
29 }
30 this.locale = locale;
31 this.parseAndSetData(profile);
32 this.buildDOM(existingChartSection);
33 if (this.data.length) this.injectChart(this.data[0]?.id);
34 }
35
36 parseAndSetData(profile) {
37 const forumUserInfos = profile?.[1]?.[7] ?? [];
38 const forumTitles = profile?.[1]?.[8] ?? [];
39
40 const forumUserInfoIDs = forumUserInfos.map(ui => ui[1]);
41 const forumTitleIDs = forumTitles.map(t => t[1]);
42 const intersectionForumIDs =
43 forumUserInfoIDs.filter(id => forumTitleIDs.includes(id));
44
45 this.data = [];
46 for (const id of intersectionForumIDs) {
47 const fui = forumUserInfos.find(ui => ui[1] === id)?.[2];
48 const numMessages = kDataKeys.reduce((prevVal, key) => {
49 if (!fui?.[key[0]]) return prevVal;
50 return prevVal + fui[key[0]].reduce((prevVal, userActivity) => {
51 return prevVal + (userActivity?.[3] ?? 0);
52 }, /* initialValue = */ 0);
53 }, /* initialValue = */ 0);
54 this.data.push({
55 id,
56 forumTitle: forumTitles.find(t => t[1] === id)?.[2],
57 forumUserInfo: fui,
58 numMessages,
59 });
60 }
61 this.data.sort((a, b) => {
62 // First sort by number of messages
63 if (b.numMessages > a.numMessages) return 1;
64 if (b.numMessages < a.numMessages) return -1;
65 // Then sort by name
66 return a.forumTitle.localeCompare(
67 b.forumTitle, 'en', {sensitivity: 'base'});
68 });
69 }
70
71 buildDOM(existingChartSection) {
72 let section = document.createElement('div');
73 section.classList.add('scTailwindUser_profileUserprofilesection');
74
75 let root = document.createElement('div');
76 root.classList.add(
77 'scTailwindSharedActivitychartroot',
78 'TWPT-scTailwindSharedActivitychartroot');
79
80 let title = document.createElement('h2');
81 title.classList.add('scTailwindSharedActivitycharttitle');
82 title.textContent = 'Per-forum activity';
83
84 let selector = this.createForumSelector();
85
86 let chartEl = document.createElement('div');
87 chartEl.classList.add('scTailwindSharedActivitychartchart');
88
89 root.append(title, selector, chartEl);
90 section.append(root);
91 existingChartSection.after(section);
92
93 this.chartEl = chartEl;
94 }
95
96 getAplosData(forumId) {
97 let aplosData = [];
98 for (const [key, label, name, color] of kDataKeys) {
99 let rawData = this.data.find(f => f.id === forumId)?.forumUserInfo?.[key];
100 let data;
101 if (!rawData)
102 data = [];
103 else
104 data = rawData.map(m => JSON.stringify(Object.values(m)));
105 aplosData.push({
106 color,
107 data,
108 label,
109 name,
110 });
111 }
112 return aplosData;
113 }
114
115 createForumSelector() {
116 let div = document.createElement('div');
117 div.classList.add('TWPT-select-container');
118
119 let select = document.createElement('select');
120 let noPostsGroup;
121 let noPostsGroupFlag = false;
122 for (const forumData of this.data) {
123 const hasPosted = forumData.numMessages > 0;
124
125 if (!hasPosted && !noPostsGroupFlag) {
126 noPostsGroup = document.createElement('optgroup');
127 noPostsGroup.label = 'Not posted to within the last 12 months';
128 noPostsGroupFlag = true;
129 }
130
131 let additionalLabelsArray = [];
132 if (hasPosted)
133 additionalLabelsArray.push(forumData.numMessages + ' messages');
134 let role = forumData.forumUserInfo?.[1]?.[3] ?? 0;
135 if (role) additionalLabelsArray.push(kRoles[role]);
136 let additionalLabels = '';
137 if (additionalLabelsArray.length > 0)
138 additionalLabels = ' (' + additionalLabelsArray.join(', ') + ')';
139
140 let option = document.createElement('option');
141 option.textContent = forumData.forumTitle + additionalLabels;
142 option.value = forumData.id;
143 if (hasPosted)
144 select.append(option);
145 else
146 noPostsGroup.append(option);
147 }
148 if (noPostsGroupFlag) select.append(noPostsGroup);
149 select.addEventListener('change', e => {
150 let forumId = e.target.value;
151 this.injectChart(forumId);
152 });
153
154 div.append(select);
155 return div;
156 }
157
158 injectChart(forumId) {
159 this.chartEl.replaceChildren();
160
161 let data = this.getAplosData(forumId);
162 let metadata = {
163 activities: [],
164 finalMonth: undefined,
165 locale: this.locale,
166 shouldDisableTransitions: true,
167 };
168 let chartTitle = 'User activity chart';
169 let chart = window.sc_renderProfileActivityChart(
170 this.chartEl, data, metadata, chartTitle);
171 }
172}