First time I use createReactionCollector.
It doesn't work, when I react the collector gets nothing.
But when I make the bot react, I get that reaction but, not mine.
const collector = startMessage.createReactionCollector(x => {
return true
}, { time: 5000 })
collector.on('collect', (r, collector) => {
console.log("collected");
})
collector.on('end', r => {
console.log(r)
})
That's because you're not using a valid filter, you need to pass the reaction and user parameters into the filter and use them like so:
const filter = (reaction, user) => reaction.emoji.name === '👌' && user.id === 'someID';
Then add the filter to the collector like so:
const collector = message.createReactionCollector(filter, { time: 15000 });
These are from the example of createReactionCollector() on the docs
Related
I'm following this tutorial and made a few changes to typescript for learning purposes but got stuck when creating a filter function from react context script.
I have a working function called getCampaigns where it maps all the object from the blockchain like below:
const getCampaigns = useCallback(async () => {
const signer = accountProvider?.getSigner();
const contractWithSigner = contract?.connect(signer);
const campaigns = await contractWithSigner?.getCampaigns();
const parsedCampaigns = campaigns.map((campaign, i) => ({
owner: campaign.owner,
title: campaign.title,
description: campaign.description,
target: ethers.utils.formatEther(campaign.target.toString()),
deadline: campaign.deadline.toNumber(),
amountCollected: ethers.utils.formatEther(
campaign.amountCollected.toString()
),
image: campaign.image,
pId: i,
}));
return parsedCampaigns;
}, [contract, accountProvider]);
This is working as it should and manage to see the content like below:
[{…}]
0:
amountCollected:"0.0"
deadline:1673049600000
description: "I want to build a Robot"
image:"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA
owner:"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
pId:0
target:"3.0"
title:"Build a Robot"
As my new function, I wanted to filter from the getCampaigns function only to display all of the owner's post and display it on a Profile page like below:
const getUserCampaigns = async () => {
const allCampaigns = await getCampaigns();
const filteredCampaigns = allCampaigns.filter(
campaign => campaign.owner === account
);
return filteredCampaigns;
};
So when I console.log filteredCampaigns, it doesnt show any result. Is there anything that I missed here? The typeof account is string and it is working if I put it like this
const filteredCampaigns = allCampaigns.filter(
campaign => campaign.owner === "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
);
Update:
So far I have been playing around with the syntax and console.log the following:
const filteredCampaigns = allCampaigns.filter(campaign => {
console.log(campaign.owner);
return campaign.owner === account;
});
it's managed to fetch the same data and the typeof campaign.owner is in fact a string (same as typeof account). But when I run it like this
const filteredCampaigns = allCampaigns.filter(campaign => {
console.log(campaign.owner === account.toString());
return campaign.owner === account;
});
It's still come out as false
It is working if I hard coded like this
console.log(campaign.owner === "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")
filteredCampaign is empty, because the content of account doesn't match any content of campaign.owner.
Check the content of account.
allCampaign.filter(elementOfArray => condition)
return element only if condition is true.
The logic of your getUserCampaign, looks right for what you want to do.
Not sure if this is the case, but may have sense, to have a field/global var/state where you keep all your campaigns.
In this way when you want to filter, you can do something like
const filteredCampaign = (account: string) => {
return allCampaigns.filter(campaign => campaign.owner === account);
}
filteredCampaign is not anymore async call, because doesn't have to await and receive the
account
I'm making a giveaway command for my server, all from my knowledge without following a tutorial.
I'm running into an issue. I don't know how to use the collector's information to determine if there is enough reactions or not, and to get a winner.
My code:
const filter = (reaction, user) => {
return reaction.emoji.name === '🎉' && user.id === message.author.id;
};
const collector = message.createReactionCollector({ filter, time: duration });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
setTimeout(() => {
if (collector <= 1) {
message.channel.send("Not enough people reacted for me to draw a winner")
return}
let winner = (m) => m.reaction.cache.get("🎉").users.cache.filter((u) => !u.bot).random();
channel.send(`Congratulations ${winner} You just won the **${prize}**!`
);
}, duration );
Any help please? Thank you!
I am writing a discord bot to ping a user at a set interval. And I want to know if there is a way to compile this to not have to copy and paste the entire script to have the same thing happen for other users.
client.on('message', message => {
if(message.content === '&ping zach forever') {
setInterval(() => {
var yourchannel = client.channels.cache.get('704506336339034115');
yourchannel.send('<#UserID>');
}, "5000");
}});
client.on('message', message => {
if(message.content === '&ping maxx forever') {
setInterval(() => {
var yourchannel = client.channels.cache.get('704506336339034115');
yourchannel.send('<#UserID>');
}, "5000");
}});
I have no experience with discord bots in particular, but as general JavaScript advice:
const users = ["zach", "maxx"];
client.on('message', message => {
const splits = message.content.split(' ');
if (splits.length === 3 && splits[0] === '&ping' && splits[2] === 'forever' && users.includes(splits[1])) {
setInterval(() => {
var yourchannel = client.channels.cache.get('704506336339034115');
yourchannel.send('<#UserID>');
}, "5000");
}
});
Simply expand the users array with the required names. You can also modify the array at runtime with .push() and .splice(). If you'd like the bot to trigger even if there is text after the command, check for splits.length >= 3 instead.
PS. As a general rule, using var is frowned upon these days. Use const for values only assigned once, and let otherwise.
Edit:
Here's a bit more fleshed out example, that includes hardcoded user ID's for each name, applies the duration (in seconds), and also includes a &stop command to stop pinging a certain person. (Code is not tested to run correctly, since I don't have a discord bot account, and don't want to make one either)
const users = new Map(Object.entries({
"zach": "UserID1",
"maxx": "UserID2"
}));
const active = new Map();
client.on('message', message => {
const splits = message.content.split(' ');
if (splits.length === 3 && splits[0] === '&ping' && users.has(splits[1])) {
const channel = client.channels.cache.get('704506336339034115');
const message = `<#${users.get(splits[1])}>`;
const time = Number(splits[2]);
if (isNaN(time) && splits[2] !== 'forever') {
// Passed a time that wasn't a number - possibly send back an error message
} else {
const id = setInterval(() => channel.send(message), 5000);
active.set(splits[1], id);
if (!isNaN(time)) setTimeout(() => clearInterval(id), time * 1000);
}
}
if (splits.length === 2 && splits[0] === '&stop') {
const id = active.get(splits[1]);
if (id) {
clearInterval(id);
active.delete(splits[1]);
}
}
});
I have a little question.
I'm currently in the progress of trying out creating a tickets bot, and had the idea of having so when a user types !close, it would present him with an embed, asking him if he really does want to close it using reactions (:wastebasket: for Yes, :x: for No).
If the user reacts for Yes, the channel will close. As for No, the embed message will be deleted.
I will be glad to help.
You can use something a little like this:
const prevMsg = message
message.channel.send(embed).then(message => {
const questionMessage = message;
questionMessage.react('🗑️')
.then(() => questionMessage.react('❌'));
const filter = (reaction, user) => {
return ['🗑️', '❌'].includes(reaction.emoji.name) && user.id === prevMsg.author.id;
};
questionMessage.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🗑️') {
// closing function here
} else {
questionMessage.delete();
}
})
})
If it didn't work, please let me know!
I'm trying to make it so when my bot picks up a reaction in a specific channel, it'll see if it hit 10 reactions on a specific reaction. Then it'll delete the reacted message and post it into another specific channel with a message attached to it.
Here's the code
doopliss.on('message', message => {
if (message.channel.id === "587066921422290953") {
setTimeout(function(){
message.react(message.guild.emojis.get('587070377696690177'))
}, 10)
setTimeout(function(){
message.react(message.guild.emojis.get('587071853609353256'))
}, 50)
setTimeout(function(){
message.react(message.guild.emojis.get('587070377704816640'))
}, 100)
}
});
const message = require("discord.js");
const emoji = require("discord.js");
const reaction = require("discord.js");
doopliss.on('message', message => {
if (message.channel.id === "587066921422290953") {
let limit = 2; // number of thumbsdown reactions you need
if (message.reaction.emoji.name == message.guild.emojis.get('587070377696690177')
&& reaction.count >= limit) message.reaction.message.delete();
let tcontent = message.reaction.message.content
let accept = message.guild.channels.get('587097086256873483')
accept.send(`${tcontent} \`\`\`This server suggestion has been accepted by the community! Great job! Now a staff member just needs to forward it to username.\`\`\``)
}})
Can't figure out how to do this.
Expected Result: Bot sees if post has 10 reactions, then delete it and take the same message to a different channel
Actual Result: An error occurs Cannot read 'channel' property
First I want to say that some question here like this one have what you search.
Moreover, the discord documentation and the guide provide an awaiting reactions section.
There is some other question that refer to the subject or the function used in the guide and by searching a bit you can even find question like this one which is almost the same thing as you.
However, here is a complete example of what you want to do. You can add a timer to the promise instead of just waiting. I didn't use the reaction collector because promise are a bit faster, but you can also create a management system of multiple collector , or use the client.on('messageReactionAdd').
const Discord = require('discord.js');
const config = require('./config.json');
const channelSuggestion = '<channelID>';
const channelSend = '<channelID>';
const emojiReact = '<emojiID>';
const prefixSuggestion = '!';
const reactionMax = 11;
const client = new Discord.Client();
client.on('ready', () => {
console.log('Starting!');
client.user.setActivity(config.activity);
});
client.on('message', (msg) => {
if ((msg.content[0] === prefixSuggestion) && (msg.channel.type === 'dm')){
sendSuggestion(msg);
}
});
function filter(reaction) {
return reaction.emoji.id === emojiReact;
}
function moveSuggestion(msg) {
client.channels.get(channelSend).send(msg.content)
.then(() => msg.delete()).catch(err => console.log(error));
}
function sendSuggestion(msg){
client.channels.get(channelSuggestion).send(msg.content.substr(1))
.then((newMsg) => newMsg.react(emojiReact))
.then((newMsgReaction) =>
newMsgReaction.message
.awaitReactions(filter, {max: reactionMax})//, time: 15000, errors: ['time']})
.then(collected => {
moveSuggestion(newMsgReaction.message);
})
// .catch(collected => {
// console.log(`After a minute, only ${collected.size} out of 10 reacted.`);
// })
);
}
client.login(config.token)
.then(() => console.log("We're in!"))
.catch((err) => console.log(err));
The bot will listen to dm message (I don't know how you want your bot to send the suggestion message, so I made my own way) which start with a !.
Then the bot will send a message to a specific channel, wait for N person to add a reaction, and then will send the message to another channel.