Cannot read property 'activities' of undefined - node.js

my problem is that when user go live and have live status on discord, in console i get error "
TypeError: Cannot read property 'activities' of undefined" and bot is crashing. I expect to bot send a message with link to stream.
Discord.js - v12
Code:
client.on('presenceUpdate', (oldMember, newMember) => {
const channel = newMember.guild.channels.cache.find(x => x.name === "test");
if (!channel) return;
let oldStreamingStatus = oldMember.presence.activities.type ? oldMember.presence.activities.streaming : false;
let newStreamingStatus = newMember.presence.activities.type ? newMember.presence.activities.streaming : false;
if(oldStreamingStatus == newStreamingStatus){
return;
}
if(newStreamingStatus){
if(message.member.roles.cache.find(r => r.name === "test")) {
channel.send(`${newMember.user}, is live URL: ${newMember.presence.activities.url} ${newMember.presence.activities.name}`);
return;
}else
return;
}});

oldMember and newMember are of type Presence, so you do not need to access the .presence property to get the member's activities, you can simply use oldMember.activities. For newMember.presence.activities.url & newMember.presence.activities.name do this:
newMember.activities.find(activity => activity.type === 'STREAMING').name
newMember.activities.find(activity => activity.type === 'STREAMING').url
Either way however, your code won't work, since activities returns an array of Activity so you can go about doing this in 2 ways.
(Recommended) Looking for Activity of type STREAMING:
let oldStreamingStatus = oldMember.activities.find(activity => activity.type === 'STREAMING') ? true : false;
let newStreamingStatus = newMember.activities.find(activity => activity.type === 'STREAMING') ? true : false;
Getting the first Activity:
let oldStreamingStatus = oldMember.activities[0].type === 'STREAMING' ? true : false
let newStreamingStatus = newMember.activities[0].type === 'STREAMING' ? true : false

The problem is, that oldMember and newMember are already presences, so remove .presence.

Related

Discord.js args TypeError: Cannot read property 'toLowerCase' of undefined

I'm trying to make a code which converts words like "eu" to "europe" but i keep getting the error TypeError: Cannot read property 'toLowerCase' of undefined if the usage was correct
const Discord = require('discord.js')
const db = require('quick.db')
module.exports = {
name: 'code',
description: 'sends your among us code to the codes channel',
example: 'code AAAAAA eu',
async execute(message, args, client, prefix) {
let ch = db.fetch(`${message.guild.id}_codechannel`)
if(ch === null) ch = 'not set'
if(ch === 'not set') return message.channel.send(`A codes channel has not been set here tell an admin to set it using the config command`)
const voiceChannel = message.member.voice.channel;
if(!voiceChannel) return message.channel.send('You must join a voice channel')
const inv = await voiceChannel.createInvite({
maxAge: 0,
unique: false,
maxUses: 100,
});
const thecode = args[0];
if (thecode.length !== 6) return message.reply('The code can only be 6 characters long');
const thecodeUC = thecode.toUpperCase();
const region = args[1];
let r = '';
if(region.toLowerCase() === 'eu' || region.toLowerCase() === 'europe') r = 'Europe';
if(region.toLowerCase() === 'na' || region.toLowerCase() === 'northamerica') r = 'North America';
if(region.toLowerCase() === 'as' || region.toLowerCase() === 'asia') r = 'Asia';
if(region === 'undefined' || region === '') return message.channel.send('the only regions available are: Europe(eu), Northamerica(na) and Asia(as)');
let channel = message.guild.channels.cache.get(ch)
const embed = new Discord.MessageEmbed()
.setColor('#00ffff')
.setAuthor(message.member.user.tag, message.author.avatarURL())
.setTitle('New Among Us Code')
.addField('Code', `${thecodeUC}`, true)
.addField('Region', `${r}`, true)
.addField('Voice Channel', `[Click Here](${inv})`, true)
.setThumbnail(message.guild.iconURL({ dynamic: true }));
channel.send(embed);
message.reply(`Sent your code in the codes channel`);
}
}
I'm really confused what's the issue since i have
if(region === 'undefined' || region === '') return message.channel.send('the only regions available are: Europe(eu), Northamerica(na) and Asia(as)');
to return a message when "region" is undefined
Let's try to understand what it says:
"TypeError: Cannot read property 'toLowerCase' of undefined"
In here you are trying to read and call a function called toLowerCase.
if(region.toLowerCase() === 'eu'
From documentation you can find that this function is a part of String data type:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase
This means, that other things, for example undefined do not have this function
You might be also confused by the word property in "Cannot read property 'toLowerCase'. Well, this is because String is a object, and it defines properties. Function toLowerCase is a property defined on object String.
String is also what you would call a data type. Hence the TypeError.
This means that when JavaScript interpreter reads the line:
if(region.toLowerCase() === 'eu' || region.toLowerCase() === 'europe') r = 'Europe';
The variable region has a value undefined
And the check:
if(region === 'undefined' || region === '') return message.channel.send('the only regions available are: Europe(eu), Northamerica(na) and Asia(as)');
is performed only after JS trying to read that property.

discord.js - TypeError: Cannot read property 'cache' of undefined Error

I get error "TypeError: Cannot read property 'cache' of undefined" when using my command which sends a message to another server
fsn.readJSON("././orders.json").then((orderDB) => {
let ticketID = args[0];
let order = orderDB[ticketID];
// If the order doesn't exist.
if(order === undefined) {
message.reply(`Couldn't find order \`${args[0]}\` Try again.`);
return;
}
if(!args[0]) {
message.reply('Correct usage: \`.deliver (order ID)\` Remember to have an attachment while using the command.');
return;
}
if (message.author.id === order.chef) {
if (order.status === "Ready") {
if (message.attachments.size > 0) {
message.attachments.forEach(Attachment => {
message.channels.cache.get(order.channelID).send(`Hi <#${order.userID}> I'm <#${order.chef}> and here is your taco that you ordered. Remember you can use \`.feedback [Feedback]\` to give us feedback on how we did. ${Attachment.url}`);
})
} else {
return message.reply('Please attach an attachment while using the command.');
}
delete orderDB[ticketID];
fsn.writeJSON("./orders.json", orderDB, {
replacer: null,
spaces: 4
}).then(() => {
message.reply(`Order \`${args[0]}\` Has been sent.`)
console.log(`Order ${args[0]} has been delivered by ${order.chefmention}`)
}).catch((err) => {
if (err) {
message.reply(`There was an error while writing to the database! Show the following message to a developer: \`\`\`${err}\`\`\``);
}
});
} else {
message.reply("This order hasn't been claimed yet. Run `.claim [Order ID]` to claim it.");
}
} else {
message.channel.send(`Only the chef of the order ${order.chefmention} may deliver this order`);
}
})
i guess the error is with the message.channels.cache.get(order.channelID).send(`Hi <#${order.userID}> I'm <#${order.chef}> and here is your taco that you ordered. Remember you can use \`.feedback [Feedback]\` to give us feedback on how we did. ${Attachment.url}`); the "order.channel.ID" is stored in the orders.json file and is defined i don't know whats wrong with the code
Message object doesn't have channels property, you probably meant to use:
message.client.channels.cache.get() //...

Forge viewer isLayerVisible is always false

For some reason I get always false on viewer.isLayerVisible(layerNode).
I followed this tutorial https://forge.autodesk.com/blog/toggle-sheet-layer-visibility
I have event handler on LAYER_VISIBILITY_CHANGED_EVENT, here is my code snippet in typescript:
viewer.addEventListener(Autodesk.Viewing.LAYER_VISIBILITY_CHANGED_EVENT, (e) => {
var root = viewer.model["myData"].layersRoot; //getLayersRoot() is not a function for some reason
var overlayLayer = viewer["getSelectedLayer"]();
if (viewer["layerRoot"] != undefined) {
var layerNode = root.children.filter((e) => { return e.name === overlayLayer })
var isLayerVisible = viewer.isLayerVisible(layerNode);
//show layer
if (isLayerVisible) {
viewer.impl.addOverlay("Edit2D", viewer["savedPoints"].overlayLayer)
}
//hide layer
else {
viewer.impl.removeOverlayScene("Edit2D")
}
}
});
After switching some layers from layer manager off, I also get viewer.areAllVisible() as true.
Forge viewer version is 7.*
Do you have any advice? Thanks!
I found out that you can access visible and visible layers from indexToLayer viewer property
var visibleLayers = Array.from(viewer.impl.layers.indexToLayer.filter(e => e != null && e.visible));

Discord.js - Updating a MessageEmbed in the following code

So, I have (this is only part of it) the following code, but I can't figure out this whole updating a sent embed thing...
The coding is all working if I send a new embed every time, but I don't want to clutter the channel; thus attempting to update the first embed.
Code:
const filter = m => m.author.id === message.author.id;
let hangembedStart = new Discord.MessageEmbed()
.setDescription("Let's get started!")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', asterisc)
message.channel.send(hangembedStart);
const collector = message.channel.createMessageCollector(filter, {
maxMatches: 9,
time: 30000
});
collector.on('collect', m => {
if (m.content === 'cancel') {
inProgress = false;
delete guessed;
collector.stop();
return;
}
if (lowChar === text) {
message.channel.send(`Congratulations, you guessed the word!`);
inProgress = false;
delete guessed;
collector.stop();
return;
}
let hits = checkChar(lowChar, text);
if (hits === 0) {
let hangembedGuess = new Discord.MessageEmbed()
.setDescription("Hangman - The Game - In progress")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', reveal)
.addField('Guessed:', guessed.join(" "))
message.channel.send(hangembedGuess);
} else if (hits > 0) {
let hangembedGuess = new Discord.MessageEmbed()
.setDescription("Hangman - The Game - In progress")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', reveal)
.addField('Guessed:', guessed.join(" "))
message.channel.send(hangembedGuess);
}
});
collector.on('end', collected => {
message.channel.send(`Game ended, word was: ${text}!`);
inProgress = false;
delete guessed;
//collector.stop();
});
How the ... can I update the first embed in this code, instead of sending a new one each time?
I tried using message.edit() but that triggers:
UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot edit a message authored by another user
I've googled, read, searched, tried, tested just about everything I've come across, but can't wrap my head around this one...
Got it sorted!!
Added the following line:
const hangmanMessage = await message.channel.send(hangembedStart);
//above
const filter = m => m.author.id === message.author.id;
Then changed the following line(s):
message.channel.send(hangembedGuess);
//to this
hangmanMessage.edit(hangembedGuess);
Now it updates the first embed, instead of sending a new one each time :D

How can i check if a person has went online, offline, etc. in discord.js?

const channel = client.channels.cache.get('<channelid>');
const person1 = client.users.cache.get('<userid>');
const person = client.users.cache.get('<userid>');
client.on('message', message =>{
client.on('presenceUpdate', () =>{
if(person1.user.presence.status === 'dnd' || person1.user.presence.status === 'online'){
channelforstatus.send('person1 is now online');
}
else if(peron1.user.presence.status === 'offline' || person1.user.presence.status === 'idle'){
channel.send('person1 is offline');
}
client.on('message', message => {
client.on('presenceUpdate', () =>{
if(person.user.presence.status === 'dnd' || person.user.presence.status === 'online'){
channel.send('person is now on');
}
else if(person.user.presence.status === 'offline' || person.user.presence.status === 'idle'){
channel.send('person is now off');
}
});
});
});
});
This is what I've tried and the .send() the function is not working. I've looked everywhere and found nothing that could help me with this problem. I just need it so it checks every time if a specific person has went online, offline, etc. And sends a message to a specific channel.
First of all, one rule to abide with is that event listeners should always be in top level of your code and never nested. (Else you are subject to memory leaks and other issues like duplicated and unintended code execution).
client.on("message", (message) => {
...
});
client.on('presenceUpdate', (oldPresence, newPresence) => {
...
});
Now when looking at presenceUpdate event and Presence object documentation you can manage to see if a status evolved like that :
client.on('presenceUpdate', (oldPresence, newPresence) => {
let member = newPresence.member;
// User id of the user you're tracking status.
if (member.id === '<userId>') {
if (oldPresence.status !== newPresence.status) {
// Your specific channel to send a message in.
let channel = member.guild.channels.cache.get('<channelId>');
// You can also use member.guild.channels.resolve('<channelId>');
let text = "";
if (newPresence.status === "online") {
text = "Our special member is online!";
} else if (newPresence.status === "offline") {
text = "Oh no! Our special member is offline.";
}
// etc...
channel.send(text);
}
}
});
Be aware that presenceUpdate event is fire by EACH guild the user and bot share, meaning that if user status change and share two guilds with your bot, this code will be executed twice.
In case you use presence but get offline instead of the user being online I spent like.. 2 whole days looking for the answer so ill share it anywayz
Common mistakes on presence.status is forgetting to check these stuff at the the developer applications. which i have no idea what means
A screenshot
now on your message (command handler) function.. if you have one
message.guild.members.cache.get('userId').presence.status
or
${message.author.username} is now ${message.author.presence.status};
Ill update this if I found out how to presence all the users instead of just one
my first post... I SHALL REMEMBER THIS xD
To get the presence, you can use user.presence, which will get all kinds of info about the user, but you only need user.presence.clientStatus.desktop
so your code would, for example, be
bot.on('presenceUpdate', () =>{
let person1 = bot.users.cache.get('USERID')
console.log(person1.presence.clientStatus.desktop)
if(person1.presence.clientStatus.desktop === 'dnd' || person1.presence.clientStatus.desktop === 'online'){
channel.send('person1 is now online');
}
else if(person1.presence.clientStatus.desktop === 'offline' || person1.presence.clientStatus.desktop === 'idle'){
channel.send('person1 is offline');
}
})

Resources