Discord.js add role by reacting to message - javascript

The following code wont work as I expected. I want a User to react with a checkmark and then log something in the console. Instead of that the bot activates the function by itself and then the function never gets called again.
client.once('ready', () => {
console.log('Ready!');
const exampleEmbed = <unimportant>;
client.channels.cache.get("771041812638728235").send(exampleEmbed).then((message) => {
message.react('✅');
message.createReactionCollector(r => r.emoji.name == '✅')
.on('collect', r => {
console.log("nice");
});
});
});

It might be because the reaction collector is created before the message.react() method finishes executing, causing it to activate on itself. You could either use async/await or a then() callback to make sure the reaction has finished, or simply add a line making sure the user is not a bot in your collector filter.
// method 1:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then(async (message) => {
// ^^^^^
// make sure the function is async
await message.react('✅');
message
.createReactionCollector((r) => r.emoji.name == '✅')
.on('collect', (r) => {
console.log('nice');
});
});
// method 2:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then(message) => {
// .then() callback
message.react('✅').then(() =>
message
.createReactionCollector((r) => r.emoji.name == '✅')
.on('collect', (r) => {
console.log('nice');
}););
});
// method 3:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then((message) => {
message.react('✅');
message
// make sure the user who reacted isn't a bot
.createReactionCollector((r, u) => r.emoji.name == '✅' && !user.bot)
.on('collect', (r) => {
console.log('nice');
});
});

Related

How to stop a function from running in React if another function has returned its data

I have two functions that are calling two endpoints that pull data from a database. One function sometimes returns data quicker than the other.
// Function One
const getDataOne = async => {
await fetch('//some-api/one').then(res => res.json()).then(data => { setDataOne(date) }).catch(err => console.log(err))
}
// Function Two
const getDataTwo = async => {
await fetch('//some-api/two').then(res => res.json()).then(data => { setDataTwo(date) }).catch(err => console.log(err))
}
I have both functions written out separately like above and BOTH are fired at the same time via a onClick How can I stop the slower function from running if the quicker one has returned its data?
The data is populating tables, and if one table is populated before the other than there is no need to populate the slower table.
I know you can use return to exit out of a function, but not sure how we could use that to exit another function if one function has data returned before the other.
Could I do something like? ...
const getSegmentData = async (date, token) => {
getDataOne(token)
if (!getDataOne) {
getDataTwo(date, token)
}
}
Reason I am not a fan of the above, is because if getDataOne takes say 15 seconds...then getDataTwo would have to wait for 15 secs before running. Which would increase the users wait time.
Actual live code with Promise.Race
const getThirdPartyLiveRampSegments = async (date, token) => {
// resets setThirdPartyLiveRampSegments
setThirdPartyLiveRampSegments([])
setThirdPartyLiveRampSegmentsLoading(true)
let count = 0
const timer = setInterval(() => {
count++
setThirdPartyLiveRampSegmentsCount(count)
}, 1000)
if (token) {
try {
await fetch(
`//${
import.meta.env.VITE_BE_HOST
}/api/thirdparty-liveramp-segments?date=${date}&token=${token}`,
)
.then(res => res.json())
.then(data => {
setThirdPartyLiveRampSegments(data)
setThirdPartyLiveRampSegmentsLoading(false)
// clears token input to reuse with date input
setToken('')
// clear timer
clearInterval(timer)
})
} catch (error) {
console.log(error)
}
} else {
setThirdPartyLiveRampSegmentsLoading(false)
popupValidation('error', 'Please enter a segment id')
}
}
const getportalDboAdvpixel = async token => {
// resets setportalDboAdvpixel
setportalDboAdvpixel([])
setportalDboAdvpixelLoading(true)
let count = 0
const timer = setInterval(() => {
count++
setportalDboAdvpixelCount(count)
}, 1000)
if (token) {
try {
await fetch(
`//${
import.meta.env.VITE_BE_HOST
}/api/portal-dbo-advpixel?token=${token}`,
)
.then(res => res.json())
.then(data => {
setportalDboAdvpixel(data)
setportalDboAdvpixelLoading(false)
// clear timer
clearInterval(timer)
})
} catch (error) {
console.log(error)
}
} else {
setportalDboAdvpixelLoading(false)
popupValidation('error', 'Please enter a segment id')
}
}
const getSegmentDataRace = async (date, token) =>
await Promise.race([
getThirdPartyLiveRampSegments(date, token),
getportalDboAdvpixel(token),
])
value from queryRace is undefined...would I have to move all my states etc into the queryRace ?
I have removed the value...but still the slower function getThirdPartyLiveRampSegments is still running. When the others data has been populated.
The Promise.race method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise.
const segmentData = await Promise.race([getDataOne(), getDataTwo()])
To stop the execution of the late function, you can use the JavaScript Promise.race() method with a state variable, as follows for example:
let state = 'idle'
const getDataOne = async => {
await fetch('//some-api/one').then(res => res.json()).then(data => {
if (state === 'idle') {
setDataOne(date)
state = 'success'
}
}).catch(err => console.log(err))
}
const getDataTwo = async => {
await fetch('//some-api/two').then(res => res.json()).then(data => {
if (state === 'idle') {
setDataTwo(date)
state = 'success'
}
}).catch(err => console.log(err))
}
const getSegmentData = async() => await Promise.race([getDataOne(), getDataTwo()])

"mute" command gives random output

if(command === "mute"){
const target = message.mentions.users.first();
if (target) {
if (!message.member.hasPermission("ADMINISTRATOR")) {
return message.reply("Unauthorized");
}
let muted = client.settings.get(message.guild.id, 'mute')
let muteRole = message.guild.roles.cache.find(role => role.name === muted);
let memberTarget = message.guild.members.cache.get(target.id);
let rolelist = memberTarget.roles.cache
.map(r => r)
if (!args[1]) {
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> has been muted`);
return
}
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> will be muted for ${ms(ms(args[1]))}`);
setTimeout(function () {
memberTarget.roles.add(rolelist);
memberTarget.roles.remove(muteRole);
}, ms(args[1]));
} else {
message.channel.send('User not found!');
}
So I have this mute command which removes all your roles, gives you the muteRole, when time is up, it gives back your previous roles and removes the muteRole. The problem I'm having is that it sometimes removes all your roles and doesn't give you the muteRole, other times it doesn't remove the muteRole when the time is up. Sometimes it removes all your roles and doesn't give you the
muteRole and when the times up it doesn't give your roles back...
Basically the outcome is always random. So my question is how do I make it consistent?
The methods .add() and .remove() return a Promise so you should try using await / .then().
If you do it with this, the next function or .then() will not be executed until the promise is completely processed.
Example:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'));
Now you're nearly finished. The last thing you need is the .catch() block, because if the code above fails / throws an error you should catch that:
.catch(err => console.log(`An error occured: ${err}`))
Final result:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'))
.catch(err => console.log(`An error occured: ${err}`));
References
GuildMemberRoleManager (Discord.js)
Promises
Handle promises
Await

Discord.js Voice Connection Timeout

I am currently struggling with a problem of my discord.js bot that plays a music stream via an url. Everything works fine, but after about 12h all players disconnect and I get the following error message: [VOICE_CONNECTION_TIMEOUT]: Connection not established within 15 seconds.
This is my code to join/leave a channel:
function join(voiceChannel, volume = 20) {
return new Promise((resolve, reject) => {
voiceChannel.join().then(vc => {
vc.voice.setSelfDeaf(true);
const dispatcher = vc.play(streamURL);
dispatcher.once('start', () => {
dispatcher.setBitrate(64);
dispatcher.setVolumeLogarithmic(volume / 100);
setTimeout(() => {
if (voiceChannel.members.filter(m => !m.user.bot).size === 0) dispatcher.pause(true);
}, 1500);
resolve();
});
// Tried to reconnect on error but does not seem to work
dispatcher.on('error', () => {
leave(voiceChannel.guild);
setTimeout(() => join(voiceChannel, volume), 5000);
});
}).catch(err => reject(err));
});
}
function leave(guild) {
guild.me?.voice?.connection?.disconnect();
}
I also have this event set up to pause the stream if nobody is listening:
client.on('voiceStateUpdate', (oldState, newState) => {
const state = oldState || newState;
if (state?.member.user.bot) return;
const guild = state?.guild;
if (!guild?.me?.voice?.connection) return;
if (newState.channel === oldState.channel) return;
Guild.findOne({guildId: guild.id}, (err, dbGuild) => {
if (err || !dbGuild) return;
const channel = guild.channels.cache.get(dbGuild.musicChannelId);
if (!channel || !guild.me.voice.connection.dispatcher) return;
const dispatcher = guild.me.voice.connection.dispatcher;
if (channel.members.filter(m => !m.user.bot).size > 0 && dispatcher.paused) {
dispatcher.resume();
return;
}
if (!dispatcher.paused && channel.members.filter(m => !m.user.bot).size === 0) {
dispatcher.pause(true);
}
});
});
Maybe somebody can help me with this. I don't know how to fix this error.
This error is familiar in the Discord.JS package. The problem is that Discord doesn't fully support voice connections for bots, so this has nothing to do with your code. Discord.JS recommends you tho to use their voice package for playing audio in a voice channel. Here are their documentations and here are some of their examples.

Is there a way i can delay the role that my bot gives to a user? [duplicate]

This question already has answers here:
How do I delay a function call for 5 seconds? [duplicate]
(2 answers)
Closed 2 years ago.
I want to know if it's possible to put a time in Milliseconds in which my bot gives the role to a user once they have triggered the command for example once the user types "!Verify" the bot won't give the role to a user until a certain time, This is what i have set up for my bot to do.
bot.on('ready', () => console.log(`${bot.user.tag} has logged in fucker.`));
bot.on('message', async message => {
if (message.author.bot) return;
bot.on('guildMemberAdd', member => {
console.log(member.user.tag);
});
if (message.channel.id === '695566841291997244')
await message.delete();
if (message.content.toLowerCase() === '!verify' && message.channel.id === '695566841291997244')
{
await message.delete().catch(err => console.log(err));
const role = message.guild.roles.cache.get('695565873515069444');
if(role) {
try {
await message.member.roles.add(role);
console.log('Role added!');
}
catch(err) {
console.log(err);
}
}
}
});
You can use the expression setTimeout()
setTimeout(async () => {
await message.delete().catch(err => console.log(err));
const role = message.guild.roles.cache.get('695565873515069444');
if(role) {
try {
await message.member.roles.add(role);
console.log('Role added!');
}
catch(err) {
console.log(err);
}
};
}, 5000);

How to use if else statement if there is an element presented or not

First of all here is my code....
describe('Details page', function () {
//
// Email Field
//
it('Entering Email', function (done) {
browser.driver
.then(() => utils.presenceOf(detailsSpecs.getEmail()))
.then(() => utils.sendKeys(detailsSpecs.getEmail(), userData.email))
.then(() => done());
});
//
// Click Next Step Button
//
it('Clicking Next Step button', function (done) {
browser.driver
.then(() => utils.click(detailsSpecs.getNextStepButton()))
.then(() => done());
});
//
// Wait for stock to fully load
//
it('Waiting for stock to fully load', function (done) {
setTimeout(function () {
done();
}, 5000);
});
if (element.all(by.className("generic-error-heading")).first()) {
it('Clicked all remove button', function (done) {
let allBtns = detailsSpecs.getRemoveButtonDesktop();
allBtns.count()
.then(function (countElement) {
console.log('Find buttons: ', countElement)
for (let i = 0; i < countElement; i++) { // let variables are scoped to the immediate enclosing block denoted by { }
utils.click(detailsSpecs.getRemoveButtonDesktop().first())
browser.sleep(1000) // sleep 1s
}
})
.then(() => {
done();
})
});
//
// Click Next Step Button - Not needed if two above is returning 0
//
it('Clicking Next Step button', function (done) {
browser.driver
.then(() => utils.elementToBeClickable(detailsSpecs.getNextStepButton()))
.then(() => utils.click(detailsSpecs.getNextStepButton()))
.then(() => done());
});
} else {
it('DONE', function (done) {
browser.driver
.then(() => console.log("YES"))
.then(() => done());
});
}
});
I have been trying to speed up my test cases by skipping if a element is not presented. If its not presented then we skip everything inside the if-statement else we do the test cases.
I have a element that I want to look after which is element.all(by.className("generic-error-heading")).first() (Should be 2 but for me its just matters that it is presented or not)
My problem is that right now it just skips it and does the Else statement even though the element is presented in the HTML.
My question is, How can I make a correct if-else statement where it actually do the if-statements if there is a element presented else skip?
change if (element.all(by.className("generic-error-heading")).first())
by:
if (expect(element.all(by.className("generic-error-heading")).first().isDisplayed()).toBe(true))

Categories