]> rtime.felk.cvut.cz Git - coffee/coffee-flask.git/blob - templates/main.js
Fix "ValueError: cannot convert float NaN to integer"
[coffee/coffee-flask.git] / templates / main.js
1 var flask = "{{ url_for('hello', _external=True) }}"
2
3 // State variables
4
5 var updateRemote = undefined;           // defined iff remote server accessible
6 var timeToLogout = undefined;           // defined during logout countdown
7 var logoutTimer;
8 var reloadTimer = undefined;
9 var id_user;                            // ID of the user who is to be accounted for the next coffee
10 var identifier_registration = false;    // true if identifier is supposed to be registered for user
11 var eventMsg = undefined;               // Feedback message about the last event performed by the user
12
13 console.log("hello from flask");
14 //sendJSON("{\"type\":\"empty\"}");
15
16 function update(id, msg) {
17     document.getElementById(id).innerHTML = msg;
18 }
19
20 function replayOfflineQueue() {
21     if (localStorage) {
22         let queue = JSON.parse(localStorage.getItem("offlineQueue")) || [];
23         if (Array.isArray(queue)) {
24             queue.forEach(function (entry) {
25                 updateRemote(entry.data, new Date(entry.time));
26             });
27             localStorage.removeItem("offlineQueue");
28         }
29     }
30 }
31
32 var flavorChosen;
33
34 // Central function to update UI elements. To ensure that the UI is
35 // consistent, other code should only change state variables and then
36 // call this function. This function updates the UI to match the state.
37 function updateUI()
38 {
39     try {
40         let offline = updateRemote === undefined;
41
42         document.getElementById("local").style.display = !offline ? "none" : "block";
43         document.getElementById("remote").style.display = offline ? "none" : "block";
44
45         if (offline) {
46             showOfflineQueue();
47             return;
48         }
49
50         if (eventMsg !== undefined) {
51             update("eventMsg", eventMsg);
52             eventMsg = undefined;
53         }
54         if (id_user !== undefined) {
55             document.getElementById("nextStep").innerHTML = "Now select a beverage on the coffee machineā€¦";
56         } else if (flavorChosen !== undefined) {
57             document.getElementById("nextStep").innerHTML = "Enjoy your " + flavorChosen + "!";
58         }
59
60         if (timeToLogout !== undefined)
61             document.getElementById("logout_button").innerHTML = '<br>logout<br>(' + timeToLogout + ' s)';
62     }
63     catch (err) {
64         console.log("updateUI error: ", err);
65     }
66 }
67
68 function hiddenUpdateRemote(json, time = new Date()) {
69     var msg = JSON.parse(json);
70
71     switch(msg.type) {
72         case "empty":
73             break;
74         case "rfid":
75             if (identifier_registration) {
76                 ajax("POST", "user/identifier/add", JSON.stringify({ id: msg.uid }), "content");
77
78                 addIdentifier_finish();
79             } else {
80                 login(msg.uid);
81             }
82             break;
83         case "keys":
84             if (!identifier_registration) {
85                 var flavor = getFlavor(msg.key);
86                 if (flavor !== "") {
87                     addCoffee(flavor, time);
88                 } else if (msg.key == "A") {
89                     // When pressing 'Menu' key, logout to not count
90                     // subsequent keys as coffee orders.
91                     logout();
92                 }
93             }
94             break;
95         case "ajax_failure":
96             ajax(msg.method, msg.route, msg.data, msg.id);
97             break;
98     }
99
100     sendLog(json);
101 }
102
103 function loadRemote(string) {
104     var xhr = new XMLHttpRequest();
105     xhr.onreadystatechange = function() {
106         if (this.readyState == 4) {
107             if (this.status == 200) {
108                 update("remote", this.responseText);
109                 updateRemote = hiddenUpdateRemote;
110                 replayOfflineQueue();
111                 updateUI();
112                 clearTimeout(reloadTimer);
113                 if (id_user)
114                     logout();
115                 else
116                     ajax("GET", "home", "", "content"); // Load home screen on first load or reload
117             } else {
118                 // Cancel current timer for the case when loadRemote()
119                 // was called multiple times (e.g. multiple ajax()
120                 // calls failed simultaneously).
121                 clearTimeout(reloadTimer);
122                 reloadTimer = setTimeout(loadRemote, 1000);
123             }
124         }
125     };
126     xhr.open("GET", flask, true);
127     xhr.send();
128 }
129
130 loadRemote();
131
132 function ajax(method, route, data, id) {
133     var xhr = new XMLHttpRequest();
134     xhr.onreadystatechange = function() {
135         if (this.readyState == 4) {
136             if (this.status == 200) {
137                 update(id, this.responseText);
138                 updateUI();
139             } else {
140                 updateRemote = undefined;
141                 updateUI();
142                 loadRemote(); // Try to contact the server periodically
143
144                 if (localStorage) {
145                     var ajax_failure = JSON.stringify({
146                         type: "ajax_failure",
147                         method: method,
148                         route: route,
149                         data: data,
150                         id: id
151                     });
152                     let queue = JSON.parse(localStorage.getItem("offlineQueue")) || [];
153                     queue.push({ time: Date.now(), data: ajax_failure });
154                     try {
155                         localStorage.setItem("offlineQueue", JSON.stringify(queue));
156                     }
157                     catch (err) {
158                         console.log(err);
159                     }
160                 }
161             }
162         }
163     };
164     xhr.open(method, flask + route, true);
165     xhr.withCredentials = true;
166     xhr.setRequestHeader("Content-type", "application/json");
167     if (method === "POST") {
168         xhr.send(data);
169     } else {
170         xhr.send();
171     }
172 }
173
174
175 function login(id) {
176     ajax("POST", "login", id, "content");
177     id_user = id;
178     countingTimeLogout(120);
179 }
180
181 function logout() {
182     sendReset();
183     ajax("GET", "logout", "", "content");
184     id_user = undefined;
185     timeToLogout = undefined;
186     identifier_registration = false;
187     window.scrollTo(0, 0); // Scroll up
188 }
189
190 function countingTimeLogout(count_time)
191 {
192     clearTimeout(logoutTimer);
193     timeToLogout = count_time;
194     updateUI();
195     if (count_time == 0) {
196         logout();
197     } else {
198         logoutTimer = setTimeout(function() { countingTimeLogout(count_time - 1); }, 1000);
199     }
200 }
201
202 function renameUser() {
203     ajax("GET", "user/rename?name=" +  document.getElementById("username").value, "", "content");
204 }
205
206 function getFlavor(letter) {
207     switch (letter) {
208         case "E": return "espresso";
209         case "C": return "cappuccino";
210         case "B": return "latte macchiato";
211         case "D": return "espresso lungo";
212         default: return "";
213     }
214 }
215
216 function addCoffee(flavor, time = new Date()) {
217     var data = JSON.stringify({
218         time: time.toISOString(),
219         flavor: flavor
220     });
221     if (id_user) {
222         ajax("POST", "coffee/add", data, "content");
223         flavorChosen = flavor;
224         id_user = undefined;
225         countingTimeLogout(10); //mean 10 seconds
226     }
227 }
228
229
230 function addEvent(event_name, action_msg, time = new Date()) {
231     var data = JSON.stringify({
232         time: time.toISOString(),
233         event_name: event_name,
234         uid: id_user
235     });
236     if (id_user) {
237         eventMsg = "You have " + action_msg + ". Thanks!"
238         ajax("POST", "event", data, "content");
239         window.scrollTo(0, 0); // Scroll up
240     }
241 }
242
243
244 function addIdentifier_start() {
245     identifier_registration = true;
246     document.getElementById("addIdentifier").disabled = true;
247     document.getElementById("labelIdentifier").style.visibility = "visible";
248     document.getElementById("abortIdentifier").disabled = false;
249 }
250
251 function addIdentifier_finish() {
252     identifier_registration = false;
253     document.getElementById("addIdentifier").disabled = false;
254     document.getElementById("labelIdentifier").style.visibility = "hidden";
255     document.getElementById("abortIdentifier").disabled = true;
256 }
257
258 function disableIdentifier(id) {
259     ajax("POST", "user/identifier/disable", JSON.stringify({ id: id }), "content");
260 }
261
262 function renameIdentifier(i) {
263     var data = JSON.stringify({
264         id: document.getElementById("identifier_" + i).innerText,
265         name: document.getElementById("identifier_name_" + i).value
266     });
267
268     ajax("POST", "user/identifier/rename", data, "content");
269 }
270
271 function sendLog(json) {
272     ajax("POST", "log", json, "log");
273 }
274
275 function tellCoffeebot(what)
276 {
277     ajax("POST", "tellCoffeebot", JSON.stringify({text: what}), "log");
278 }