diff --git a/client_src/css/popup.css b/client_src/css/popup.css index f12fc78..1f3fc83 100644 --- a/client_src/css/popup.css +++ b/client_src/css/popup.css @@ -4,7 +4,7 @@ h2.device-name { text-align: center; } .device-name::after { - content: "#" attr(data-id); + content: "#" attr(data-id) ", " attr(data-minutes_ago); float: right; margin-right: 1em; font-size: 80%; diff --git a/client_src/js/DeviceData.mjs b/client_src/js/DeviceData.mjs index c0bb8e2..3a4c8ae 100644 --- a/client_src/js/DeviceData.mjs +++ b/client_src/js/DeviceData.mjs @@ -26,8 +26,12 @@ class DeviceData { // Create a map to help us lookup ids faster this.device_map = new Map(); - for(let device of this.devices) + for(let device of this.devices) { + // Parse the last_seen date into a JS date object + device.last_seen = new Date(device.last_seen); + // Add the device to the device map this.device_map.set(device.id, device); + } } /** diff --git a/client_src/js/Helpers/DateHelper.mjs b/client_src/js/Helpers/DateHelper.mjs index 470e16c..0669fbf 100644 --- a/client_src/js/Helpers/DateHelper.mjs +++ b/client_src/js/Helpers/DateHelper.mjs @@ -10,4 +10,43 @@ function human_duration_unit(milliseconds) { return "year"; } -export { human_duration_unit }; +/** + * Calculates the time since a particular datetime and returns a + * human-readable result. + * @source Ported from PHP in Pepperminty Wiki https://github.com/sbrl/Pepperminty-Wiki/blob/712e954/core/05-functions.php#L55-L89 + * @param {Date} datetime The datetime to convert. + * @return {string} The time since the given timestamp as a human-readable string. + */ +function human_time_since(datetime) { + return human_time((new Date() - datetime) / 1000); +} +/** + * Renders a given number of seconds as something that humans can understand more easily. + * @source Ported from PHP in Pepperminty Wiki https://github.com/sbrl/Pepperminty-Wiki/blob/712e954/core/05-functions.php#L55-L89 + * @param {int} seconds The number of seconds to render. + * @return {string} The rendered time. + */ +function human_time(seconds) +{ + if(seconds < 0) return "the future"; + + let tokens = new Map([ + [ 31536000, 'year' ], + [ 2592000, 'month' ], + [ 604800, 'week' ], + [ 86400, 'day' ], + [ 3600, 'hour' ], + [ 60, 'minute' ], + [ 1, 'second' ] + ]); + for(let unit of tokens) { + if (seconds < unit[0]) continue; + numberOfUnits = Math.floor(seconds / unit[0]); + return `${numberOfUnits} ${unit[1]}${((numberOfUnits > 1)?'s':'')} ago`; + } +} + +export { + human_duration_unit, + human_time_since, human_time +}; diff --git a/client_src/js/LayerDeviceMarkers.mjs b/client_src/js/LayerDeviceMarkers.mjs index 11f2a1b..1cc4eb9 100644 --- a/client_src/js/LayerDeviceMarkers.mjs +++ b/client_src/js/LayerDeviceMarkers.mjs @@ -11,6 +11,7 @@ import Emitter from 'event-emitter-es6'; import Config from './Config.mjs'; import DeviceReadingDisplay from './DeviceReadingDisplay.mjs'; import GetFromUrl from './Helpers/GetFromUrl.mjs'; +import { human_time_since } from './Helpers/DateHelper.mjs'; class LayerDeviceMarkers extends Emitter { constructor(in_map, in_device_data) { @@ -70,6 +71,7 @@ class LayerDeviceMarkers extends Emitter { console.info("Fetching device info for device", device_id); let device_info = JSON.parse(await GetFromUrl(`${Config.api_root}?action=device-info&device-id=${device_id}`)); + device_info.last_seen = new Date(`${device_info.last_seen}+0000`); // Force parsing as UTC device_info.location = [ device_info.latitude, device_info.longitude ]; delete device_info.latitude; delete device_info.longitude; @@ -88,6 +90,8 @@ class LayerDeviceMarkers extends Emitter { `Device: ${device_info.name}` )); result.querySelector(".device-name").dataset.id = device_info.id; + result.querySelector(".device-name").dataset.last_seen = device_info.last_seen; + result.querySelector(".device-name").dataset.minutes_ago = human_time_since(device_info.last_seen); // ----------------------------------