Incrementing number and saving it with put method - javascript

There is a page with two images where you can vote to one of the pictures.
After the voting two new images is loading randomly and so on. The votes should be
incremented and saved to the server, but here comes the problem that I can not put the incremented
number, because I get an array: [{"votes":2},null]
I'd like to increment, save, and load the two new images with one onClick event.
Here it is what I tried to do:
handelVote(id) {
this.setState(
prevState => ({ //I get an array
voteNr: prevState.castles.map(c =>
c.id === id ? { votes: c.votes + 1 } : console.log(this.state.voteNr)
)
})
this.getCastles(),
axios
.put("............." + id, {
vote: this.state.voteNr
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
})
);
}
here I'm getting the data from the server and load only two pictures and the belonging two votes:
componentDidMount() {
if (this.state.castles.length === 0) this.getCastles();
}
async getCastles() {
let castles = [];
let voteNr = [];
let i = [];
for (i = 0; i < 1; i++) {
const f = z(4); //random nr from Choise.js
const uniqueSet = new Set(f); //to avoid duplicates
const b = [...uniqueSet];
if (b.length < 2) {
b.shift();
b.push(1, 2); //in case of duplicates load the first two images
}
let res = await axios.get(".....");
let { data } = res;
let castle = data;
this.setState({ castles: castle });
for (i = 0; i < 2; i++) {
//load only two
var t;
t = b[i];
let name = castle[t].name;
let id = castle[t]._id;
let image = castle[t].image;
let votes = castle[t].vote;
castles.push({ image, name, id, votes });
voteNr.push({votes});
}
}
this.setState(prevState => ({
loading: false,
castles: [...castles]
}));
}
and after this comes the already qouted onClick event what makes the problems.

Related

How to modify the code to only use one of the folders with the similar first word in their name using javascript?

The following code is used to generate NFTs by combining layers which are located inside folders.
What if I wanted to use the entire collection of folders provided in props.folderNames but also force the program that if among the folders provided there were more than one folder with the similar first word (for example "Face Old" and "Face New") it only use one of these folders for the generation process randomly and not both of the at once.
For example the the first artwork is generated by combining the layers inside the "Face Old" and "Hats New" folder and the second artwork is generated by combining the layers inside the "Face new" and "Hats futuristic" folder etc.
const constructLayerToDna = (_dna = "", _layers = []) => {
let mappedDnaToLayers = _layers.map((layer, index) => {
let selectedElement = layer.elements.find(
(e) => e.id == cleanDna(_dna.split("-")[index])
);
return {
name: layer.name,
selectedElement: selectedElement,
};
});
return mappedDnaToLayers;
};
const startCreating = async () => {
props.setProgress(0);
let editionCount = 1;
let failedCount = 0;
while (editionCount <= props.config.supply) {
let newDna = createDna(props.folderNames);
if (isDnaUnique(dnaList, newDna)) {
let results = constructLayerToDna(newDna, props.folderNames);
let loadedElements = [];
results.forEach((layer) => {
loadedElements.push(loadLayerImg(layer));
});
await Promise.all(loadedElements).then((renderObjectArray) => {
ctx.clearRect(0, 0, props.config.width, props.config.height);
renderObjectArray.forEach((renderObject, index) => {
drawElement(renderObject, index);
});
saveImage(editionCount);
addMetadata(newDna, editionCount);
saveMetaDataSingleFile(editionCount);
console.log(`Created edition: ${editionCount}`);
});
dnaList.add(filterDNAOptions(newDna));
editionCount++;
props.setProgress(editionCount - 1);
} else {
console.log("DNA exists!");
failedCount++;
if (failedCount >= 1000) {
console.log(
`You need more layers or elements to grow your edition to ${props.config.supply} artworks!`
);
process.exit();
}
}
}
writeMetaData(JSON.stringify(metadataList, null, 2));
};
I tried adding the following code:
const folderGroups = props.folderNames.reduce((groupedFolders, folder) => {
const folderName = folder.toString().split(" ")[0];
groupedFolders[folderName] = groupedFolders[folderName] || [];
groupedFolders[folderName].push(folder);
return groupedFolders;
}, {});
const selectedFolders = Object.values(folderGroups).map((folderGroup) => {
const randomIndex = Math.floor(Math.random() * folderGroup.length);
return folderGroup[randomIndex];
});
and also changed the startCreating function to this:
const startCreating = async () => {
props.setProgress(0);
let editionCount = 1;
let failedCount = 0;
while (editionCount <= props.config.supply) {
let newDna = createDna(selectedFolders);
if (isDnaUnique(dnaList, newDna)) {
let results = constructLayerToDna(newDna, selectedFolders);
// rest of the code
However, this didn't work and resulted in the program to only use one of the folders provided to it out of the entire collection of folders.

Break the loop in the map function and move

So basically im working on a cron job in my app that fires every 3 hours and updating users 'score' by calling the RiotApi
basically the function so far
exports.updatePlayersPoints = async () => {
console.log('STARTED UPDATING');
try {
const players = await UserLadder.findAll();
await Promise.all(
players.map(async (player) => {
const p = await RiotAccount.findOne({
where: {
userId: player.userId,
},
include: RiotRegions,
});
const beginTime = new Date(player.dataValues.createdAt);
let data;
try {
const res = await axios.get(
`https://${
p.dataValues.riot_region.dataValues.name
}.api.riotgames.com/lol/match/v4/matchlists/by-account/${
p.dataValues.accountId
}?queue=420&beginTime=${beginTime.getTime()}&api_key=${
process.env.RIOT_KEY
}`
);
data = res.data;
} catch (error) {
if (!error.response.status === 404) {
console.error(error);
}
}
if (!data) {
return;
}
let totalScore = player.dataValues.userPoints;
await Promise.all(
data.matches.map(async (match, i) => {
if (i < 15) {
const { data } = await axios.get(
`https://${p.dataValues.riot_region.dataValues.name}.api.riotgames.com/lol/match/v4/matches/${match.gameId}?api_key=${process.env.RIOT_KEY}`
);
const calculateScore = () => {
return new Promise((resolve) => {
const { stats } = _.find(
data.participants,
(o) => o.championId === match.champion
);
const killsPts = stats.kills * 2;
const deathPts = stats.deaths * -1.5;
const assistsPts = stats.assists;
const wardsPts = stats.wardsPlaced / 4;
const firstBloodPts = stats.firstBloodKill ? 3 : 0;
const firstBloodAssistPts = stats.firstBloodAssist ? 3 : 0;
const firstTowerPts = stats.firstTowerKill ? 2 : 0;
const firstTowerAssistPts = stats.firstTowerAssist ? 2 : 0;
const score =
killsPts +
deathPts +
assistsPts +
wardsPts +
firstBloodPts +
firstBloodAssistPts +
firstTowerPts +
firstTowerAssistPts;
totalScore += score;
resolve();
});
};
await calculateScore();
}
})
);
const user = await UserLadder.findOne({
where: {
userId: player.userId,
},
});
user.userPoints = parseFloat(totalScore);
user.lastGameId = data.matches[0].gameId;
await user.save();
})
);
console.log('FINISHED UPDATING');
} catch (error) {
console.error(error);
}
};
Basically it just looks up the table userladder to find the players that are signed to the ladder and for each one of these players it fires a map function that makes a request to the riotapi to get the match history of this player and then later make an inside map function to map each one of these matches.
but basically I updated it to now keep track of the game id of the last call before 3 hours so it doesn't have to make request that was already done.
user.lastGameId = data.matches[0].gameId;
but now in my second map function that maps the matches I wasn't it so that if the last game from my database matches the game id that currently being mapped I want to stop the map function and not continue this record or the ones after because it also means they all have been already counted.
but I can not seem to find a way to do it.
i tried using break; but it didn't work
any ideas?
using for loop
I tried a small test with for loop so I tried
for (let i = 0; i < 15; i++) {
await new Promise(async (resolve, reject) => {
const match = data.matches[i];
console.log(match);
resolve();
if (i === 1) {
break;
}
});
}
but I still go the same error
SyntaxError: Illegal break statement
Instead of trying to "break" a map, you should filter the matches that you want to process before you execute the map.
Something like this:
await Promise.all(
const filteredMatches = data.matches.filter(match => match.gameId > previousId);
filteredMatches.map(async (match, i) => { ...
More on filter() in javascript.
Edit: If generated id's are random and are not ordered, you can store all previous id's in a Set, and then just ask if it has been previously added
await Promise.all(
const filteredMatches = data.matches.filter(match => mySet.has(match.gameId));
filteredMatches.map(async (match, i) => { ...
More on Set in javascript.

JS how to do a double each.for

for a gaming app, a player can select card types for his/her deck (first eachfor) and amount of each card type (2nd each.for). After this, I want to push this selection in an array.
Following part of my code works well:
//defining card types
let availableRoles = ["werwolf", "dorfbewohner", "seherin", "hexe", "jaeger", "armor", "heiler", "prinz"]
let gameState = {
roles: {}
}
//set card amount 0
;(() => {
availableRoles.forEach(role => gameState.roles[role] = 0)
})()
//adding & subtracting roles
const addRole = role => {
gameState.roles[role]++
document.getElementById(role + "_btn_remove").disabled = false;
document.getElementById(role + '_cnt').innerHTML = gameState.roles[role];
document.getElementById('total_cnt').innerHTML = totalNumberOfRolesInGame();
}
const removeRole = role => {
gameState.roles[role]--
if (gameState.roles[role] <= 0) {
gameState.roles[role] = 0
document.getElementById(role + "_btn_remove").disabled = true;
}
document.getElementById(role + '_cnt').innerHTML = gameState.roles[role];
document.getElementById('total_cnt').innerHTML = totalNumberOfRolesInGame();
}
const totalNumberOfRolesInGame = () => Object.values(gameState.roles).reduce((a,c) => a + c)
Now I want to hit every role and hit every number insider the role by using for each command. But it does not work.
var rollen = []
function Holmir() {
;(() => {
gameState.roles.forEach(element => element.forEach (myRole => rollen.push(myRole))
) })()
{
I'm thankful for any help!
forEach works with an array.
gameState = {
roles: {}
}
gameState.roles gives you an object so forEach won't work with this

Pass result .js to another .js

I want to pass result from var url (index.js) to game.js, so that it follows the process that I need. Is that possible? Any help will be appreciated, thank you very much.
I put the complete index.js code so that you understand what you want to achieve.
I've tried to do it in many ways, but none successfully, I don't know what else to try.
index.js
//SELECT CATEGORY
//CATEGORY => 8, 9, 10, 11, ..., 32
const obj = {
url: 'https://opentdb.com/api.php?amount=20',
category: '',
difficulty: ''
}
let newUrl = Object.values(obj).join('');
function selectCat() {
var c = document.getElementById('cat').value;
console.log(c);
obj.category = c;
newUrl = Object.values(obj).join('');
}
//SELECT DIFFICULTY
//DIFFICULTY => any, easy, medium, hard
function selectDiff() {
var d = document.getElementById('diff').value;
console.log(d);
obj.difficulty = d;
newUrl = Object.values(obj).join('');
}
/*NEST VALUE TO CATEGORY AND DIFFICULTY
NEXT TO THE URL TO GET THE NEWURL*/
//CLICK EVENT BUTTON
var btnFetch = document.getElementById('fetch');
/*var url =*/ btnFetch.addEventListener('click', function(e) {
console.log(newUrl);});
game.js
fetch(
url
)
.then(res => {
return res.json();
})
.then(loadedQuestions => {
console.log(loadedQuestions.results);
questions = loadedQuestions.results.map(loadedQuestion => {
const formattedQuestion = {
question: loadedQuestion.question
};
const answerChoices = [...loadedQuestion.incorrect_answers];
formattedQuestion.answer = Math.floor(Math.random() * 3) + 1;
answerChoices.splice(
formattedQuestion.answer - 1,
0,
loadedQuestion.correct_answer
);
answerChoices.forEach((choice, index) => {
formattedQuestion["choice" + (index + 1)] = choice;
});
return formattedQuestion;
});
startGame();
})
.catch(err => {
console.error(err);
});

Firebase cloud function Deadline exceeded error in nested promises

I have a firebase cloud function that is unable to finish executing. I suspect my code can be dramatically improved but I'm not quite sure how.
I've made the query as specific as possible to try and reduce the number of documents required to iterate through but that didn't solve the issue.
I get a Deadline Exceeded error which I suspect is due to the fact that I'm iterating through so many documents and trying to update them.
I increased the timeout (9 minutes)and memory allocation (2GB) in Google cloud console but that didn't help either.
exports.updatePollWinner = functions.runWith(runtimeOpts).firestore.document('triggerAccuracyCalculation/{id}').onCreate(trigger => {
const week = trigger.get('week');
const scoringTags = ["STD", "0.25PPR", "0.5PPR", "PPR", "0.10PPC", "0.25PPC", "0.5PPC", "4PTPASS", "5PTPASS", "6PTPASS", "-2INT", "TEPREMIUM"]
let winningChoiceIds = [];
let totalPollIds = [];
return db.collection("polls").where("sport", "==", 1).where("week", "==", week).where("pollType", "==", "WDIS").get()
.then((querySnapshot) => {
console.log("A");
querySnapshot.forEach((doc) => {
totalPollIds.push(doc.id);
let pollData = doc.data();
// extract relevant scoring tags
let tags = pollData.tags.filter(tag => scoringTags.includes(tag.code)).map(tag => tag.code);
// if no scoring setting is tagged, then use STD - determine what STD is
// extract player from each option
let winner = {score: 0, choice: {}, choiceId: null};
let cnt = 0;
pollData.choices.forEach((choice) => {
let choiceId = choice.id
let mappedChoices = choice.players.map(player => {
return { displayName: player.displayName, playerId: player.playerId, position: player.position, team: player.team }
});
// ToDo: What happens if someone posts a poll with two players in one option? This poll should be ignoree from accuracy calculation
// ignmore if option has more than one player
// if (mappedChoices.length > 1) return;
const player = mappedChoices[0]
// We can't score defense
if (player.position === "DEF") {
return;
}
const playerId = player.playerId;
// Make FFN API call to retrieve stats for that player in that weekconst statsEndpoint = `https://www.fantasyfootballnerd.com/service/player/json/${functions.config().ffnerd.key}${req.url}`;
const statsEndpoint = `https://www.fantasyfootballnerd.com/service/player/json/${functions.config().ffnerd.key}/${playerId}`;
const json = {"Stats": {"2019": ""}, "Player": {}};
https.get(statsEndpoint, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
const weekString = week.toString();
const fetchedStats = JSON.parse(data).Stats
if (!fetchedStats) return;
const response = fetchedStats["2019"]
if (!response) return;
// TODO SCORE KICKERS AND DEFENSES
const stats = response[weekString];
let score = 0;
stats["recYards"] ? score += parseInt(stats["recYards"]) / 10 : false
stats["recTD"] ? score += parseInt(stats["recTD"]) * 6 : false
stats["rushYards"] ? score += parseInt(stats["rushYards"]) / 10 : false
stats["rushTD"] ? score += parseInt(stats["rushTD"]) * 6 : false
stats["xpMade"] ? score += parseInt(stats["xpMade"]) : false
stats["fgMade"] ? score += parseInt(stats["fgMade"]) * 3 : false
stats["kickoffRet"] ? score += parseInt(stats["kickoffRet"]) / 10 : false
stats["SackYards"] ? score -= parseInt(stats["SackYards"]) / 10 : false
stats["fumbleLost"] ? score -= parseInt(stats["fumbleLost"]) * 2 : false
// Determine winner
// ToDo: handle ties
if (score > winner.score) {
winner.score = score;
winner.choiceId = choiceId;
winner.choice = choice;
}
if (cnt>=pollData.choices.length-1){
// Save player object on the poll Document (include choice ID)
winningChoiceIds.push(winner.choiceId);
const pollDoc = db.doc(`polls/${doc.id}`);
pollDoc.update({winner: winner});
}
cnt++;
});
}).on("error", (err) => {
console.log("Error: ", err.message);
});
});
});
console.log("B");
return false;
}).then(() => {
console.log("C");
let dateToQueryAfter = new Date(new Date("08/22/19").setHours(0,0,0,0))
return db.collection("users").where("recentVote", ">", dateToQueryAfter).get()
})
.then((querySnapshot) => {
console.log("D");
const promises = [];
querySnapshot.forEach((doc) => {
const p = db.collection("votes").where("uid", "==", doc.id).where("week", "==", week).where("pollType", "==", "WDIS").get()
promises.push(p)
});
return Promise.all(promises)
})
.then((querySnapshots) => {
console.log("E");
querySnapshots.forEach((querySnapshot) => {
if (querySnapshot.docs.length <= 0) return;
const uid = querySnapshot.docs[0].data().uid
const retrieveUserDoc = db.doc(`users/${uid}`);
let correctVotes = 0;
let cnt = 0;
let totalVotes = 0;
let pollVoteIds = [];
let pollVoteIdsCorrect = [];
querySnapshot.docs.forEach((doc) => {
const voteData = doc.data();
if (totalPollIds.includes(voteData.poll)) {
pollVoteIds.push(voteData.poll)
totalVotes++;
if (winningChoiceIds.includes(voteData.choice)) {
pollVoteIdsCorrect.push(voteData.poll)
correctVotes++;
}
}
if (cnt>=querySnapshot.size-1){
console.log("Updating user ID: ", uid);
retrieveUserDoc.update({
['accuracyWeeks.week'+week]: true,
['accuracy.week'+week]: {
totalVotes: totalVotes,
correct: correctVotes,
accuracy: correctVotes/totalVotes,
correctVoteIds: pollVoteIdsCorrect,
totalVoteIds: pollVoteIds
}
});
}
cnt++;
})
});
console.log("F");
return false;
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
});

Categories