content/hifi-content/robin/robinStuff/computerForSeattle/internalVotingApp/voteApp.js
2022-02-14 02:04:11 +01:00

872 lines
No EOL
26 KiB
JavaScript

"use strict";
/* eslint-disable indent */
//
// Example Vue App
//
// Created by Milad Nazeri on 2018-10-11
// Modified from AppUi.js by Howard Stearns on 2 Nov 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* globals Tablet, Script, HMD, Controller, AccountServices, Menu */
(function () { // BEGIN LOCAL_SCOPE
// Dependencies
// /////////////////////////////////////////////////////////////////////////
var AppUi = Script.require('./appUi.js?v12311');
// UTC month 0 = January
// UTC month 10 = November
var UNLOAD_DATE = new Date(Date.UTC(2018, 10, 21, 22, 45));
var BUTTON_NAME = "VOTEAPP";
var VOTE_APP_NAME = "voteApp.js";
var UNLOAD_TIME = 10000;
// need UTC TIME FOR FINAL
// Consts
// /////////////////////////////////////////////////////////////////////////
var URL = Script.resolvePath("./html/Tablet.html?1"),
EVENT_BRIDGE_OPEN_MESSAGE = "eventBridgeOpen";
var GOOGLE_SCRIPTS_URL = "https://script.google.com/macros/s/AKfycbyCnTK2w8gAuPmNzLUnAE4dMJNRtUarjlHFrjKPFBRRQsiy5Q/exec";
var EVENT_NAME = "Futvrelands_11_17_2018";
var DOMAIN = "domain";
var AVATAR = "avatar";
var setupNotLoggedIn = false;
// DATA MANAGEMENT
var domainsInfo = {}; // will use Object.keys to get array
var avatarsInfo = {}; // array for now
var firstLoad = true;
var VOTE_APP_SETTINGS_NAME = "Futvrelands_voteApp";
var DEFAULT_VOTE_APP_SETTINGS = {
domains: [],
voted: {
avatar: "", domain: ""
}
};
// types
var VOTE_AVATARS_GOOGLE = "voteAvatars";
var VOTE_DOMAINS_GOOGLE = "voteDomains";
var GET_INFO_GOOGLE = "getInfo";
var DEBUG = false;
// Init
// /////////////////////////////////////////////////////////////////////////
var ui;
var dataStore = {
unload: false,
loading: true,
loggedin: true,
voted: {
domain: false,
avatar: false
},
openPolls: {
avatar: false,
domain: false,
},
visitedAllDomains: false,
domains: [],
avatars: []
};
// Constructors
// /////////////////////////////////////////////////////////////////////////
// Collections
// /////////////////////////////////////////////////////////////////////////
function shuffle(a) {
var j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
a[i] = a[j];
a[j] = x;
}
return a;
}
// GOOGLE SHEET FUNCTIONS
function getGoogleData() {
// REQUEST list of domains
var params = encodeURLParams({ type: GET_INFO_GOOGLE });
var onComplete = function (request) {
if (DEBUG) {
print("recieved google info");
}
// print ("GOOGLE INFO IS :", JSON.stringify(request));
try {
var gInfo = JSON.parse(request.responseText);
} catch (e) {
console.error("Error parsing request in sendDomainInfoRequest");
}
print ("GOOGLE INFO IS :", JSON.stringify(gInfo));
compareGoogleData(gInfo);
};
var onError = function () {
if (DEBUG) {
print("Error in VoteApp.js: Issue in getGoogleData()");
}
};
sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError);
}
function hasUserVoted(type) {
// var voted = false;
var voteAppSettings = getVoteAppSettings();
print ("Settings says:", voteAppSettings.voted[type], voteAppSettings.voted[type] !== "");
return voteAppSettings.voted[type] !== "";
// if (!voteAppSettings.voted[type]) {
// return false;
// } else {
// return voteAppSettings.voted[type];
// }
// var entryArray = type === DOMAIN ? dataStore.domains : dataStore.avatars;
// entryArray.forEach(function (entry) {
// if (entry.voted === true) { // voted for this entry
// voted = true;
// }
// });
// return voted;
}
function sendAvatarVote(name) {
if (DEBUG) {
print("HELLO 100");
}
avatarsInfo[name.toLowerCase()].voted = true;
dataStore.voted.avatar = true;
if (DEBUG) {
print("Checking 0", JSON.stringify(dataStore.voted.avatar));
}
ui.updateUI(dataStore);
var params = encodeURLParams({
type: VOTE_AVATARS_GOOGLE,
date: Date.now(),
uuid: MyAvatar.sessionUUID,
username: AccountServices.username,
avatar: name,
event: EVENT_NAME
});
var onComplete = function (request) {
var voteAppSettings = getVoteAppSettings();
if (DEBUG) {
print("Checking 1", JSON.stringify(voteAppSettings));
}
voteAppSettings.voted[AVATAR] = name.toLowerCase();
Settings.setValue(VOTE_APP_SETTINGS_NAME, voteAppSettings);
// TODO *** voted
// var avatarName = name.toLowerCase();
// avatarsInfo[avatarName].voted = true;
// dataStore.voted.avatar = true;
// ui.updateUI(dataStore);
};
var onError = function () {
if (DEBUG) {
print("Error in VoteApp.js: Issue in sendAvatarVote()");
}
avatarsInfo[name.toLowerCase()].voted = false;
dataStore.voted.avatar = false;
ui.updateUI(dataStore);
};
sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError);
}
function sendDomainVote(name) {
if (DEBUG) {
print("HELLO 100");
}
domainsInfo[name.toLowerCase()].voted = true;
dataStore.voted.domain = true;
if (DEBUG) {
print("Checking 0", JSON.stringify(dataStore.voted.domain));
}
ui.updateUI(dataStore);
var params = encodeURLParams({
type: VOTE_DOMAINS_GOOGLE,
date: Date.now(),
uuid: MyAvatar.sessionUUID,
username: AccountServices.username,
domain: name,
event: EVENT_NAME
});
var onComplete = function (request) {
var voteAppSettings = getVoteAppSettings();
voteAppSettings.voted[DOMAIN] = name.toLowerCase();
Settings.setValue(VOTE_APP_SETTINGS_NAME, voteAppSettings);
if (DEBUG) {
print("Checking 2", JSON.stringify(voteAppSettings));
}
// TODO *** voted
// if not vote or request failed
// var domainName = name.toLowerCase();
// domainsInfo[domainName].voted = true;
// dataStore.voted.domain = true;
// ui.updateUI(dataStore);
};
var onError = function () {
if (DEBUG) {
print("Error in VoteApp.js: Issue in sendDomainVote()");
}
domainsInfo[name.toLowerCase()].voted = false;
dataStore.voted.domain = false;
ui.updateUI(dataStore);
};
sendRequest(GOOGLE_SCRIPTS_URL, params, onComplete, onError);
}
// Helper Functions
// /////////////////////////////////////////////////////////////////////////
function getVoteAppSettings () {
var voteAppSettings = Settings.getValue(VOTE_APP_SETTINGS_NAME, DEFAULT_VOTE_APP_SETTINGS);
if (Array.isArray(voteAppSettings)) {
// to correct old format
var settings = {
domains: voteAppSettings,
voted: {
avatar: "", domain: ""
}
};
voteAppSettings = settings;
}
return voteAppSettings;
}
function onHostChanged(host) {
if (DEBUG) {
print("Host changed to: " + host);
}
if (DEBUG) {
print("location is visitable: ", host, isLocationVisitable(host));
}
var domainName = host.toLowerCase();
if (domainsInfo[domainName]) {
domainsInfo[domainName].visited = true;
// set value in settings to save it
var voteAppSettings = getVoteAppSettings();
clientVisitedList = voteAppSettings.domains;
clientVisitedList.push(domainName);
voteAppSettings.domains = clientVisitedList;
Settings.setValue(VOTE_APP_SETTINGS_NAME, voteAppSettings);
dataStore.visitedAllDomains = checkVisitedAllDomains(clientVisitedList);
ui.updateUI(dataStore);
}
}
function compareGoogleData(gData) {
// {
// openPolls: {
// avatar: true,
// domain: true
// },
// domains: [ "TheSpot", "Studio" ],
// avatars: [
// { name: "Robin", image: "hello" }
// ]
// };
if (DEBUG) {
print("CHANGED GOOGLE DATA");
}
dataStore.loading = true;
ui.updateUI(dataStore);
var changedPolls = setPollsOpen(gData.openPolls);
var changedDomains = setDomains(gData.domains);
var changedAvatars = setAvatars(gData.avatars);
var voteAppSettings = getVoteAppSettings();
dataStore.visitedAllDomains = checkVisitedAllDomains(voteAppSettings.domains);
dataStore.voted.avatar = hasUserVoted(AVATAR);
dataStore.voted.domain = hasUserVoted(DOMAIN);
var needsUpdateUI = changedPolls && changedAvatars && changedDomains;
if (firstLoad) {
shuffle(dataStore.avatars);
}
dataStore.loading = false;
ui.updateUI(dataStore);
}
function setPollsOpen(gPolls) {
// {
// avatar: true,
// domain: truex
// },
if (DEBUG) {
print("polls are ", gPolls.avatar, gPolls.domain);
}
var changed = false;
if (dataStore.openPolls.avatar !== gPolls.avatar || dataStore.openPolls.domain !== gPolls.domain) {
changed = true;
dataStore.openPolls.avatar = gPolls.avatar;
dataStore.openPolls.domain = gPolls.domain;
}
return changed;
}
function setDomains(gDomains) {
// [ "TheSpot", "Studio" ],
// add domains to the location array
if (DEBUG) {
print("voting 3");
}
var changed = false;
var existingDomains = Object.keys(domainsInfo);
if (DEBUG) {
print("EXISTING ", JSON.stringify(existingDomains));
}
if (DEBUG) {
print("NEW GOOGLE ", JSON.stringify(gDomains));
}
gDomains.forEach(function (domainName) {
var lowercase = domainName.toLowerCase();
var voteAppSettings = getVoteAppSettings();
var votedName = voteAppSettings.voted[DOMAIN];
if (votedName !== "") {
dataStore.voted.domain = true;
}
var existingIndex = existingDomains.indexOf(lowercase);
if (existingIndex !== -1) {
existingDomains.splice(existingIndex, 1);
if (DEBUG) {
print("INDEX EXISTING ", JSON.stringify(existingDomains), JSON.stringify(existingIndex));
}
}
if (firstLoad || !domainsInfo[lowercase]) {
// need to get all domain info because of first load
// or new domain encountered
changed = true;
domainsInfo[lowercase] = {
name: domainName,
image: "",
visited: false,
index: -1,
voted: votedName && lowercase === votedName ? true : false
};
sendDomainInfoRequest(lowercase);
}
});
if (DEBUG) {
print(" EXISTING LENGTH", JSON.stringify(existingDomains.length));
}
if (existingDomains.length > 0) {
if (DEBUG) {
print("INSIDE DELETE 1");
}
// found domains to delete
removeItems (existingDomains, DOMAIN);
}
if (changed === true) {
Script.setTimeout(function () {
setDataStoreDomainsInfo();
ui.updateUI(dataStore);
}, 500);
}
return changed;
}
function sendDomainInfoRequest(domainName) {
// domainName is lowercase
if (DEBUG) {
print("voting 4");
}
var url = "https://metaverse.highfidelity.com/api/v1/places/" + domainName;
var paramString = "";
var onComplete = function (request) {
if (DEBUG) {
print("voting 5");
}
try {
var response = JSON.parse(request.responseText);
} catch (e) {
console.error("Error parsing request in sendDomainInfoRequest");
}
var image = response.data.place.previews
? response.data.place.previews.thumbnail
: "http://img.youtube.com/vi/kEJDqO7WrKY/hqdefault.jpg"; // url to image
domainsInfo[domainName].image = image;
ui.updateUI(dataStore);
if (DEBUG) {
print(JSON.stringify(image));
}
};
var onError = function () {
if (DEBUG) {
print("Error in VoteApp.js: Issue in sendDomainInfoRequest()");
}
};
sendRequest(url, paramString, onComplete, onError);
}
function setDataStoreDomainsInfo() {
if (DEBUG) {
print("voting 6");
}
if (firstLoad) {
var domains = [];
var domainKeys = Object.keys(domainsInfo);
domainKeys.forEach(function (domainKey, index) {
domainsInfo[domainKey].index = index;
domainsInfo[domainKey].visited = hasUserVisitedDomain(domainKey);
domains.push(domainsInfo[domainKey]);
});
shuffle(domains);
firstLoad = false;
} else {
}
dataStore.domains = domains;
}
function hasUserVisitedDomain(domainName) {
if (DEBUG) {
print("voting 7");
}
// domainName is lowercase
var visitedDomainList = getVoteAppSettings().domains;
var visited = visitedDomainList.indexOf(domainName) !== -1;
return visited;
}
function setAvatars(gAvatars) {
// { name: "Robin", image: "hello" }
// update avatar images if necessary
var changed = false;
var existingAvatars = Object.keys(avatarsInfo);
var voteAppSettings = getVoteAppSettings();
var votedName = voteAppSettings.voted[AVATAR];
if (votedName !== "") {
dataStore.voted.avatar = true;
}
gAvatars.forEach(function (avatar, index) {
if (DEBUG) {
print("Avatar ", index, JSON.stringify(avatar));
}
var lowercase = avatar.name.toLowerCase();
var existingIndex = existingAvatars.indexOf(lowercase);
if (existingIndex !== -1) {
existingAvatars.splice(existingIndex, 1);
}
if (firstLoad || !avatarsInfo[lowercase]) {
// need to get all domain info because of first load
// or new domain encountered
changed = true;
avatarsInfo[lowercase] = {
name: avatar.name,
image: avatar.image,
index: dataStore.avatars.length - 1, // not using this yet
voted: votedName && lowercase === votedName ? true : false
};
dataStore.avatars.push(avatarsInfo[lowercase]);
} else if (avatarsInfo[lowercase].image !== avatar.image) {
// image changed, update to new image
avatarsInfo[lowercase].image = avatar.image;
}
});
if (existingAvatars.length > 0) {
// found avatars to delete
removeItems(existingAvatars, AVATAR);
}
Script.setTimeout(function () {
ui.updateUI(dataStore);
}, 500);
return changed;
}
function removeItems(listToDelete, type) {
if (DEBUG) {
print("REMOVE ITEM", type, JSON.stringify(listToDelete));
}
var list = type === DOMAIN ? dataStore.domains : dataStore.avatars;
var infoStore = type === DOMAIN ? domainsInfo : avatarsInfo;
if (DEBUG) {
print("INSIDE DELETE 2", JSON.stringify(list));
}
listToDelete.forEach(function (nameToDelete) {
// for every avatar to delete
var deleteIndex = -1;
for (var i = 0; i < list.length; i++) {
// search
var current = list[i];
var lowercase = current.name.toLowerCase();
if (DEBUG) {
print("COMPARE ", nameToDelete, lowercase);
}
if (nameToDelete === lowercase) {
// found
deleteIndex = i;
if (DEBUG) {
print("INSIDE DELETE 3", JSON.stringify(deleteIndex));
}
break;
}
}
if (deleteIndex !== -1) {
if (DEBUG) {
print("INSIDE DELETE 4", JSON.stringify(deleteIndex));
}
// remove from dataStore list and the avatar object itself
list.splice(deleteIndex, 1);
delete infoStore[nameToDelete];
}
});
ui.updateUI(dataStore);
}
function checkVisitedAllDomains(clientVisitedList) {
if (DEBUG) {
print("voting 8");
}
if (DEBUG) {
print("Domain info: ", JSON.stringify(domainsInfo));
}
if (DEBUG) {
print("ClientVisitedList info: ", JSON.stringify(clientVisitedList));
}
var visitedAllDomains = Object.keys(domainsInfo).reduce(function (visitedAll, domainName) {
var wasVisited = clientVisitedList.indexOf(domainName) !== -1;
return visitedAll && wasVisited;
}, true);
return visitedAllDomains;
}
function isLocationVisitable(host) {
var domainName = host.toLowerCase();
var isCurrentLocationVisitable = Object.keys(domainsInfo).indexOf(domainName) !== -1; // currentLocation is on list
return isCurrentLocationVisitable;
}
// Takes an object as argument and creates the paramString for sendRequest() to send along with a GET request
// Example argument { username: "MyUsername", displayName: "MyDisplayName" }
function encodeURLParams(params) {
var paramPairs = [];
for (var key in params) {
paramPairs.push(key + "=" + params[key]);
}
return paramPairs.join("&");
}
// url - the request url
// paramString - the encodedURLParams as arguments to be sent, if not needed can be null or ""
// onComplete - the callback after requst completes see defaultOnComplete for standards
// onError - the callback after an error
function sendRequest(url, paramString, onComplete, onError) {
var defaultOnComplete = function (request) {
if (DEBUG) {
print("sendRequest() is complete");
}
try {
var info = JSON.parse(request.responseText);
} catch (e) {
console.error("Error parsing response in defaultOnComplete");
}
if (DEBUG) {
print ("Response info is: ", JSON.stringify(info));
}
}
var defaultOnError = function () {
console.error("sendRequest() timed out or there was another error.");
}
// Set request callbacks or assign to the default
var onCompleteCallback = onComplete ? onComplete : defaultOnComplete;
var onErrorCallback = onError ? onError : defaultOnError;
// Create the request
var request = new XMLHttpRequest();
// If paramString is truthy (exists and is not an empty string) append the param string to the url
// For GET requests, this is how we send in arguments
var requestURL = paramString
? url + "?" + paramString
: url;
if (DEBUG) {
print("REQUEST URL IS: ");
print(requestURL);
}
request.open('GET', requestURL);
request.timeout = 10000;
request.ontimeout = onErrorCallback;
request.onreadystatechange = function () {
// request.readyState === 4 indicates the request was complete and returned
if (request.readyState === 4) {
onCompleteCallback(request);
}
};
request.send();
}
// Tablet
// /////////////////////////////////////////////////////////////////////////
function startup() {
ui = new AppUi({
buttonName: BUTTON_NAME,
home: URL,
onMessage: onMessage,
graphicsDirectory: Script.resolvePath("./icons/"),
onOpened: onOpened
});
location.hostChanged.connect(onHostChanged);
checkDateToUnload();
// onOpened();
}
function onOpened() {
var isUnloading = checkDateToUnload();
if (isUnloading) {
return;
}
var isLoggedIn = AccountServices.isLoggedIn();
if (isLoggedIn) {
print("ROBIN: is logged in");
dataStore.loggedin = true;
getGoogleData(); // asynchronous and will call compareGoogleData(gData) once complete
} else {
// is not logged in
print("ROBIN: is NOT logged in");
handleNotLoggedInStatus();
}
}
function handleNotLoggedInStatus() {
if (!setupNotLoggedIn) {
print("Robin: setup is not logged in");
dataStore.loggedin = false;
AccountServices.loggedInChanged.connect(loggedIn);
setupNotLoggedIn = true;
dataStore.loading = false;
ui.updateUI();
}
function loggedIn() {
print("Robin: Logging In!!");
AccountServices.loggedInChanged.disconnect(loggedIn);
setupNotLoggedIn = false;
dataStore.loggedin = true;
}
}
function unload() {
if (DEBUG) {
print("WATCH OUT!");
}
location.hostChanged.disconnect(onHostChanged);
}
function checkDateToUnload() {
if (DEBUG) {
print("CHECK DATE");
}
var now = new Date();
if (now > UNLOAD_DATE) {
var scriptList = ScriptDiscoveryService.getRunning();
var url;
scriptList.forEach(function (scriptInfo) {
if (scriptInfo.name === VOTE_APP_NAME ) {
url = scriptInfo.url;
dataStore.unload = true;
dataStore.loading = false;
ui.updateUI(dataStore);
}
});
if (DEBUG) {
print("UNLOAD DATE");
}
Script.setTimeout(function() {
ScriptDiscoveryService.stopScript(url);
}, UNLOAD_TIME);
return true;
}
return false;
}
// *** web event actions
var GOTO = "goto",
VOTE_AVATAR = "vote_avatar",
VOTE_DOMAIN = "vote_domain";
function onMessage(data) {
// EventBridge message from HTML script.
switch (data.type) {
case EVENT_BRIDGE_OPEN_MESSAGE:
ui.updateUI(dataStore);
break;
case GOTO:
Window.location = "hifi://" + data.value;
break;
case VOTE_AVATAR:
console.log(hasUserVoted(AVATAR));
if (hasUserVoted(AVATAR) === false) {
sendAvatarVote(data.value);
}
break;
case VOTE_DOMAIN:
console.log(hasUserVoted(DOMAIN));
if (hasUserVoted(DOMAIN) === false) {
sendDomainVote(data.value);
}
break;
default:
}
}
// Main
// /////////////////////////////////////////////////////////////////////////
startup();
Script.scriptEnding.connect(unload);
}()); // END LOCAL_SCOPE