Donordrive Display
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"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> | |
<style> | |
/* local css here */ | |
#donation-sums { position: absolute; align-self: center; } | |
#donation-bar { width: 100%; /* position: relative; top: 100px; left: 100px; */ } | |
</style> | |
</head> | |
<body> | |
<div class="container-fluid"> | |
<div style="display: flex;"> | |
<div style="width: min-content;"> | |
<div id="donation-sum"></div> | |
</div> | |
<div style="width: 100%;"> | |
<div id="donation-bar"> | |
<div class="progress"> | |
<div class="progress-bar progress-bar-striped" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
</div> | |
</div> | |
<div style="width: min-content;"> | |
<div id="donation-goal"></div> | |
</div> | |
</div> | |
</div> | |
</body> | |
<script> | |
const baseUrl = "https://try.donordrive.com/api/participants/15882"; | |
const pollIntervalMs = 15000; | |
let lastEtag = null; | |
// queries the DonorDrive API and calls the updateCallback if the data has changed | |
function queryApi(baseUrl, updateCallback) { | |
// I'm too dumb to pass both the json data and the etag through the promise, | |
// so keep it in this local variable | |
let etag = null; | |
// cache argument should take care of ETag etc | |
fetch(baseUrl, {cache: "no-cache"}) | |
.then((response) => { | |
if (!response.ok) | |
throw new Error(response.status); | |
etag = response.headers.get("Etag"); | |
return response.json(); | |
}) | |
.then((participant) => { | |
console.debug("etag", etag); | |
// use etag of participant endpoint to determine changes | |
// see https://github.com/DonorDrive/PublicAPI/blob/master/README.md | |
if (etag != lastEtag) { | |
// when the etag has changed, fetch other data and update | |
updateUI(participant); | |
lastEtag = etag; // only store new etag when the update was successful | |
} | |
}) | |
.catch((err) => { | |
console.error(err); | |
// TODO: handle error. indicate on layout? | |
}); | |
} | |
// format to a currency string like "$1,234", will round to two fraction digits | |
function formatMoney(value) { | |
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 2 }); | |
} | |
// this function is called when new data is coming in | |
function updateUI(participant) { | |
// participant: https://github.com/DonorDrive/PublicAPI/blob/master/resources/participants.md | |
console.debug("update", participant); | |
let barPercentage = Math.min(100, (participant.sumDonations / participant.fundraisingGoal) * 100); | |
console.debug("progress", participant.sumDonations, participant.fundraisingGoal, barPercentage); | |
// update progress bar | |
let barElement = document.querySelector("#donation-bar .progress-bar"); | |
barElement.style.width = barPercentage+'%'; | |
barElement.ariaValueNow = barPercentage; | |
document.querySelector("#donation-sum").textContent = formatMoney(participant.sumDonations); | |
document.querySelector("#donation-goal").textContent = formatMoney(participant.fundraisingGoal); | |
} | |
setInterval(queryApi, pollIntervalMs, baseUrl); | |
queryApi(baseUrl); // make the first request immediately, setInterval only triggers after the interval | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment