diff --git a/foodsharing_planner.user.js b/foodsharing_planner.user.js index 127cc48..8d01dde 100644 --- a/foodsharing_planner.user.js +++ b/foodsharing_planner.user.js @@ -1,9 +1,9 @@ // ==UserScript== // @name Foodsharing Planner // @namespace http://tampermonkey.net/ -// @version 0.3 -// @updateURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js -// @downloadURL https://github.com/TroogS/userscripts/raw/master/foodsharing_planner.user.js +// @version 0.4 +// @updateURL https://github.com/TroogS/userscripts/blob/master/foodsharing_planner.user.js +// @downloadURL https://github.com/TroogS/userscripts/blob/master/foodsharing_planner.user.js // @description Generate a calendar like view as addition to the foodsharing website germany, austria and switzerland // @author A. Beging // @match https://foodsharing.de* @@ -23,17 +23,29 @@ function GM_addStyle (cssStr) { document.head.append(newNode); } +var userId; var token; var gPickupData; var gLoaded = false; var gFirstDayDate; -(function() { +(async function() { 'use strict'; + // Load Token + token = ReadToken(); + if(!token) return; + + // Load user + var meResult = await LoadMe(); + if(!meResult) return; + CreateButton(); gFirstDayDate = GetFirstDay(); - var mainPanel = CreateElement("div", "fspl d-none"); + var weekPanel = CreateElement("div", "week"); + var mainPanel = CreateElement("div", "fspl d-none", weekPanel); + CreateNavigationButtons(mainPanel); + document.querySelectorAll("body")[0].append(mainPanel); })(); @@ -58,7 +70,13 @@ a.navbar-brand.brand span:nth-child(2) span{ height: calc(100vh - 100px); width: calc(100vw - 100px); left: 50px; + display: flex; + flex-direction: column; top: 50px; +} + +.fspl .week { + height: 100%; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; overflow-y: auto; @@ -90,7 +108,7 @@ a.navbar-brand.brand span:nth-child(2) span{ } .day .pickup.pickup-yellow { - border-left-color: #ffc107 + border-left-color: #64ae2457; } .day .pickup.pickup-red { @@ -98,28 +116,36 @@ a.navbar-brand.brand span:nth-child(2) span{ } .day .pickup .img-container { - display: flex; + display: grid; + grid-template-columns: min-content min-content; + gap: 5px; } -.day .pickup .img-container > div { - padding-right: 5px; +.day .pickup .img-container div.not-confirmed { + opacity: .33; +} + +.day .pickup .img-container div.not-confirmed img { + border-inline: 1px solid red; +} + +.day .pickup .img-container > div, +.day .pickup .img-container .empty-slot{ + width: 35px; + height: 35px; } .day .pickup .img-container > div img { - width: 35px; - height: 35px; border-radius: 5px; + border: 1px solid transparent; } .day .pickup .img-container .empty-slot { - width: 34px; display: flex; - height: 34px; justify-content: center; align-items: center; border: 1px solid #533a20; text-decoration: none; - margin-right: 5px; border-radius: 5px; } @@ -129,9 +155,15 @@ a.navbar-brand.brand span:nth-child(2) span{ ` ); +async function LoadMe() { + var apiUserData = await ApiGetCallAsync("user/current"); + userId = apiUserData.id; + return apiUserData; +} + async function BuildPlannerAsync() { - var mainPanel = document.querySelectorAll(".fspl")[0]; - mainPanel.innerHTML = ""; + var weekPanel = document.querySelectorAll(".fspl .week")[0]; + weekPanel.innerHTML = ""; var mon = CreateColumn(0, "Montag"); var tue = CreateColumn(1, "Dienstag"); @@ -141,27 +173,25 @@ async function BuildPlannerAsync() { var sat = CreateColumn(5, "Samstag"); var sun = CreateColumn(6, "Sonntag"); - CreateNavigationButtons(mainPanel); - - mainPanel.append(mon); - mainPanel.append(tue); - mainPanel.append(wed); - mainPanel.append(thu); - mainPanel.append(fri); - mainPanel.append(sat); - mainPanel.append(sun); + weekPanel.append(mon); + weekPanel.append(tue); + weekPanel.append(wed); + weekPanel.append(thu); + weekPanel.append(fri); + weekPanel.append(sat); + weekPanel.append(sun); if(!gLoaded) gPickupData = await LoadPickupsAsync(); var lastDayDate = GetLastDay(gFirstDayDate); - gPickupData.sort(function(a, b){return a.pickup.date > b.pickup.date}); + gPickupData.sort(function(a, b){return a.pickup.dateObj > b.pickup.dateObj}); gPickupData.forEach(pickup => { - if(pickup.pickup.date > gFirstDayDate && pickup.pickup.date < lastDayDate) { + if(pickup.pickup.dateObj > gFirstDayDate && pickup.pickup.dateObj < lastDayDate) { var pickupDiv = CreatePickupDiv(pickup); - switch (pickup.pickup.date.getDay()) { + switch (pickup.pickup.dateObj.getDay()) { case 1: mon.append(pickupDiv); break; @@ -189,13 +219,25 @@ async function BuildPlannerAsync() { } function CreateNavigationButtons(mainPanel) { - var nextButton = CreateElement("button", "nextbutton"); + var navigationPanel = CreateElement("div", "fspl-nav text-center"); + + var prevButton = CreateElement("button", "button m-1"); + prevButton.innerHTML = ''; + prevButton.addEventListener('click',function () { + gFirstDayDate.setDate(gFirstDayDate.getDate() - 7); + BuildPlannerAsync(); + }); + navigationPanel.append(prevButton); + + var nextButton = CreateElement("button", "button m-1"); nextButton.innerHTML = ''; nextButton.addEventListener('click',function () { gFirstDayDate.setDate(gFirstDayDate.getDate() + 7); BuildPlannerAsync(); }); - mainPanel.append(nextButton); + navigationPanel.append(nextButton); + + mainPanel.prepend(navigationPanel); } function GetFirstDay() { @@ -217,6 +259,7 @@ function GetLastDay(firstDayDate) { } function CreatePickupDiv(data) { + var elementClass = "pickup"; 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"; @@ -227,8 +270,8 @@ function CreatePickupDiv(data) { var headerSpan = CreateElement("div", "font-weight-bold", data.store.name); element.append(headerSpan); - var hours = (data.pickup.date.getHours() < 10 ? '0' : '') + data.pickup.date.getHours(); - var minutes = (data.pickup.date.getMinutes() < 10 ? '0' : '') + data.pickup.date.getMinutes(); + var hours = (data.pickup.dateObj.getHours() < 10 ? '0' : '') + data.pickup.dateObj.getHours(); + var minutes = (data.pickup.dateObj.getMinutes() < 10 ? '0' : '') + data.pickup.dateObj.getMinutes(); var timeString = hours + ":" + minutes; var timeSpan = CreateElement("div", "", timeString); element.append(timeSpan); @@ -243,7 +286,9 @@ function CreatePickupDiv(data) { var imgUrl = 'images/mini_q_' + slot.profile.avatar; if(slot.profile.avatar.startsWith('/api/')) imgUrl = slot.profile.avatar + '?w=35&h=35'; - var imgDiv = CreateElement("div"); + var imgClass = ""; + if(!slot.isConfirmed) imgClass = "not-confirmed"; + var imgDiv = CreateElement("div", imgClass); imgDiv.innerHTML = ''; imgContainer.append(imgDiv); }); @@ -252,8 +297,10 @@ function CreatePickupDiv(data) { // Free slots for (let i = 0; i < data.pickup.freeSlots; i++) { var freeSlotA = CreateElement("a", "empty-slot"); - freeSlotA.setAttribute("href", "https://" + window.location.hostname + "/?page=fsbetrieb&id=" + data.store.id); - freeSlotA.setAttribute("target", "_blank"); + freeSlotA.setAttribute("href", "#"); + freeSlotA.addEventListener('click', function () { + BookPickup(data); + }); freeSlotA.innerHTML = ''; @@ -266,6 +313,25 @@ function CreatePickupDiv(data) { return element; } +async function BookPickup(data) { + + var dateText = GetDateText(data.pickup.dateObj); + var timeText = GetTimeText(data.pickup.dateObj); + + var confResult = confirm("Bitte bestätigen!\nAbholung " + dateText + " - " + timeText + " bei " + data.store.name + " buchen?"); + + if(confResult) { + var endpoint = "stores/" + data.store.id + "/pickups/" + data.pickup.dateObj.toISOString() + "/" + userId; + var result = await ApiPostCallAsync(endpoint); + + // Invalidate and reload + gLoaded = false; + BuildPlannerAsync(); + } + + +} + async function LoadPickupsAsync() { let pickupData = new Array(); @@ -277,7 +343,7 @@ async function LoadPickupsAsync() { apiPickups.pickups.forEach(pickup => { - pickup.date = new Date(pickup.date); + pickup.dateObj = new Date(pickup.date); pickup.freeSlots = pickup.totalSlots - pickup.occupiedSlots.length; var obj = { @@ -309,16 +375,19 @@ function CreateColumn(num, title) { var displayDate = new Date(gFirstDayDate); displayDate.setDate(gFirstDayDate.getDate() + num); - console.log(displayDate); - titleDiv.innerHTML = titleDiv.innerHTML + "
" + GetDatetext(displayDate); + titleDiv.innerHTML = titleDiv.innerHTML + "
" + GetDateText(displayDate); var day = CreateElement("div", "day day-" + num, titleDiv); return day; } -function GetDatetext(date) { +function GetTimeText(date) { + return WithLeadingZeros(date.getHours(), 2) + ":" + WithLeadingZeros(date.getMinutes(), 2); +} + +function GetDateText(date) { return WithLeadingZeros(date.getDate(), 2) + "." + WithLeadingZeros(date.getMonth(), 2) + "." + WithLeadingZeros(date.getFullYear(), 4) } @@ -368,14 +437,63 @@ function CreateElement(tagName, classList, content) { return element; } -// Api call function +// Api get call function async function ApiGetCallAsync(endpoint) { - const res = await window.$.ajax({ - url: 'https://' + window.location.hostname + '/api/' + endpoint, - type: 'GET', - }); - return res; + try { + const res = await window.$.ajax({ + url: 'https://' + window.location.hostname + '/api/' + endpoint, + type: 'GET', + headers: { + "accept": "*/*", + "X-CSRF-Token": token, + }, + }); + + return res; + } + catch (e) { + return false; + } +} + +// Api patch call function +async function ApiPatchCallAsync(endpoint, data) { + const res = await window.$.ajax({ + url: 'https://' + window.location.hostname + '/api/' + endpoint, + type: 'PATCH', + contentType: "application/json; charset=utf-8", + headers: { + "accept": "*/*", + "X-CSRF-Token": token, + }, + data : JSON.stringify(data), + //data: {name:'yogesh',salary: 35000,email: 'yogesh@makitweb.com'}, + success: function(response){ + + } + }); + + return res; +} + +// Api post call function +async function ApiPostCallAsync(endpoint, data) { + const res = await window.$.ajax({ + url: 'https://' + window.location.hostname + '/api/' + endpoint, + type: 'POST', + contentType: "application/json; charset=utf-8", + headers: { + "accept": "*/*", + "X-CSRF-Token": token, + }, + data : JSON.stringify(data), + success: function(response){ + + } + }); + + return res; } // Read token from cookie