blob: c0154e8e77829becc3523403025c70b2cc576c7f [file] [log] [blame]
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +01001import {MDCTooltip} from '@material/tooltip';
2
3import {createExtBadge} from './common.js';
4
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +01005// Each entry includes the following information in order:
6// - ID
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +01007// - Codename
8// - Color (for the label in the legend)
9const kDataKeys = [
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +010010 [4, 'recommended', '#34A853'],
11 [6, 'replies', '#DADCE0'],
12 [5, 'questions', '#77909D'],
Adrià Vilanova Martínez22d56032023-07-22 12:28:51 +020013 [7, 'communityvideos', '#F4511E'],
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010014];
15const kRoles = {
16 1: 'bronze',
17 2: 'silver',
18 3: 'gold',
19 4: 'platinum',
20 5: 'diamond',
21 10: 'community_manager',
22 20: 'community_specialist',
23 100: 'google_employee',
24 30: 'alumnus',
25};
26
27export default class PerForumStatsSection {
avm9996337601bc2022-02-21 10:36:45 +010028 constructor(existingChartSection, profile, locale, isCommunityConsole) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010029 this.locale = locale;
avm9996337601bc2022-02-21 10:36:45 +010030 this.isCommunityConsole = isCommunityConsole;
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010031 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) {
avm9996337601bc2022-02-21 10:36:45 +010047 const fui = forumUserInfos.find(ui => ui?.[1] === id)?.[2];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010048 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,
avm9996337601bc2022-02-21 10:36:45 +010056 forumTitle: forumTitles.find(t => t?.[1] === id)?.[2],
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010057 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');
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +010082
avm9996337601bc2022-02-21 10:36:45 +010083 let badge, badgeTooltip;
84 if (this.isCommunityConsole) {
85 [badge, badgeTooltip] = createExtBadge();
86 } else {
87 badge = document.createElement('span');
88 badge.classList.add('TWPT-badge');
89
90 var badgeImg = document.createElement('img');
91 badgeImg.src =
92 'https://fonts.gstatic.com/s/i/materialicons/repeat/v6/24px.svg';
93
94 badge.appendChild(badgeImg);
95 }
96
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +010097 let titleText = document.createElement('span');
avm9996337601bc2022-02-21 10:36:45 +010098 titleText.textContent =
99 chrome.i18n.getMessage('inject_perforumstats_heading');
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +0100100
101 title.append(badge, titleText);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100102
103 let selector = this.createForumSelector();
104
105 let chartEl = document.createElement('div');
106 chartEl.classList.add('scTailwindSharedActivitychartchart');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100107 chartEl.setAttribute('data-twpt-per-forum-chart', '');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100108
109 root.append(title, selector, chartEl);
110 section.append(root);
111 existingChartSection.after(section);
avm9996337601bc2022-02-21 10:36:45 +0100112 if (this.isCommunityConsole) new MDCTooltip(badgeTooltip);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100113 }
114
115 getAplosData(forumId) {
116 let aplosData = [];
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100117 for (const [key, name, color] of kDataKeys) {
Adrià Vilanova Martínez217e5f02023-07-22 20:55:50 +0200118 let rawData = this.data.find(f => f.id == forumId)?.forumUserInfo?.[key];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100119 let data;
avm9996337601bc2022-02-21 10:36:45 +0100120 if (!rawData) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100121 data = [];
avm9996337601bc2022-02-21 10:36:45 +0100122 } else {
123 // We're filtering empty strings since in the public forum there a lose
124 // conversion takes place and the first element of the array is always
125 // null, which breaks the Aplos graph rendering.
126 data =
127 rawData.map(m => JSON.stringify(Object.values(m))).filter(m => !!m);
128 }
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100129 aplosData.push({
130 color,
131 data,
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100132 label: chrome.i18n.getMessage('inject_perforumstats_chart_' + name),
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100133 name,
134 });
135 }
136 return aplosData;
137 }
138
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100139 getMessagesString(num) {
140 if (num == 1) {
141 return chrome.i18n.getMessage(
142 'inject_perforumstats_nummessages_singular');
143 }
144 return chrome.i18n.getMessage(
145 'inject_perforumstats_nummessages_plural', [num]);
146 }
147
148 getForumOptionString(forumTitle, labels) {
149 if (labels.length == 0) return forumTitle;
150 if (labels.length == 1)
151 return chrome.i18n.getMessage(
152 'inject_perforumstats_forumoption_1helper', [forumTitle, ...labels]);
153 if (labels.length == 2)
154 return chrome.i18n.getMessage(
155 'inject_perforumstats_forumoption_2helpers', [forumTitle, ...labels]);
156
157 // If labels.length > 3, this is unexpected. Here's a sensible fallback:
158 return forumTitle + ' (' + labels.join(', ') + ')';
159 }
160
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100161 createForumSelector() {
162 let div = document.createElement('div');
163 div.classList.add('TWPT-select-container');
164
165 let select = document.createElement('select');
166 let noPostsGroup;
167 let noPostsGroupFlag = false;
168 for (const forumData of this.data) {
169 const hasPosted = forumData.numMessages > 0;
170
171 if (!hasPosted && !noPostsGroupFlag) {
172 noPostsGroup = document.createElement('optgroup');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100173 noPostsGroup.label =
174 chrome.i18n.getMessage('inject_perforumstats_optgroup_notposted');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100175 noPostsGroupFlag = true;
176 }
177
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100178 let additionalLabels = [];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100179 if (hasPosted)
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100180 additionalLabels.push(this.getMessagesString(forumData.numMessages));
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100181 let role = forumData.forumUserInfo?.[1]?.[3] ?? 0;
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100182 if (role)
183 additionalLabels.push(chrome.i18n.getMessage(
184 'inject_perforumstats_role_' + kRoles[role]));
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100185
186 let option = document.createElement('option');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100187 option.textContent =
188 this.getForumOptionString(forumData.forumTitle, additionalLabels);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100189 option.value = forumData.id;
190 if (hasPosted)
191 select.append(option);
192 else
193 noPostsGroup.append(option);
194 }
195 if (noPostsGroupFlag) select.append(noPostsGroup);
196 select.addEventListener('change', e => {
197 let forumId = e.target.value;
198 this.injectChart(forumId);
199 });
200
201 div.append(select);
202 return div;
203 }
204
205 injectChart(forumId) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100206 let data = this.getAplosData(forumId);
207 let metadata = {
208 activities: [],
209 finalMonth: undefined,
210 locale: this.locale,
211 shouldDisableTransitions: true,
212 };
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100213 let chartTitle = chrome.i18n.getMessage('inject_perforumstats_chart_label');
214 const message = {
215 action: 'renderProfileActivityChart',
216 prefix: 'TWPT-extrainfo',
217 data,
218 metadata,
219 chartTitle,
220 };
221 window.postMessage(message, '*');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100222 }
223}