index.js (10738B)
1 import 'chartjs-adapter-dayjs-4'; 2 import "./style.css" 3 4 import fetchCurrent from "./fetchCurrent"; 5 import fetchData from "./fetchData"; 6 import {updateHighTime} from "./highTime"; 7 import {updateLowTime} from "./lowTime"; 8 import {addLoader, removeLoader} from "./loader"; 9 import {allowOverlay, forceOverlayOff, forceOverlayOn, isOverlayAllowed, isOverlaySelected} from "./overlay"; 10 import TokenChart from "./tokenChart"; 11 import Datum from "./datum"; 12 13 // TODO: This file should be seperated into multiple with better ownership 14 15 let currentRegionSelection = ''; 16 let currentTimeSelection = ''; 17 let currentAggregateSelection = ''; 18 let startYAtZero = false; 19 let datum; 20 let chart; 21 const currentPriceHash = { 22 us: 0, 23 eu: 0, 24 kr: 0, 25 tw: 0 26 }; 27 const chartData = { 28 us: [], 29 eu: [], 30 kr: [], 31 tw: [] 32 } 33 34 async function callUpdateURL() { 35 await updateTokens(await fetchCurrent()); 36 } 37 38 async function updateTokens(data) { 39 await Promise.all([ 40 updateRegionalToken('us', data), 41 updateRegionalToken('eu', data), 42 updateRegionalToken('kr', data), 43 updateRegionalToken('tw', data) 44 ]); 45 } 46 47 async function updateRegionalToken(region, data) { 48 if (currentPriceHash[region] !== data[region][1]) { 49 currentPriceHash[region] = data[region][1]; 50 if (region === currentRegionSelection) { 51 formatToken(); 52 datum = new Datum(Date.parse(data[region][0]), data[region][1]); 53 if (currentAggregateSelection === 'none' && chart.active()) { 54 await chart.addDataToChart(datum); 55 } 56 else if (currentAggregateSelection === 'none' && !chart.active()) { 57 await chart.lateUpdate(datum); 58 } 59 } 60 } 61 } 62 63 async function updateRegionPreference(newRegion) { 64 if (newRegion !== currentRegionSelection) { 65 await chart.destroyChart(); 66 addLoader(); 67 currentRegionSelection = newRegion; 68 } 69 formatToken(); 70 await pullChartData(); 71 } 72 73 async function updateTimePreference(newTime) { 74 if (newTime !== currentTimeSelection) { 75 await chart.destroyChart(); 76 addLoader(); 77 currentTimeSelection = newTime; 78 } 79 if (newTime === "all") { 80 forceOverlayOff(); 81 } 82 else { 83 allowOverlay(); 84 } 85 await pullChartData(); 86 updateHighTime(); 87 updateLowTime(); 88 } 89 90 async function updateAggregatePreference(newAggregate) { 91 if (newAggregate !== currentAggregateSelection) { 92 await chart.destroyChart(); 93 addLoader(); 94 currentAggregateSelection = newAggregate; 95 } 96 await pullChartData(); 97 } 98 99 function toggleAdvancedSetting() { 100 let element = document.getElementById('advanced-options') 101 if (document.getElementById('enable-advanced').checked) 102 { 103 element.style.display = 'flex'; 104 } 105 else 106 { 107 element.style.display = 'none'; 108 } 109 } 110 111 function toggleStartYAtZero(){ 112 startYAtZero = document.getElementById('y-start').checked; 113 chart.toggleYStart(startYAtZero); 114 } 115 116 async function toggleOverlay() { 117 await chart.destroyChart(); 118 addLoader(); 119 await pullChartData(); 120 } 121 122 async function pullChartData() { 123 let timeSelection = currentTimeSelection; 124 if (isOverlaySelected()) { 125 let timeDigits = parseInt(timeSelection.slice(0, timeSelection.length - 1)) * 2; 126 let timeUnit = timeSelection.slice(timeSelection.length - 1); 127 timeSelection = `${timeDigits}${timeUnit}`; 128 } 129 chartData[currentRegionSelection] = await fetchData(currentRegionSelection, timeSelection, currentAggregateSelection); 130 if (!chart.active()) { 131 await chart.createChart(currentRegionSelection, currentTimeSelection, startYAtZero, chartData[currentRegionSelection]); 132 } 133 else { 134 for (let i = 0; i < chartData[currentRegionSelection].length; i++) { 135 await chart.addDataToChart(chartData[currentRegionSelection][i]); 136 } 137 console.warn("This should never hit, and should be okay to remove"); 138 } 139 removeLoader(); 140 } 141 142 function formatToken() { 143 document.getElementById("token").innerText = currentPriceHash[currentRegionSelection].toLocaleString(); 144 } 145 146 // TODO: These maybe able to be collapsed into a single function with params or a lambda 147 148 function detectRegionQuery(urlSearchParams) { 149 const validRegions = ['us', 'eu', 'tw', 'kr']; 150 if (validRegions.includes(urlSearchParams.get('region').toLowerCase())) { 151 currentRegionSelection = urlSearchParams.get('region').toLowerCase(); 152 let regionDDL = document.getElementById('region'); 153 for (let i = 0; i < regionDDL.options.length; i++) { 154 if (regionDDL.options[i].value === currentRegionSelection) { 155 regionDDL.options[i].selected = true; 156 } 157 } 158 } else { 159 console.warn("An incorrect or malformed region selection was made in the query string"); 160 } 161 } 162 163 function detectTimeQuery(urlSearchParams) { 164 // In the future, we will allow all the times to be selected, 165 // once I come up with a good reduction algorithm. 166 // For larger time selections, it's currently hardcoded into the backend 167 const validTimes = ['72h', '168h', '336h', '720h', '30d', '2190h', '90d', '1y', '2y', '6m', 'all']; 168 if (validTimes.includes(urlSearchParams.get('time').toLowerCase())) { 169 currentTimeSelection = urlSearchParams.get('time').toLowerCase(); 170 if (currentTimeSelection === 'all') { 171 forceOverlayOff(); 172 } 173 let timeDDL = document.getElementById('time'); 174 for (let i = 0; i < timeDDL.options.length; i++) { 175 if (timeDDL.options[i].value === currentTimeSelection) { 176 timeDDL.options[i].selected = true; 177 } 178 } 179 updateHighTime(); 180 updateLowTime(); 181 } else { 182 console.warn("An incorrect or malformed time selection was made in the query string"); 183 } 184 } 185 186 function detectAggregateQuery(urlSearchParams) { 187 const validOperations = ['none', 'daily_mean', 'avg']; 188 if (validOperations.includes(urlSearchParams.get('aggregate').toLowerCase())) { 189 currentAggregateSelection = urlSearchParams.get('aggregate').toLowerCase(); 190 // For backwards compatibility 191 if (currentAggregateSelection === 'daily_mean') { 192 currentAggregateSelection = 'avg'; 193 } 194 let aggregateDDL = document.getElementById('aggregate'); 195 for (let i = 0; i < aggregateDDL.options.length; i++) { 196 if (aggregateDDL.options[i].value === currentAggregateSelection) { 197 aggregateDDL.options[i].selected = true; 198 } 199 } 200 } else { 201 console.warn("An incorrect or malformed aggregate selection was made in the query string"); 202 } 203 } 204 205 function detectZeroQuery(urlSearchParams) { 206 startYAtZero = urlSearchParams.get('startAtZero') === 'true'; 207 let advOptions = document.getElementById('enable-advanced'); 208 let startAtZeroOption = document.getElementById('y-start'); 209 advOptions.checked = startYAtZero; 210 startAtZeroOption.checked = startYAtZero; 211 toggleAdvancedSetting(); 212 toggleStartYAtZero(); 213 } 214 215 function detectOverlayQuery(urlSearchParams) { 216 const enableOverlay = urlSearchParams.get('overlay') === 'previous_time'; 217 if (enableOverlay) { 218 forceOverlayOn(); 219 } else { 220 forceOverlayOff(); 221 } 222 } 223 224 function detectURLQuery() { 225 const urlSearchParams = new URLSearchParams(window.location.search); 226 if (urlSearchParams.has('region')) { 227 detectRegionQuery(urlSearchParams); 228 } 229 if (urlSearchParams.has('time')) { 230 detectTimeQuery(urlSearchParams); 231 } 232 if (urlSearchParams.has('aggregate')) { 233 detectAggregateQuery(urlSearchParams); 234 } 235 if (urlSearchParams.has('startAtZero')) { 236 detectZeroQuery(urlSearchParams) 237 } 238 if (urlSearchParams.has('overlay')) { 239 detectOverlayQuery(urlSearchParams); 240 } 241 } 242 243 function buildDeepLinksURL() { 244 let url = "https://wowtoken.app/?" 245 if (currentTimeSelection !== '72h'){ 246 url += `time=${currentTimeSelection}&` 247 } 248 if (currentRegionSelection !== 'us'){ 249 url += `region=${currentRegionSelection}&` 250 } 251 if (currentAggregateSelection !== '' && currentAggregateSelection !== 'none'){ 252 url += `aggregate=${currentAggregateSelection}&` 253 } 254 if (startYAtZero !== false){ 255 url += `startAtZero=${startYAtZero}&` 256 } 257 if (isOverlaySelected()){ 258 url += `overlay=previous_time&` 259 } 260 return url 261 } 262 263 function copyURL() { 264 let toolTip = document.getElementById('urlTooltip'); 265 navigator.clipboard.writeText(buildDeepLinksURL()).then( 266 () => { 267 toolTip.innerHTML= "Copied the URL"; 268 }, 269 () => { 270 toolTip.innerHTML = "Unable to copy URL to clipboard"; 271 } 272 ); 273 } 274 275 function toolTipMouseOut() { 276 let tooltip = document.getElementById("urlTooltip"); 277 tooltip.innerHTML = "Copy to clipboard"; 278 } 279 280 function registerEventHandles() { 281 registerCopyHandlers(); 282 registerOptionHandlers(); 283 registerAdvancedHandlers(); 284 } 285 286 // TODO: These need to be moved out into probably tokenChart if not other files 287 288 function registerAdvancedHandlers() { 289 document.getElementById('enable-advanced').addEventListener('change', () => { 290 toggleAdvancedSetting(); 291 }) 292 document.getElementById('y-start').addEventListener('change', () => { 293 toggleStartYAtZero(); 294 }) 295 document.getElementById('period-overlay').addEventListener('change', () => { 296 toggleOverlay(); 297 }) 298 } 299 300 function registerCopyHandlers() { 301 document.getElementById('copyURLButton').addEventListener('click', function () { 302 copyURL(); 303 }) 304 document.getElementById('copyURLButton').addEventListener('mouseout', function () { 305 toolTipMouseOut(); 306 }) 307 } 308 309 function registerOptionHandlers() { 310 document.getElementById('region').addEventListener('change', function() { 311 updateRegionPreference(this.value); 312 }); 313 currentRegionSelection = document.getElementById('region').value; 314 document.getElementById('time').addEventListener('change', function() { 315 updateTimePreference(this.value); 316 }); 317 currentTimeSelection = document.getElementById('time').value; 318 document.getElementById('aggregate').addEventListener('change', function () { 319 updateAggregatePreference(this.value); 320 }) 321 currentAggregateSelection = document.getElementById('aggregate').value; 322 } 323 324 document.addEventListener('DOMContentLoaded', function () { 325 registerEventHandles(); 326 detectURLQuery(); 327 chart = new TokenChart(); 328 Promise.all([ 329 callUpdateURL(), 330 ]).then(pullChartData); 331 332 setInterval(callUpdateURL, 60*1000); 333 }, false); 334