Created
May 15, 2019 18:11
-
-
Save pdahl95/629764f0fae38cf847d4f9ded6c962eb to your computer and use it in GitHub Desktop.
Tatati Hiring Homework
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
Start | End | Name | |
---|---|---|---|
6:00 AM | 12:00 PM | Morning | |
12:00 PM | 4:00 PM | Afternoon | |
3:00 PM | 8:00 PM | Prime |
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
Date | Time | Creative | Spend | Views | |
---|---|---|---|---|---|
01/02/2016 | 8:30 AM | TEST001H | 120.50 | 100 | |
01/02/2016 | 11:30 AM | TEST001H | 240.50 | 110 | |
01/02/2016 | 3:30 PM | TEST002H | 500 | 80 | |
01/02/2016 | 3:34 PM | TEST002H | 400 | 90 | |
01/02/2016 | 3:40 PM | TEST001H | 400 | 110 | |
02/02/2016 | 7:30 AM | TEST001H | 700 | 200 | |
02/02/2016 | 7:30 PM | TEST002H | 700 | 300 |
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
body{ | |
font-family: Tahoma, Verdana, Segoe, sans-serif; | |
} | |
.content { | |
background-color: #f9fbfd; | |
width: 95%; | |
height: 800px; | |
margin: auto; | |
box-shadow: 0px 0px 5px rgba(0, 0, 0, .1); | |
} | |
table{ | |
width:80%; | |
padding-left: 2%; | |
margin: 10px 0px 10px 0px; | |
margin: 0 auto; | |
background-color: white; | |
border-collapse: collapse; | |
} | |
tr{ | |
border: solid #f9fbfd; | |
border-width: 3px 0; | |
} | |
td{ | |
padding: 15px; | |
cellspacing: 4; | |
} | |
th{ | |
color: gray; | |
font-size: 16px; | |
font-weight: lighter; | |
text-align: left; | |
padding-top: 3%; | |
padding-left: 10px; | |
} | |
#spotReport, #rotationReport{ | |
padding-top: 2%; | |
} | |
#overalView{ | |
margin: 0 auto; | |
text-align: center; | |
width: 80%; | |
} | |
.column { | |
float: left; | |
width: 30%; | |
padding: 10px; | |
} | |
.row{ | |
margin-left: 5%; | |
padding-bottom: 3%; | |
} | |
.row:after { | |
content: ""; | |
display: table; | |
clear: both; | |
} |
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
/** | |
* this function converts a csv string to a json array | |
* @param csv | |
* @returns {Array} | |
*/ | |
function csvToJsonArray(csv) { | |
csv = csv.replace(/["]/g, ""); // csv is a string here, so we should get rid of double quotes | |
let jsonArray = []; | |
csv = csv.split("\n"); // split csv string using return TODO: file might have empty lines at the end => fix | |
let headers = csv[0].split(','); | |
for (let i = 1, length = csv.length; i < length; i++) { | |
let row = csv[i].split(','); | |
let temp = {}; | |
for (let x = 0; x < row.length; x++) { | |
temp[headers[x]] = row[x]; | |
} | |
jsonArray.push(temp); | |
} | |
return jsonArray; | |
} | |
/** | |
* this function reads a human readable time string am/pm format and sets it in a date object | |
* this will help us to find if spots fall in a rotation | |
* @param date | |
* @param timeString | |
*/ | |
function setTimeToDate(date, timeString) { | |
// if time is pm I am adding 12 hours | |
if (timeString.includes("PM")) { | |
let time = timeString.replace("PM",""); // remove pm from string | |
time = time.trim(); // remove white space | |
date.setHours(Number(time.split(":")[0]) % 12 + 12); // get hour | |
date.setMinutes(Number(time.split(":")[1])); // get min | |
} else if (timeString.includes("AM")) { | |
let time = timeString.replace("AM",""); | |
time = time.trim(); | |
date.setHours(Number(time.split(":")[0])); | |
date.setMinutes(Number(time.split(":")[1])); | |
} else { | |
console.log("File format error!"); | |
} | |
} | |
/** | |
* this will help us to find if spots fall in a rotation | |
* @param rotations | |
*/ | |
function buildRotationMap(rotations) { | |
let map = {}; | |
$.each(rotations, function (ind, row) { | |
let name = row["Name"]; | |
map[name] = {}; | |
map[name]["start"] = new Date(); | |
map[name]["end"] = new Date(); | |
setTimeToDate(map[name]["start"], row["Start"]); | |
setTimeToDate(map[name]["end"], row["End"]); | |
}); | |
return map; | |
} | |
/** | |
* | |
* @param rotationTable | |
* @param time | |
* @returns {Array} | |
*/ | |
function getMatchedRotations(rotationTable, time) { | |
let date = new Date(); | |
setTimeToDate(date, time); | |
let matchedRotations = []; | |
$.each(rotationTable, function (key, rotation) { | |
if (date >= rotation['start'] && date <= rotation['end']) { | |
matchedRotations.push(key); | |
} | |
}); | |
return matchedRotations; | |
} | |
function buildTableFromObject(object, where, header) { | |
var table = "<table>"; | |
table += "<tr>"; | |
$.each(header, function (idx, item) { | |
table += "<th>"; | |
table += item; | |
table += "</th>"; | |
}); | |
table += "</tr>"; | |
$.each(object, function (key, value) { | |
table += "<tr><td>"; | |
table += key + "</td>"; | |
$.each(value, function (k, v) { | |
table += "<td>"; | |
table += v; | |
table += "</td>"; | |
}); | |
table += "</tr>"; | |
}); | |
table += "</tr>"; | |
table += "</table>"; | |
$(where).html(table); | |
} |
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Title</title> | |
<link rel="stylesheet" type="text/css" href="css/main.css"> | |
</head> | |
<body> | |
<div id="overalView"> | |
<div class="row"> | |
<div class="column" id="totalSpots"></div> | |
<div class="column" id="totalSpend"></div> | |
<div class="column" id="totalView"></div> | |
</div> | |
</div> | |
<div class="content"> | |
<div id="spotReport"><h1>By Creative</h1></div> | |
<div id="rotationReport"><h1>By Day - Rotation</h1></div> | |
</div> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> | |
<script type="text/javascript" src="js/util.js"></script> | |
<script> | |
// assumption is made that spots.csv and rotations.csv will be accessed by a ajax call | |
// for the purpose of this homework I put them in asset folder and I get them using jquery get function | |
const spotsPath = "assets/spots.csv"; | |
const rotationsPath = "assets/rotations.csv"; | |
let rotationTable = {}; | |
$.get(spotsPath, function (spotsTextFile) { | |
let spotsText = spotsTextFile; | |
$.get(rotationsPath, function (rotationTextFile) { | |
let rotationText = rotationTextFile; | |
let spots = csvToJsonArray(spotsText); | |
let rotations = csvToJsonArray(rotationText); | |
rotationTable = buildRotationMap(rotations); | |
// Overall view | |
let totalSpots = spots.length; | |
console.log(totalSpots); | |
$("#totalSpots").html("<h3> Total Spots </h3>").append(totalSpots); | |
let totalSpend; | |
$("#totalSpend").html("<h3> Total Spend </h3>").append(totalSpend); | |
let totalView; | |
$("#totalView").html("<h3> Total Views </h3>").append(totalView); | |
// Logic to generate by-creative view | |
let byCreativeView = {}; | |
$.each(spots, function (ind, spot) { | |
var name = spot["Creative"]; | |
if (!byCreativeView[name]) { | |
byCreativeView[name] = {}; | |
byCreativeView[name]["spent"] = Number(spot["Spend"]); | |
byCreativeView[name]["view"] = Number(spot["Views"]); | |
} else { | |
byCreativeView[name]["spent"] += Number(spot["Spend"]); | |
byCreativeView[name]["view"] += Number(spot["Views"]); | |
} | |
byCreativeView[name]["cpv"] = Number(byCreativeView[name]["spent"]/byCreativeView[name]["view"]).toFixed(2); | |
totalSpend += Number(byCreativeView[name]["spent"]); | |
}); | |
console.log(totalSpend) | |
buildTableFromObject(byCreativeView, "#spotReport", ["Creative", "Spend", "Views", "CPV"]); | |
// Logic to generate day-rotation view | |
let byDayRotationView = {}; | |
$.each(spots, function (ind, spot) { | |
$.each(getMatchedRotations(rotationTable, spot["Time"]), function (ind, rotationName) { | |
let key = spot["Date"] +" "+ rotationName; | |
if (!byDayRotationView[key]) { | |
byDayRotationView[key] = {}; | |
byDayRotationView[key]["time"] = key; | |
byDayRotationView[key]["spent"] = Number(spot["Spend"]); | |
byDayRotationView[key]["view"] = Number(spot["Views"]); | |
} else { | |
byDayRotationView[key]["spent"] += Number(spot["Spend"]); | |
byDayRotationView[key]["view"] += Number(spot["Views"]); | |
} | |
byDayRotationView[key]["CPV"] = Number(byDayRotationView[key]["spent"] / byDayRotationView[key]["view"]).toFixed(2); | |
}); | |
}); | |
buildTableFromObject(byDayRotationView, "#rotationReport", ["Day - Duration", "Spend", "Views", "CPV"]); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment