Update foodsharing_planner.user.js
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Foodsharing Planner
|
// @name Foodsharing Planner
|
||||||
// @namespace http://tampermonkey.net/
|
// @namespace http://tampermonkey.net/
|
||||||
// @version 0.9
|
// @version 0.11
|
||||||
// @updateURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js
|
// @updateURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js
|
||||||
// @downloadURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js
|
// @downloadURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js
|
||||||
// @description Generate a calendar like view as addition to the foodsharing website germany, austria and switzerland
|
// @description Generate a calendar like view as addition to the foodsharing website germany, austria and switzerland
|
||||||
@@ -17,6 +17,96 @@
|
|||||||
// @grant none
|
// @grant none
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
|
class CacheHelper {
|
||||||
|
|
||||||
|
static Write(key, value) {
|
||||||
|
|
||||||
|
var data = {"data" : value};
|
||||||
|
console.log("storing data", data);
|
||||||
|
|
||||||
|
var serializedData = JSON.stringify(data);
|
||||||
|
|
||||||
|
window.localStorage.setItem("fspl_" + key, serializedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Read(key) {
|
||||||
|
var serializedData = window.localStorage.getItem("fspl_" + key);
|
||||||
|
if(!serializedData) return null;
|
||||||
|
var data = JSON.parse(serializedData);
|
||||||
|
return data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ReadDate(key) {
|
||||||
|
var serializedData = window.localStorage.getItem("fspl_" + key);
|
||||||
|
if(!serializedData) return null;
|
||||||
|
|
||||||
|
var data = JSON.parse(serializedData);
|
||||||
|
var date = new Date(data.data);
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PickupsValid() {
|
||||||
|
|
||||||
|
var lastLoadString = this.ReadDate("pickupLoaded");
|
||||||
|
if(!lastLoadString) return false;
|
||||||
|
|
||||||
|
var lastLoad = new Date(lastLoadString);
|
||||||
|
|
||||||
|
var diff = new Date() - lastLoad;
|
||||||
|
diff = diff / 1000;
|
||||||
|
|
||||||
|
if(diff > 600) return false;
|
||||||
|
|
||||||
|
var pickupData = this.Read("pickupData");
|
||||||
|
if(!pickupData) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InvalidatePickups() {
|
||||||
|
this.Write("pickupLoaded", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async GetStoreDetails(storeId) {
|
||||||
|
|
||||||
|
var localStorageKey = "storeDetails-" + storeId;
|
||||||
|
var storeDetails = this.Read(localStorageKey);
|
||||||
|
if(storeDetails) return storeDetails;
|
||||||
|
|
||||||
|
var storeDetailsApi = await Api.GetStoreDetails(storeId);
|
||||||
|
|
||||||
|
var storeDetails = {
|
||||||
|
id: storeId,
|
||||||
|
name: storeDetailsApi.store.name,
|
||||||
|
group: storeDetailsApi.store.group
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Write(localStorageKey, storeDetails);
|
||||||
|
return storeDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async LoadPickupsAsync() {
|
||||||
|
|
||||||
|
var valid = this.PickupsValid();
|
||||||
|
|
||||||
|
if(valid) {
|
||||||
|
var pickupData = this.Read("pickupData");
|
||||||
|
pickupData.forEach(pickup => {
|
||||||
|
pickup.pickup.dateObj = new Date(pickup.pickup.date);
|
||||||
|
});
|
||||||
|
return pickupData;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pickupData = await Api.LoadPickupsAsync();
|
||||||
|
this.Write("pickupData", pickupData);
|
||||||
|
this.Write("pickupLoaded", new Date());
|
||||||
|
|
||||||
|
return pickupData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class Api {
|
class Api {
|
||||||
|
|
||||||
static PickupData;
|
static PickupData;
|
||||||
@@ -31,15 +121,20 @@ class Api {
|
|||||||
var confResult = confirm("Bitte bestätigen!\nAbholung " + dateText + " - " + timeText + " bei " + data.store.name + " buchen?");
|
var confResult = confirm("Bitte bestätigen!\nAbholung " + dateText + " - " + timeText + " bei " + data.store.name + " buchen?");
|
||||||
|
|
||||||
if(confResult) {
|
if(confResult) {
|
||||||
|
Convenience.ShowLoadingOverlay();
|
||||||
var endpoint = "stores/" + data.store.id + "/pickups/" + data.pickup.dateObj.toISOString() + "/" + this.User.id;
|
var endpoint = "stores/" + data.store.id + "/pickups/" + data.pickup.dateObj.toISOString() + "/" + this.User.id;
|
||||||
var result = await this.PostAsync(endpoint);
|
var result = await this.PostAsync(endpoint);
|
||||||
|
|
||||||
// Invalidate and reload
|
// Invalidate and reload
|
||||||
DataStore.Loaded = false;
|
CacheHelper.InvalidatePickups();
|
||||||
BuildPlannerAsync();
|
BuildPlannerAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async GetStoreDetails(storeId) {
|
||||||
|
return await this.GetAsync("stores/" + storeId);
|
||||||
|
}
|
||||||
|
|
||||||
// Api get call function
|
// Api get call function
|
||||||
static async GetAsync(endpoint) {
|
static async GetAsync(endpoint) {
|
||||||
|
|
||||||
@@ -71,7 +166,6 @@ class Api {
|
|||||||
"X-CSRF-Token": this.Token,
|
"X-CSRF-Token": this.Token,
|
||||||
},
|
},
|
||||||
data : JSON.stringify(data),
|
data : JSON.stringify(data),
|
||||||
//data: {name:'yogesh',salary: 35000,email: 'yogesh@makitweb.com'},
|
|
||||||
success: function(response){
|
success: function(response){
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -112,11 +206,11 @@ class Api {
|
|||||||
var apiStoreData = await this.GetAsync("user/current/stores");
|
var apiStoreData = await this.GetAsync("user/current/stores");
|
||||||
|
|
||||||
await Convenience.AsyncForEach(apiStoreData, async (store) => {
|
await Convenience.AsyncForEach(apiStoreData, async (store) => {
|
||||||
|
|
||||||
var apiPickups = await this.GetAsync('stores/' + store.id + '/pickups');
|
var apiPickups = await this.GetAsync('stores/' + store.id + '/pickups');
|
||||||
if(apiPickups.pickups.length > 0) {
|
if(apiPickups.pickups.length > 0) {
|
||||||
|
|
||||||
apiPickups.pickups.forEach(pickup => {
|
apiPickups.pickups.forEach(pickup => {
|
||||||
|
|
||||||
pickup.dateObj = new Date(pickup.date);
|
pickup.dateObj = new Date(pickup.date);
|
||||||
pickup.freeSlots = pickup.totalSlots - pickup.occupiedSlots.length;
|
pickup.freeSlots = pickup.totalSlots - pickup.occupiedSlots.length;
|
||||||
|
|
||||||
@@ -133,8 +227,6 @@ class Api {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DataStore.Loaded = true;
|
|
||||||
|
|
||||||
return pickupData;
|
return pickupData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,8 +365,8 @@ class StyleHelper {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fspl .loading-overlay.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fspl .loading-overlay > div {
|
.fspl .loading-overlay > div {
|
||||||
@@ -316,6 +408,10 @@ class StyleHelper {
|
|||||||
background-color: #d8ffbe;
|
background-color: #d8ffbe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.day .pickup.highlight {
|
||||||
|
background-color: #9ef6ff;
|
||||||
|
}
|
||||||
|
|
||||||
.day .pickup > a {
|
.day .pickup > a {
|
||||||
color: var(--fs-brown);
|
color: var(--fs-brown);
|
||||||
}
|
}
|
||||||
@@ -334,7 +430,7 @@ class StyleHelper {
|
|||||||
|
|
||||||
.day .pickup .img-container {
|
.day .pickup .img-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content min-content;
|
grid-template-columns: min-content min-content min-content;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +488,6 @@ class StyleHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DataStore {
|
class DataStore {
|
||||||
static Loaded = false;
|
|
||||||
static FirstDay;
|
static FirstDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,6 +515,13 @@ class DOMHelper {
|
|||||||
document.querySelectorAll(".navbar-nav.nav-row")[0].append(div);
|
document.querySelectorAll(".navbar-nav.nav-row")[0].append(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CreateNavigationSeparator(parentElement) {
|
||||||
|
|
||||||
|
var separatorElement = this.CreateElement("div", "d-inline");
|
||||||
|
separatorElement.innerHTML = "•";
|
||||||
|
parentElement.append(separatorElement);
|
||||||
|
}
|
||||||
|
|
||||||
static CreateNavigationButton(parentElement, title, iconClass, callback) {
|
static CreateNavigationButton(parentElement, title, iconClass, callback) {
|
||||||
|
|
||||||
var buttonElement = this.CreateElement("button", "button m-1");
|
var buttonElement = this.CreateElement("button", "button m-1");
|
||||||
@@ -433,6 +535,19 @@ class DOMHelper {
|
|||||||
return buttonElement;
|
return buttonElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CreateNavigationTextButton(parentElement, title, callback) {
|
||||||
|
|
||||||
|
var buttonElement = this.CreateElement("button", "button m-1");
|
||||||
|
buttonElement.setAttribute("title", title);
|
||||||
|
buttonElement.innerHTML = title;
|
||||||
|
buttonElement.addEventListener('click',function () {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
|
parentElement.append(buttonElement);
|
||||||
|
return buttonElement;
|
||||||
|
}
|
||||||
|
|
||||||
static CreateLoadingOverlay(parentElement) {
|
static CreateLoadingOverlay(parentElement) {
|
||||||
var loadingOverlay = this.CreateElement("div", "loading-overlay hidden");
|
var loadingOverlay = this.CreateElement("div", "loading-overlay hidden");
|
||||||
|
|
||||||
@@ -498,12 +613,16 @@ async function BuildPlannerAsync() {
|
|||||||
weekPanel.append(sat);
|
weekPanel.append(sat);
|
||||||
weekPanel.append(sun);
|
weekPanel.append(sun);
|
||||||
|
|
||||||
if(!DataStore.Loaded) Api.PickupData = await Api.LoadPickupsAsync();
|
var pickupData = await CacheHelper.LoadPickupsAsync();
|
||||||
|
|
||||||
var lastDayDate = Convenience.GetLastDay(DataStore.FirstDay);
|
var lastDayDate = Convenience.GetLastDay(DataStore.FirstDay);
|
||||||
|
|
||||||
Api.PickupData.sort(function(a, b){return a.pickup.dateObj > b.pickup.dateObj});
|
pickupData.sort(function(a, b){return a.pickup.dateObj > b.pickup.dateObj});
|
||||||
Api.PickupData.forEach(pickup => {
|
|
||||||
|
await Convenience.AsyncForEach(pickupData, async (pickup) => {
|
||||||
|
|
||||||
|
var storeDetails = await CacheHelper.GetStoreDetails(pickup.store.id);
|
||||||
|
pickup.store.details = storeDetails;
|
||||||
|
|
||||||
if(pickup.pickup.dateObj > DataStore.FirstDay && pickup.pickup.dateObj < lastDayDate) {
|
if(pickup.pickup.dateObj > DataStore.FirstDay && pickup.pickup.dateObj < lastDayDate) {
|
||||||
var pickupDiv = CreatePickupDiv(pickup);
|
var pickupDiv = CreatePickupDiv(pickup);
|
||||||
@@ -534,12 +653,48 @@ async function BuildPlannerAsync() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get distinct list of store groups
|
||||||
|
const groups = [];
|
||||||
|
const map = new Map();
|
||||||
|
for (const item of pickupData) {
|
||||||
|
if(!map.has(item.store.details.group.id)){
|
||||||
|
map.set(item.store.details.group.id, true); // set any value to Map
|
||||||
|
groups.push({
|
||||||
|
id: item.store.details.group.id,
|
||||||
|
name: item.store.details.group.name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(groups && groups.length > 1) {
|
||||||
|
var groupButtonDiv = document.querySelectorAll("#groupbuttons")[0];
|
||||||
|
groupButtonDiv.innerHTML = "";
|
||||||
|
groups.forEach(group => {
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationTextButton(groupButtonDiv, group.name, () => {
|
||||||
|
|
||||||
|
var targetPickups = document.querySelectorAll(".group-" + group.id);
|
||||||
|
targetPickups.forEach(targetPickup => {
|
||||||
|
targetPickup.classList.toggle("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationSeparator(groupButtonDiv);
|
||||||
|
}
|
||||||
|
|
||||||
Convenience.HideLoadingOverlay();
|
Convenience.HideLoadingOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreateNavigationButtons(mainPanel) {
|
function CreateNavigationButtons(mainPanel) {
|
||||||
var navigationPanel = DOMHelper.CreateElement("div", "fspl-nav text-center");
|
var navigationPanel = DOMHelper.CreateElement("div", "fspl-nav text-center");
|
||||||
|
|
||||||
|
var groupToggleDiv = DOMHelper.CreateElement("div", "d-inline");
|
||||||
|
groupToggleDiv.setAttribute("id", "groupbuttons");
|
||||||
|
navigationPanel.append(groupToggleDiv);
|
||||||
|
|
||||||
DOMHelper.CreateNavigationButton(navigationPanel, "Vorherige Woche", "fas fa-arrow-left", () => {
|
DOMHelper.CreateNavigationButton(navigationPanel, "Vorherige Woche", "fas fa-arrow-left", () => {
|
||||||
DataStore.FirstDay.setDate(DataStore.FirstDay.getDate() - 7);
|
DataStore.FirstDay.setDate(DataStore.FirstDay.getDate() - 7);
|
||||||
BuildPlannerAsync();
|
BuildPlannerAsync();
|
||||||
@@ -550,33 +705,56 @@ function CreateNavigationButtons(mainPanel) {
|
|||||||
BuildPlannerAsync();
|
BuildPlannerAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
var closeButton = DOMHelper.CreateNavigationButton(navigationPanel, "Heute", "fas fa-times", () => {
|
|
||||||
TogglePlanner();
|
|
||||||
});
|
|
||||||
closeButton.classList.add("button-red");
|
|
||||||
|
|
||||||
DOMHelper.CreateNavigationButton(navigationPanel, "Neu laden", "fas fa-sync", () => {
|
|
||||||
DataStore.Loaded = false;
|
|
||||||
BuildPlannerAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
DOMHelper.CreateNavigationButton(navigationPanel, "Nächste Woche", "fas fa-arrow-right", () => {
|
DOMHelper.CreateNavigationButton(navigationPanel, "Nächste Woche", "fas fa-arrow-right", () => {
|
||||||
DataStore.FirstDay.setDate(DataStore.FirstDay.getDate() + 7);
|
DataStore.FirstDay.setDate(DataStore.FirstDay.getDate() + 7);
|
||||||
BuildPlannerAsync();
|
BuildPlannerAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationSeparator(navigationPanel);
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationButton(navigationPanel, "Toggle Marker", "fas fa-highlighter", () => {
|
||||||
|
|
||||||
|
var highlightElements = document.querySelectorAll(".highlighter");
|
||||||
|
highlightElements.forEach(highlightElement => {
|
||||||
|
highlightElement.classList.toggle("hidden");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationSeparator(navigationPanel);
|
||||||
|
|
||||||
|
DOMHelper.CreateNavigationButton(navigationPanel, "Neu laden", "fas fa-sync", () => {
|
||||||
|
CacheHelper.InvalidatePickups();
|
||||||
|
BuildPlannerAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
var closeButton = DOMHelper.CreateNavigationButton(navigationPanel, "Heute", "fas fa-times", () => {
|
||||||
|
TogglePlanner();
|
||||||
|
});
|
||||||
|
closeButton.classList.add("button-red");
|
||||||
|
|
||||||
mainPanel.prepend(navigationPanel);
|
mainPanel.prepend(navigationPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreatePickupDiv(data) {
|
function CreatePickupDiv(data) {
|
||||||
|
|
||||||
var elementClass = "pickup";
|
var elementClass = "pickup store-" + data.store.id + " group-" + data.store.details.group.id;
|
||||||
if(data.pickup.occupiedSlots.length == data.pickup.totalSlots) elementClass += " pickup-green";
|
if(data.pickup.occupiedSlots.length == data.pickup.totalSlots) elementClass += " pickup-green";
|
||||||
if(data.pickup.occupiedSlots.length < data.pickup.totalSlots && data.pickup.occupiedSlots.length > 0) elementClass += " pickup-yellow";
|
if(data.pickup.occupiedSlots.length < data.pickup.totalSlots && data.pickup.occupiedSlots.length > 0) elementClass += " pickup-yellow";
|
||||||
if(data.pickup.occupiedSlots.length == 0) elementClass += " pickup-red";
|
if(data.pickup.occupiedSlots.length == 0) elementClass += " pickup-red";
|
||||||
|
|
||||||
var element = DOMHelper.CreateElement("div", elementClass);
|
var element = DOMHelper.CreateElement("div", elementClass);
|
||||||
|
|
||||||
|
var highlightLink = DOMHelper.CreateElement("a", "highlighter hidden");
|
||||||
|
highlightLink.innerHTML = '<i class="fas fa-highlighter"></i> ';
|
||||||
|
highlightLink.setAttribute("href", "#");
|
||||||
|
highlightLink.addEventListener('click', function () {
|
||||||
|
var hlPickups = document.querySelectorAll(".pickup.store-" + data.store.id);
|
||||||
|
hlPickups.forEach(hlPickup => {
|
||||||
|
hlPickup.classList.toggle("highlight");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
element.append(highlightLink);
|
||||||
|
|
||||||
var headerSpan = DOMHelper.CreateElement("a", "font-weight-bold", data.store.name);
|
var headerSpan = DOMHelper.CreateElement("a", "font-weight-bold", data.store.name);
|
||||||
headerSpan.setAttribute("href", "https://foodsharing.de/?page=fsbetrieb&id=" + data.store.id);
|
headerSpan.setAttribute("href", "https://foodsharing.de/?page=fsbetrieb&id=" + data.store.id);
|
||||||
headerSpan.setAttribute("target", "_blank");
|
headerSpan.setAttribute("target", "_blank");
|
||||||
|
|||||||
Reference in New Issue
Block a user