-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
StreamHatchet Frontend Technical Test
- Loading branch information
Showing
7 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/*Responsive page, has two sizes for desktop or phone devices (just to show off how the streamhatchet header webcomponent resizes)*/ | ||
body { | ||
margin-top: 450px; | ||
display: flex; | ||
flex-direction: column; | ||
font-family: 'Nunito', Arial; | ||
font-size: 22px; | ||
} | ||
.container{ | ||
margin: auto; | ||
display: flex; | ||
gap: 30px; | ||
flex-direction: row; | ||
justify-content: center; | ||
width: 80%; | ||
margin: auto; | ||
height: 100%; | ||
} | ||
|
||
.containerr { | ||
width: 80%; | ||
margin: 8em auto; | ||
} | ||
|
||
.chart-container { | ||
min-width: 300px; | ||
} | ||
|
||
#myChart { | ||
width: 100%; | ||
max-width: 300px; | ||
margin: 0 auto; | ||
} | ||
|
||
#buttonContainer{ | ||
transform: scale(0); | ||
margin: auto; | ||
} | ||
|
||
button{ | ||
margin: auto 0; | ||
height: 100px; | ||
} | ||
|
||
button:hover{ | ||
cursor: pointer; | ||
} | ||
|
||
#getRequestContainer button{ | ||
height: 20px; | ||
} | ||
|
||
#buttonload { | ||
display: none; | ||
} | ||
|
||
/* Specifications for desktop screen size*/ | ||
@media only screen and (min-width:800px) { | ||
body { | ||
margin-top: 80px; | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Demo StreamHatchet</title> | ||
<link rel="shortcut icon" href="img/logo.png" type="image/x-icon"> | ||
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/charts.css/dist/charts.min.css"> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> | ||
<link rel="stylesheet" href="css/main.css"> | ||
</head> | ||
<!--THIS ENTIRE PAGE SERVES AS THE TECHNICAL TEST REQUIRED FOR AN INTERVIEW AIMING TO JOIN STREAMHATCHET TEAM. | ||
TO CORRECTLY USE/SEE THIS PAGE CONTENT, A VALID API MUST BE PROVIDED.--> | ||
<body> | ||
|
||
<header> | ||
<!--Custom webcomponent element for the header--> | ||
<header-streamhatchet></header-streamhatchet> | ||
</header> | ||
|
||
<div class="container" id="getRequestContainer"> | ||
<p>API Key: | ||
<!--Custom webcomponent element for a clickable popup that displays relevant info for the user--> | ||
<popup-notify> | ||
<span slot="popupText"> | ||
-Input your 30-characters API_KEY | ||
<br> | ||
(Used for GET server request through Axios method, doesn't get stored) | ||
</span> | ||
</popup-notify> | ||
<input type="text" id="apiInput" value=""> | ||
<!--This button calls for axios get request with above's given input value field, making this static page secure to load on a public repository without compromising any keys/secrets--> | ||
<button id="fetchServer">Send Api Request</button> | ||
<button id="buttonload"> | ||
<i class="fa fa-circle-o-notch fa-spin"></i>Waiting for server | ||
</button> | ||
</p> | ||
</div> | ||
<div class="container"> | ||
<!--We use chart.js library to create custom charts for StreamHatchet API data through the "canvas" HTML element--> | ||
<div class="chart-container"> | ||
<canvas id="myChart"></canvas> | ||
</div> | ||
</div> | ||
|
||
<!-- A div containing all the buttons, remains hidden until data is fetched from server and is secure to push buttons--> | ||
<div id="buttonContainer"> | ||
<button id="airtimeHours">Airtime hours</button> | ||
<button id="maxRank">Max Rank</button> | ||
<button id="averageViewers">Average Viewers</button> | ||
<button id="averageChannels">Average Channels</button> | ||
</div> | ||
|
||
<!--Script for Axios Fetching and creating the desired Chart with the library chart.js that was previsously lodaded on the page--> | ||
<script src="./js/main.js"></script> | ||
<!--Custom webcomponent file reference for the header--> | ||
<script src="./js/popupNotify.js"></script> | ||
<script src="js/header-streamhatchet.js"></script> | ||
</body> | ||
</html> |
83 changes: 83 additions & 0 deletions
83
sites/streamhatchet_frontendtest/js/header-streamhatchet.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
//const template = document.createElement("template"); //If more webcomponents use this, remove it and add it to the main js file ONCE. | ||
template.innerHTML = ` | ||
<style> | ||
ul { | ||
list-style-type: none; | ||
gap: 5px; | ||
margin: 0; | ||
padding: 10px; | ||
overflow: hidden; | ||
background-color: #333; | ||
position: fixed; | ||
top: 0; | ||
width: 100%; | ||
} | ||
li { | ||
font-size: 1.1em; | ||
} | ||
li > img { | ||
height: 50px; | ||
margin-right: 20px; | ||
} | ||
li > a{ | ||
display: block; | ||
color: white; | ||
text-align: center; | ||
padding: 14px 16px; | ||
text-decoration: none; | ||
} | ||
li > a:hover:not(.active) { | ||
background-color: #111; | ||
border-radius: 50px; | ||
} | ||
.active { | ||
color: black; | ||
background-color: white; | ||
border-radius: 50px; | ||
} | ||
@media only screen and (min-width:800px) { | ||
li{ | ||
float: left; | ||
} | ||
} | ||
</style> | ||
<ul class="headerList"> | ||
<li class="header-item"><img src="img/logo.png" alt="logo" srcset="https://streamhatchet.com/wp-content/uploads/2020/05/SH_Icon_-primary-2.png"></li> | ||
<li class="header-item "><a href="#channels">Channels</a></li> | ||
<li class="header-item"><a class="active" href="#games">Games</a></li> | ||
<li class="header-item"><a href="#campaigns">Campaigns</a></li> | ||
<li class="header-item"><a href="#esports">Esports</a></li> | ||
<li class="header-item"><a href="#comparison">Comparison</a></li> | ||
<li class="header-item"><a href="#insight">Insights</a></li> | ||
<li class="header-item"><a href="#youtube">YouTube VODs</a></li> | ||
</ul> | ||
`; | ||
|
||
class HeaderStreamHatchet extends HTMLElement { | ||
constructor() { | ||
super(); | ||
this.attachShadow({ mode: "open" }); | ||
this.shadowRoot.appendChild(template.content.cloneNode(true)); | ||
} | ||
|
||
|
||
//function to change between header titles/pages | ||
headerSelect() { | ||
const headerItem = this.shadowRoot.querySelector('.header-item'); | ||
return true; | ||
} | ||
|
||
connectedCallback() { | ||
this.shadowRoot.querySelector('.header-item').addEventListener('click', () => { | ||
this.headerSelect() | ||
}) | ||
} | ||
} | ||
|
||
window.customElements.define("header-streamhatchet", HeaderStreamHatchet); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
//We initialize all the variables needed later on server GET Request | ||
let API_KEY = ""; //API will be provided by user input, we don't store API's on our client-side app's. | ||
let {game1, game2, game3, game4, game5} = {}; //Variables to initialize empty chart to later be populated by server response.data | ||
const template = document.createElement("template"); //We load the template that will be used by the WEB-COMPONENTS (for now we have 2, a custom HeaderStreamHatchet and a popupNotify for user interaction) | ||
|
||
//Buttons that dynamically change the chart data | ||
airtimeHours.addEventListener("click", () => { | ||
chart1.data.datasets[0].label = 'Airtime-hours'; | ||
chart1.data.datasets[0].data = [game1.airtime_hours, game2.airtime_hours, game3.airtime_hours, game4.airtime_hours, game5.airtime_hours, ] | ||
chart1.update(); | ||
}); | ||
|
||
maxRank.addEventListener("click", () => { | ||
chart1.data.datasets[0].label = 'Max_rank'; | ||
chart1.data.datasets[0].data = [game1.max_rank, game2.max_rank, game3.max_rank, game4.max_rank, game5.max_rank, ] | ||
chart1.update(); | ||
}); | ||
|
||
averageViewers.addEventListener("click", () => { | ||
chart1.data.datasets[0].label = 'Average_viewers'; | ||
chart1.data.datasets[0].data = [game1.average_viewers, game2.average_viewers, game3.average_viewers, game4.average_viewers, game5.average_viewers, ] | ||
chart1.update(); | ||
}); | ||
|
||
averageChannels.addEventListener("click", () => { | ||
chart1.data.datasets[0].label = 'Average_channels'; | ||
chart1.data.datasets[0].data = [game1.average_channels, game2.average_channels, game3.average_channels, game4.average_channels, game5.average_channels] | ||
chart1.update(); | ||
}); | ||
|
||
//Chart creation with chart.js library -> TODO: Make it a standalone webcomponent as we did with custom header-streamhatchet, this way a constructor() could be setted for future charts. | ||
//first we fetch de document element for the chart, a canvas inside a div with id #myChart | ||
const ctx = document.getElementById('myChart'); | ||
//Then we prepare the data set that is going to get passedd to the chart constructor | ||
const data = { | ||
//Instead of using generic labels we put the basic instructions for the user to read | ||
labels: [ | ||
'You need to input a valid api', | ||
'to get this working, anyways chart', | ||
'animations do work meanwhile, you', | ||
'just need to click on {here} or even', | ||
'<---{here} if you want to see it.' | ||
], | ||
datasets: [{ | ||
//Label showed on-hover | ||
label: 'Input a valid API', | ||
//dummy-data for first page load | ||
data: [1, 1, 1, 1, 1], | ||
backgroundColor: [ | ||
'rgb(255, 99, 132)', | ||
'rgb(54, 162, 235)', | ||
'rgb(255, 205, 86)', | ||
'rgb(255, 205, 0)', | ||
'rgb(255, 0, 86)' | ||
], | ||
hoverOffset: 4, | ||
//this is the doughnut circumference, we want only half for this chart | ||
circumference: 180, | ||
//by default the half-doughnut is rotated vertically, we need to adjust it by 90degrees increments (270 in this case) | ||
rotation: 270 | ||
}] | ||
}; | ||
//We load the initial chart (Axios hasnt fetched data from server, dummy/demo datasets should be provided as goodpractices) | ||
const chart1 = new Chart(ctx, { | ||
type: 'doughnut', | ||
data: data, | ||
options: { | ||
aspectRatio: 1, | ||
plugins: { | ||
tooltip: {enabled:true}, | ||
legend: {display: true} | ||
} | ||
} | ||
}); | ||
|
||
//Server Requests | ||
//fetch that loads when providing an API through the screen input field + button | ||
fetchServer.addEventListener("click", () => { | ||
|
||
//Store the user | ||
API_KEY = document.getElementById("apiInput").value; | ||
document.getElementById("apiInput").value = ""; | ||
|
||
//Only when API provided by user has accepted length we fetch/call the server | ||
if ( API_KEY.length == 30 ) { | ||
//When the API is valid, we disable GET button and show a button animation | ||
document.getElementById("fetchServer").style.display = "none"; | ||
document.getElementById("buttonload").style.display = "inline-flex"; | ||
|
||
axios | ||
.get(`https://api.streamhatchet.com/discovery/games/month/2024-01?token=${API_KEY}&sort_by=average_viewers&order=desc&limit=50&offset=0`) | ||
.then((response) => { | ||
//First things first, after server request is successful we disable API Input element's display | ||
document.getElementById("getRequestContainer").style.display = "none"; | ||
//We store the server response on games const, if we ever want to change the displayed games with a future button | ||
const games = response.data.games; | ||
game1 = games[0]; | ||
game2 = games[1]; | ||
game3 = games[2]; | ||
game4 = games[3]; | ||
game5 = games[4]; | ||
|
||
//initial data population for the first server load | ||
chart1.data.labels = [game1.game, game2.game, game3.game, game4.game, game5.game] | ||
chart1.data.datasets[0].label = 'Airtime-hours'; | ||
chart1.data.datasets[0].data = [game1.airtime_hours, game2.airtime_hours, game3.airtime_hours, game4.airtime_hours, game5.airtime_hours, ] | ||
chart1.update(); | ||
buttonContainer.style.transform = 'scale(1)'; | ||
}) | ||
.catch((error) => { | ||
console.log(error); | ||
//When the API_KEY is not valid, we enable GET button again | ||
document.getElementById("fetchServer").style.display = "inline-flex"; | ||
document.getElementById("buttonload").style.display = "none"; | ||
}); | ||
}else{ | ||
//Promp a warning indicating wrong input length/type | ||
|
||
} | ||
}); |
Oops, something went wrong.