Skip to content

Commit

Permalink
Adding in Vue, and creating separate leaderboard page.
Browse files Browse the repository at this point in the history
  • Loading branch information
H. Ryan Jones committed Aug 10, 2019
1 parent f432105 commit 2c3eae1
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 48 deletions.
96 changes: 96 additions & 0 deletions board.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<title>Guess my word - Completion board</title>
<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="./index.css"/>
</head>
<body>
<div id="leaderboard-container">

<header>
<h1>
<a href="./" class="home">Guess my word</a>
<select id="difficulty-changer" v-on:change="setDifficulty">
<option value="normal">normal</option>
<option value="hard">hard</option>
</select>
</h1>
<a class="bigger-target" href="./README.html">about</a>
</header>

<div class="leaderboard" v-cloak>
<h2>Completion board for "{{difficulty}}" today</h2>

<div class="error">{{error}}</div>

<div>{{message}}</div>

<table v-if="leaders.length">
<thead>
<tr>
<th>name</th>
<th>total guesses</th>
<th>time</th>
</tr>
</thead>
<tbody id="leaderboard">
<tr v-for="leader in leaders">
<td>{{leader.name}}</td>
<td>{{leader.numberOfGuesses}}</td>
<td>{{leader.formattedTime}}</td>
</tr>
</tbody>
</table>
</div>
</div>

<script src="https://d2t3dun0il9ood.cloudfront.net/dictionary.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="index.js"></script>
<script>
function getLeaders() {
const date = getTimezonelessLocalDate(new Date());

const onSuccess = (json) => {
this.leaders = normalizeAndSortLeaders(json);
this.error = '';
if (this.leaders.length === 0) {
this.message = 'nobody has guessed the word for today';
}
}

const onFailure = (json) => {
this.leaders = [];
this.message = '';
this.error = UNKNOWN_LEADERBOARD_ERROR;
};
makeLeaderboardRequest(date, this.difficulty, onSuccess, onFailure);
}

new Vue({
el: '#leaderboard-container',
data: {
leaders: [],
difficulty: 'normal',
message: '',
error: '',
},
created() {
this.getLeaders();
},
methods: {
getLeaders,
setDifficulty(e) {
const newDifficulty = e.target.value;
this.difficulty = newDifficulty;
this.getLeaders();
}
},
});
</script>

<script src="/assets/js/googleAnalytics.js"></script>
</body>
</html>
11 changes: 7 additions & 4 deletions index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ header {
flex-wrap: wrap;
}

[v-cloak] {
display: none;
}


.bigger-target,
li, li a {
padding: 8px;
}

a.home,
a.home:visited,
a#give-up,
a#give-up:visited
{
Expand Down Expand Up @@ -176,15 +179,15 @@ form {
display: none; /* don't offer leaderboard form if they got it in one guess */
}

#leaderboard-validation-error {
#leaderboard-validation-error,
.error {
color: #c50000;
font-style: italic;
font-size: 80%
}

.leaderboard {
margin-top: 10px;
display: none;
}

.leaderboard table {
Expand Down
16 changes: 11 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ <h1>
<option value="hard">hard</option>
</select>
</h1>

<a class="bigger-target" href="./board.html">🏆 Board</a>
<a class="bigger-target" href="./README.html">about</a>
</header>

Expand Down Expand Up @@ -44,7 +46,7 @@ <h3 class="aww">My word is:</h3>
<a id="give-up" href="#" onclick="giveUp()" class="initially-hidden">give up :(</a>
</form>

<form class="yeah leaderboard-form" onsubmit="return submitToLeaderboard()">
<form class="yeah leaderboard-form" v-on:submit.prevent="submitToLeaderboard">
<br/>
<label>
enter your name for the completion board<br/>
Expand Down Expand Up @@ -77,7 +79,7 @@ <h4 class="aww">
<div id="before-guesses">
</div>
</div>
<div class="leaderboard">
<div class="leaderboard" v-if="leaders.length" v-cloak>
come back tomorrow for a new word
<span class="try-hard">or
<a href="#" onclick="changeDifficulty('hard')">try a hard word</a>?
Expand All @@ -94,15 +96,19 @@ <h2>Completion board for </h2>
</tr>
</thead>
<tbody id="leaderboard">

<tr v-for="leader in leaders">
<td>{{leader.name}}</td>
<td>{{leader.numberOfGuesses}}</td>
<td>{{getFormattedTime(leader.time)}}</td>
</tr>
</tbody>
</table>
</div>
<div>

</div>


<script src="https://d2t3dun0il9ood.cloudfront.net/dictionary.js"></script>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="index.js"></script>

<!-- Uncomment to run tests in browser -->
Expand Down
97 changes: 58 additions & 39 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,32 @@ let startTime;
let winTime;
let word;
let difficulty = 'normal';
let vueApp;

const UNKNOWN_LEADERBOARD_ERROR = "Sorry, can't contact the leaderboard right now. Please try again in a little bit. (please contact @hryanjones if it persists)";

document.addEventListener('DOMContentLoaded', () => {
if (getElement('container')) {
vueApp = new Vue({
el: '#container',
data: {
leaders: [],
},
methods: {
submitToLeaderboard,
reset() {
this.leaders = [];
}
},
});
}

setup();
setup();

// fix input validation when typing
getInput() && getInput().addEventListener('input', event => event.target.setCustomValidity(''));
});

// fix input validation when typing
getInput() && getInput().addEventListener('input', event => event.target.setCustomValidity(''));

function setup() {
word = undefined;
Expand All @@ -42,6 +63,7 @@ function setup() {
// remove possible win/gave-up state
removeClass('show-win');
removeClass('show-leaderboard');
vueApp.reset();
removeClass('gave-up');
removeClass('difficulty-hard');
removeClass('difficulty-normal');
Expand Down Expand Up @@ -343,39 +365,55 @@ function getDOY(date) {
// LEADERBOARD

function submitToLeaderboard() { // eslint-disable-line no-unused-vars
const data = {
const postData = {
name: getElement('leaderboard-name').value,
time: winTime - startTime,
guesses,
};
const timezonelessDate = getTimezonelessLocalDate(startTime);
let responseStatus;

setDisabledForLeaderboardForm(true);

// fetch(`http://localhost:8080/leaderboard/${timezonelessDate}/wordlist/${difficulty}`, {
fetch(`https://home.hryanjones.com/leaderboard/${timezonelessDate}/wordlist/${difficulty}`, {
method: 'POST',
const onSuccess = (json) => {
this.leaders = normalizeAndSortLeaders(json);
getContainer().classList.add('show-leaderboard');
};
makeLeaderboardRequest(timezonelessDate, difficulty, onSuccess, handleBadResponse, postData);
}

function makeLeaderboardRequest(timezonelessDate, wordlist, onSuccess, onFailure, postData) {
let responseStatus;
let body;
let method = 'GET';
let headers;
if (postData) {
method = 'POST';
headers = { 'Content-Type': 'application/json' };
body = JSON.stringify(postData);
}

const server = 'https://home.hryanjones.com';
// const server = 'http://192.168.1.6:8080';

fetch(`${server}/leaderboard/${timezonelessDate}/wordlist/${wordlist}`, {
method,
mode: 'cors',
cache: 'no-store', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
headers,
body,
})
.then((response) => {
responseStatus = response.status;
return response.json();
})
.catch(handleBadResponse)
.catch(onFailure)
.then((json) => {
if (responseStatus !== 200) {
handleBadResponse(json);
onFailure(json);
return;
}
return normalizeAndSortLeaders(json);
})
.then(renderLeaderboard);
return false;
onSuccess(json);
});
}

function setDisabledForLeaderboardForm(disabled = false) {
Expand All @@ -387,7 +425,7 @@ function setDisabledForLeaderboardForm(disabled = false) {

function handleBadResponse(json) {
const invalidReason = (json && json.invalidReason)
|| 'Unknown issue with leaderboard (please contact @hryanjones if it persists)';
|| UNKNOWN_LEADERBOARD_ERROR;
getElement('leaderboard-validation-error').innerText = invalidReason;
setDisabledForLeaderboardForm(false);
throw new Error(invalidReason);
Expand All @@ -398,6 +436,7 @@ function normalizeAndSortLeaders(leadersByName) {
for (const name in leadersByName) {
const leader = leadersByName[name];
leader.name = name; // warning mutating inputs here, don't care YOLO
leader.formattedTime = getFormattedTime(leader.time);
leaders.push(leader);
}
leaders.sort(sortByGuessesThenTime);
Expand All @@ -419,23 +458,3 @@ function sortByGuessesThenTime(leader1, leader2) {
}
return 0;
}

function renderLeaderboard(leaders) {
const leadersLines = document.createDocumentFragment();
leaders.forEach(renderTableLine);
const leaderboard = getElement('leaderboard');
leaderboard.innerHTML = '';
leaderboard.append(leadersLines);
getContainer().classList.add('show-leaderboard');

function renderTableLine(leader) {
const { name, numberOfGuesses, time } = leader;
const leaderLine = document.createElement('tr');
[name, numberOfGuesses, getFormattedTime(time)].forEach((cellContents) => {
const cell = document.createElement('td');
cell.innerText = cellContents;
leaderLine.append(cell);
});
leadersLines.append(leaderLine);
}
}

0 comments on commit 2c3eae1

Please sign in to comment.