blob: e2639654208ec92a1668a0ba657cf9a119e06877 [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ínezcf40f682023-11-01 22:02:16 +010014 [8, 'communityguides', '#9334E6'],
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010015];
16const kRoles = {
17 1: 'bronze',
18 2: 'silver',
19 3: 'gold',
20 4: 'platinum',
21 5: 'diamond',
22 10: 'community_manager',
23 20: 'community_specialist',
24 100: 'google_employee',
25 30: 'alumnus',
26};
27
28export default class PerForumStatsSection {
avm9996337601bc2022-02-21 10:36:45 +010029 constructor(existingChartSection, profile, locale, isCommunityConsole) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010030 this.locale = locale;
avm9996337601bc2022-02-21 10:36:45 +010031 this.isCommunityConsole = isCommunityConsole;
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010032 this.parseAndSetData(profile);
33 this.buildDOM(existingChartSection);
34 if (this.data.length) this.injectChart(this.data[0]?.id);
35 }
36
37 parseAndSetData(profile) {
38 const forumUserInfos = profile?.[1]?.[7] ?? [];
39 const forumTitles = profile?.[1]?.[8] ?? [];
40
41 const forumUserInfoIDs = forumUserInfos.map(ui => ui[1]);
42 const forumTitleIDs = forumTitles.map(t => t[1]);
43 const intersectionForumIDs =
44 forumUserInfoIDs.filter(id => forumTitleIDs.includes(id));
45
46 this.data = [];
47 for (const id of intersectionForumIDs) {
avm9996337601bc2022-02-21 10:36:45 +010048 const fui = forumUserInfos.find(ui => ui?.[1] === id)?.[2];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010049 const numMessages = kDataKeys.reduce((prevVal, key) => {
50 if (!fui?.[key[0]]) return prevVal;
51 return prevVal + fui[key[0]].reduce((prevVal, userActivity) => {
52 return prevVal + (userActivity?.[3] ?? 0);
53 }, /* initialValue = */ 0);
54 }, /* initialValue = */ 0);
55 this.data.push({
56 id,
avm9996337601bc2022-02-21 10:36:45 +010057 forumTitle: forumTitles.find(t => t?.[1] === id)?.[2],
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +010058 forumUserInfo: fui,
59 numMessages,
60 });
61 }
62 this.data.sort((a, b) => {
63 // First sort by number of messages
64 if (b.numMessages > a.numMessages) return 1;
65 if (b.numMessages < a.numMessages) return -1;
66 // Then sort by name
67 return a.forumTitle.localeCompare(
68 b.forumTitle, 'en', {sensitivity: 'base'});
69 });
70 }
71
72 buildDOM(existingChartSection) {
73 let section = document.createElement('div');
74 section.classList.add('scTailwindUser_profileUserprofilesection');
75
76 let root = document.createElement('div');
77 root.classList.add(
78 'scTailwindSharedActivitychartroot',
79 'TWPT-scTailwindSharedActivitychartroot');
80
81 let title = document.createElement('h2');
82 title.classList.add('scTailwindSharedActivitycharttitle');
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +010083
avm9996337601bc2022-02-21 10:36:45 +010084 let badge, badgeTooltip;
85 if (this.isCommunityConsole) {
86 [badge, badgeTooltip] = createExtBadge();
87 } else {
88 badge = document.createElement('span');
89 badge.classList.add('TWPT-badge');
90
91 var badgeImg = document.createElement('img');
92 badgeImg.src =
93 'https://fonts.gstatic.com/s/i/materialicons/repeat/v6/24px.svg';
94
95 badge.appendChild(badgeImg);
96 }
97
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +010098 let titleText = document.createElement('span');
avm9996337601bc2022-02-21 10:36:45 +010099 titleText.textContent =
100 chrome.i18n.getMessage('inject_perforumstats_heading');
Adrià Vilanova Martínez4768e812022-02-01 13:41:28 +0100101
102 title.append(badge, titleText);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100103
104 let selector = this.createForumSelector();
105
106 let chartEl = document.createElement('div');
107 chartEl.classList.add('scTailwindSharedActivitychartchart');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100108 chartEl.setAttribute('data-twpt-per-forum-chart', '');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100109
110 root.append(title, selector, chartEl);
111 section.append(root);
112 existingChartSection.after(section);
avm9996337601bc2022-02-21 10:36:45 +0100113 if (this.isCommunityConsole) new MDCTooltip(badgeTooltip);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100114 }
115
116 getAplosData(forumId) {
117 let aplosData = [];
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100118 for (const [key, name, color] of kDataKeys) {
Adrià Vilanova Martínez217e5f02023-07-22 20:55:50 +0200119 let rawData = this.data.find(f => f.id == forumId)?.forumUserInfo?.[key];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100120 let data;
avm9996337601bc2022-02-21 10:36:45 +0100121 if (!rawData) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100122 data = [];
avm9996337601bc2022-02-21 10:36:45 +0100123 } else {
124 // We're filtering empty strings since in the public forum there a lose
125 // conversion takes place and the first element of the array is always
126 // null, which breaks the Aplos graph rendering.
127 data =
128 rawData.map(m => JSON.stringify(Object.values(m))).filter(m => !!m);
129 }
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100130 aplosData.push({
131 color,
132 data,
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100133 label: chrome.i18n.getMessage('inject_perforumstats_chart_' + name),
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100134 name,
135 });
136 }
137 return aplosData;
138 }
139
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100140 getMessagesString(num) {
141 if (num == 1) {
142 return chrome.i18n.getMessage(
143 'inject_perforumstats_nummessages_singular');
144 }
145 return chrome.i18n.getMessage(
146 'inject_perforumstats_nummessages_plural', [num]);
147 }
148
149 getForumOptionString(forumTitle, labels) {
150 if (labels.length == 0) return forumTitle;
151 if (labels.length == 1)
152 return chrome.i18n.getMessage(
153 'inject_perforumstats_forumoption_1helper', [forumTitle, ...labels]);
154 if (labels.length == 2)
155 return chrome.i18n.getMessage(
156 'inject_perforumstats_forumoption_2helpers', [forumTitle, ...labels]);
157
158 // If labels.length > 3, this is unexpected. Here's a sensible fallback:
159 return forumTitle + ' (' + labels.join(', ') + ')';
160 }
161
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100162 createForumSelector() {
163 let div = document.createElement('div');
164 div.classList.add('TWPT-select-container');
165
166 let select = document.createElement('select');
167 let noPostsGroup;
168 let noPostsGroupFlag = false;
169 for (const forumData of this.data) {
170 const hasPosted = forumData.numMessages > 0;
171
172 if (!hasPosted && !noPostsGroupFlag) {
173 noPostsGroup = document.createElement('optgroup');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100174 noPostsGroup.label =
175 chrome.i18n.getMessage('inject_perforumstats_optgroup_notposted');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100176 noPostsGroupFlag = true;
177 }
178
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100179 let additionalLabels = [];
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100180 if (hasPosted)
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100181 additionalLabels.push(this.getMessagesString(forumData.numMessages));
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100182 let role = forumData.forumUserInfo?.[1]?.[3] ?? 0;
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100183 if (role)
184 additionalLabels.push(chrome.i18n.getMessage(
185 'inject_perforumstats_role_' + kRoles[role]));
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100186
187 let option = document.createElement('option');
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100188 option.textContent =
189 this.getForumOptionString(forumData.forumTitle, additionalLabels);
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100190 option.value = forumData.id;
191 if (hasPosted)
192 select.append(option);
193 else
194 noPostsGroup.append(option);
195 }
196 if (noPostsGroupFlag) select.append(noPostsGroup);
197 select.addEventListener('change', e => {
198 let forumId = e.target.value;
199 this.injectChart(forumId);
200 });
201
202 div.append(select);
203 return div;
204 }
205
206 injectChart(forumId) {
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100207 let data = this.getAplosData(forumId);
208 let metadata = {
209 activities: [],
210 finalMonth: undefined,
211 locale: this.locale,
212 shouldDisableTransitions: true,
213 };
Adrià Vilanova Martínez69c30502022-01-28 20:47:08 +0100214 let chartTitle = chrome.i18n.getMessage('inject_perforumstats_chart_label');
215 const message = {
216 action: 'renderProfileActivityChart',
217 prefix: 'TWPT-extrainfo',
218 data,
219 metadata,
220 chartTitle,
221 };
222 window.postMessage(message, '*');
Adrià Vilanova Martínez4f56d562022-01-26 00:23:27 +0100223 }
224}