Discord.js | How to create a limit of .addFields objects, creating a list with .addFields with different value of an Array? - node.js

I created a script to do tests, I want to make a listing with 4 objects inside the .addfields, if you have more than 4, create an embed throwing other data in the objects inside the .addfields in it.
const Command = require("../../structures/Command");
const { EmbedBuilder, ModalBuilder, TextInputComponent, ButtonBuilder, ButtonStyle, ApplicationCommandType, ActionRowBuilder, SelectMenuOptionBuilder, SelectMenuBuilder} = require('discord.js');
module.exports = class extends Command {
constructor(client) {
super(client, {
name: 'shop',
description: 'shop',
type: ApplicationCommandType.ChatInput
});
};
run = async (interaction) => {
let listItems = ['Whinds', 'Freeway', 'Teste', 'Maria'];
const embed = [];
let i = 0;
listItems.forEach(e => {
if (!embed[Math.floor(i / 60)]) {
embed.push(new EmbedBuilder()
.setDescription(`testando`)
.addFields(
listItems.map(item => (
{
name: `${item[i]} [R$ ${item[i]}]`, value: `${item[i]}`}
))
)
);
}
i++;
})
console.log(embed)
embed.forEach(e => {
interaction.reply({embeds: [e] });
})
}
}
I would like support, how can I make this listing system with a maximum of 4 objects in the embed addfields.

Related

Changing Zipcode from a child component (react native node js)

I have a home screen that is capturing the location of the user using expo-location.
HomeScreen is getting the zipcode like this:
`
const [zipcode, setZipcode] = useState("");
const GetCurrentLocation = async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
toastRef.current.show(
"Permission to access location was denied",
3000
);
}
let { coords } = await Location.getCurrentPositionAsync();
if (coords) {
const { latitude, longitude } = coords;
let response = await Location.reverseGeocodeAsync({
latitude,
longitude
});
for (let item of response) {
let zip = `${item.postalCode}`;
setZipcode(zip);
}
}
};
`
I'm sending using props the zipcode={zipcode} to the child (I have added an icon in Home Screen, that when you click brings a modal with a component called "Change Zipcode" wish literally is the form that I want to use to the users change their zipcode manually)
ChangeZipcode.js :
What I'm trying to do, is to update the zipcode in HomeScreen with the new zipcode that the users are changing manually but I don't know how.
I was trying to create an usestate called zipcode and then do a useEffect with the zipcodeNew from the form, but not success.
export function ChangeZipcode(props) {
const {zipcodeOld} = props;
const [zipcode, setZipcode] = useState("");
const formik = useFormik({
initialValues: initialValues(),
validationSchema: validationSchema(),
validateOnChange: false,
onSubmit: async (formValue) => {
try {
const zipcodeNew = formValue.zipcode;
useEffect(() => {
if(zipcodeNew) {
setZipcode(zipcodeNew);
}
}, [zipcode]);
} catch (error) {
Toast.show({
type: "error",
position: "bottom",
text1: "Error updating the zipcode",
})
}
console.log(zipcode);
}
});
If someone can help me would be amazing!!!

How to test mongoose methods using sinon fakes?

I have the following arrangement of tests using sinon, mocha and chai:
type ModelObject = {
name: string;
model: typeof Categoria | typeof Articulo | typeof Usuario;
fakeMultiple: () => object[];
fakeOne: (id?: string) => object;
}
const models: ModelObject[] = [
{
name: 'categorias',
model: Categoria,
fakeMultiple: () => fakeMultiple({ creator: oneCategoria }),
fakeOne: oneCategoria
},
{
name: 'articulos',
model: Articulo,
fakeMultiple: () => fakeMultiple({ creator: oneArticulo }),
fakeOne: oneArticulo
},
{
name: 'usuarios',
model: Usuario,
fakeMultiple: () => fakeMultiple({ creator: oneUsuario }),
fakeOne: oneUsuario
}
];
const randomModel = models[Math.floor(Math.random() * models.length)];
describe(`v1/${randomModel.name}`, function () {
this.afterEach(function () {
sinon.restore();
});
context.only("When requesting information from an endpoint, this should take the Model of the requested endpoint and query the database for all the elements of that model", function () {
it.only(`Should return a list of elements of ${randomModel.name} model`, function (done) {
const fakes = randomModel.fakeMultiple();
const findFake = sinon.fake.resolves({ [randomModel.name]: fakes });
sinon.replace(randomModel.model, 'find', findFake);
chai.request(app)
.get(`/api/v1/${randomModel.name}`)
.end(
(err, res) => {
expect(res).to.have.status(200);
expect(res.body.data).to.be.an('object');
expect(res.body.data).to.have.property(randomModel.name);
expect(res.body.data[randomModel.name]).to.have.lengthOf(fakes.length);
expect(findFake.calledOnce).to.be.true;
done();
}
)
});
}}
I use this to test an endpoint that arbitrary returns information about a given model. In my controllers, I'm using a dynamic middleware to determine which model is going to be queried, for example, if the route consumed is "api/v1/categorias", it will query for Categorias model. If the route consumed is "api/v1/articulos", it will query for Articulos model, and so on.
To make the query, i use the following service:
import { Articulo } from '../models/articulo';
import { Usuario } from '../models/usuario';
import { Categoria } from '../models/categoria';
import logger from '../config/logging';
import { Model } from 'mongoose';
const determineModel = (model: string): Model<any> => {
switch (model) {
case 'articulos':
return Articulo;
case 'usuarios':
return Usuario;
case 'categorias':
return Categoria;
default:
throw new Error(`Model ${model} not found`);
}
};
export const getInformation = async (schema: string, page: number, limit: number) => {
try {
const model = determineModel(schema);
const data = await model.find().skip((page - 1) * limit).limit(limit);
const dataLength = await model.find().countDocuments();
return {
data,
total: dataLength,
};
} catch (err) {
logger.error(err);
console.log(err);
throw err;
}
};
The problem here lies when running my tests, it seems that is unable to run the .skip() and .limit() methods for my model.find()
error: model.find(...).skip is not a function
TypeError: model.find(...).skip is not a function
I think that I need to fake those methods, because when running the same test without skip and limit, it works as a charm. My problem lies in the fact that I don't know how to fake those, or to see if my guess is correct.
As a note, I have default params for the variables page and limit (1 and 15 respectively) so I'm not passing empty values to the methods.

Retrieving Data from Firestore with angular/fire/rxjs

I'm trying to get collection data from a firestore instance and don't want to use valueChanges{idField: id}. So far this is the only solution that somehow processes some of the data and gets the output close to what I need.
I'm new to angular & angular/fire as well as to rxjs and am really struggling to understand observables, pipe, map and rxjs in general.
What am I missing here?
async fetchJobs() {
let jc = await collection(this.firestore, 'jobs');
let cSN = await collectionSnapshots(jc);
let jobsArr = cSN.pipe(
map((data) =>
data.forEach((d) => {
let jobsData = d['_document']['data']['value']['mapValue'][
'fields'
] as Job;
const newData = {
id: d.id,
title: jobsData.title,
subtitle: jobsData.subtitle,
description: jobsData.description,
publish: jobsData.publish,
img: jobsData.img,
} as Job;
return newData;
})
)
);
}
This should work.
fetchJobs(): Observable<Job[]> {
const jc = collection(this.firestore, 'jobs')
return collectionSnapshots(jc)
.pipe(
map((snapshots) =>
snapshots.map((snapshot) => {
return { ...snapshot.data(), id: snapshot.id } as Job
})
)
)
}
which is equivalent to:
fetchJobs(): Observable<Job[]> {
const jc = collection(this.firestore, 'jobs')
return collectionData(jc, { idField: 'id' })
.pipe(
map((data) => data as Job[])
)
}
Since you only need to fetch the Job's data, collectionData() is way more appropriate.
collectionSnapshots() may be interesting when you need to perform additional operations on each Job, such as updating/deleting each one of them, which is possible with snapshot.ref
Example:
fetchJobs() {
const jc = collection(this.firestore, 'jobs')
return collectionSnapshots(jc)
}
deleteAllJobs() {
fetchJobs()
.pipe(take(1))
.subscribe(snapshots =>
snapshots.map((snapshot) => {
deleteDoc(snapshot.ref)
})
)
}
This is a mere example and the logic may not apply to your use case.

Update an imported module in Typescript

I'm sorry, but I'm kinda new in this language.
I was creating a custom discord bot these days and I got stucked on this problem...
I gave this bot the possibility to load the commands dynamically from a folder with one module for each command, but now I was trying to make a command to reload them all, but each time after the commands are reloaded the output is always the same.
Here is the code:
refreshCommands = () => {
this.commands = {};
console.log("Refreshing commands");
Promise.all(fs.readdirSync("./dist/commands").map(file => {
return new Promise(async resolve => {
const tmp = (await import(`./commands/${file}`)).default;
this.commands[tmp.name] = tmp;
resolve(tmp);
});
})).then(() => {
console.log("Listing commands: ");
console.log(Object.keys(this.commands));
});
}
Of course I update the commands from the js file, and not from the ts 'cause I would have to compile it again.
I tried to make a simple "ping! Pong!" like command, and then to edit it to "ping! ping!" on runtime before using the //reload command, but it keeps writing "ping! Pong!"
Edit 1:
The modules I have to import are made like this one:
import command from "../utils/command";
import { Guild, GuildEmoji, GuildEmojiManager, Message, MessageEmbed, Role } from "discord.js";
import { games } from "../utils/games";
import app from "../app";
import ReactionListener from "../utils/reactionListener";
const roleMessage: command = {
name: "rolesMessage",
description: "",
execute: async (message, bot) => {
message.delete();
createRoles(message.guild as Guild);
const embed = new MessageEmbed()
.setColor('#F00')
.setTitle("React to set your ROLE!");
games.forEach(game => {
let emoji = message.guild?.emojis.cache.find(emoji => emoji.name === game.emoji);
console.log(emoji);
embed.fields.push({
name: game.name,
value: (emoji as GuildEmoji).toString(),
inline: false
});
});
const msg = await message.channel.send(embed);
app.reactionListeners.push(new ReactionListener(msg,
(reaction, user) => {
let tmp = games.find(game=> reaction.emoji.name === game.emoji);
if(tmp){
//msg.channel.send(tmp);
const role = (message.guild as Guild).roles.cache.find(role => role.name === tmp?.roleName) as Role;
message.guild?.members.cache.find(member => member.id === user.id)?.roles.add(role);
}else{
reaction.remove();
}
}, (reaction, user)=>{
let tmp = games.find(game=> reaction.emoji.name === game.emoji);
if(tmp){
//msg.channel.send(tmp);
const role = (message.guild as Guild).roles.cache.find(role => role.name === tmp?.roleName) as Role;
message.guild?.members.cache.find(member => member.id === user.id)?.roles.remove(role);
}
})
);
games.forEach(game => {
msg.react((message.guild?.emojis.cache.find(emoji => emoji.name === game.emoji) as GuildEmoji));
});
}
}
const createRoles = (guild: Guild) => {
games.forEach(game => {
if(!guild.roles.cache.find(role => role.name === game.roleName)){
guild.roles.create({
data: {
name: game.roleName,
color: "#9B59B6",
},
reason: 'we needed a role for Super Cool People',
})
.then(console.log)
.catch(console.error);
}
});
}
export default roleMessage;
This is a different one from the one I was talking about earlier, but the problem is the same... Once I update and reload it (from the js compiled version), the old version keeps being runned
I managed to find a solution to the problem.
As node js chaches every module once imported, I deleted it from the cache like this
refreshCommands = () => {
Promise.all(fs.readdirSync("./dist/commands").map(file => {
return new Promise(async resolve => {
delete require.cache[require.resolve('./commands/' + file)];
resolve(file);
});
})).then(() => {
this.commands = {};
console.log("Refreshing commands");
Promise.all(fs.readdirSync("./dist/commands").map(file => {
return new Promise(async resolve => {
const tmp = (await import(`./commands/${file}`)).default;
this.commands[tmp.name] = tmp;
resolve(tmp);
});
})).then(() => {
console.log("Listing commands: ");
console.log(Object.keys(this.commands));
});
});
}
The code might look like garbage, but it actually works... I'm on my way to make it better, but meanwhile I can rely on it.
Any suggestion is well accepted

NodeJS: how to implement repository pattern

I would like to implement the Repository pattern in my NodeJS app, but I'm running into troubles with circular requires (I guess...).
How I'm trying to implement it:
PersonRepository class with methods: getAll, getById, create, update, delete
Person class with methods: init, createAccount, showRelations, addRelation,
First of all: Is my repository pattern design correct?
My classes:
personRepository.js
const PersonModel = require('./model');
const Person = require('./person');
class PersonRepository {
constructor() {
this._persons = new Set();
}
getAll( cb ) { // To Do: convert to promise
let results = new Set();
PersonModel.find({}, 'firstName lastName', (err, people) => {
if (err) {
console.error(err);
}
people.forEach((person, index) => {
let foundPerson = new Person(person._id.toString(), person.firstName, person.lastName, person.email, person.birthday);
results.add(foundPerson);
});
this._persons = results;
if (cb) cb(this._persons);
});
}
getById(id) {
return PersonModel.findOne({ _id: id });
}
getByEmail(email) {
throw new Error("Method not implemented");
}
create( person ) {
throw new Error("Method not implemented");
}
update ( person ) {
throw new Error("Method not implemented");
}
delete ( person ) {
throw new Error("Method not implemented");
}
}
module.exports = new PersonRepository();
person.js
const PersonModel = require('./model');
const personRepository = require('./personRepository');
class Person {
constructor(personId, first, last, email, birthday) {
this._id = personId ? personId : undefined;
this._firstName = first ? first : undefined;
this._lastName = last ? last : undefined;
this._email = email ? email : undefined;
this._birthday = birthday ? new Date(birthday) : undefined;
this._relations = new Map();
}
init() { // Get all data from database
personRepository.getById(this._id)
.then(console.log)
.catch(console.error);
}
}
module.exports = Person;
tests.js
console.log("--- GET ALL : results--- ");
personRepository.getAll( (persons) => {
for (let person of persons) {
person.loadAllData()
.then(() => {
console.log(person);
})
.catch((e) => {
console.log(e);
});
}
});
console.log("--- INIT : results--- ");
var personInit = new Person("59c18a9029ef510012312995");
console.log("before init");
console.log(personInit);
personInit.init();
console.log("after init");
console.log(personInit);
Problem:
When running the "Get all" test (without the INIT tests), it works.
When I add the INIT tests, I get the error:
personRepository.getById(this._id)
^
TypeError: personRepository.getById is not a function
at Person.init
How can I prevent this from happening?
- Change the way I require my modules?
- Change my design? (eg. don't require Person class in personRepository and just create a Set of ids in "getAll" instead of a Set of persons)
- Other ideas?
Thanks for helping me! I'm trying to solve this for hours now...
Solved it myself. The problem was a circular dependency between the 2 modules. Problem is fixed by moving the requires after the module.exports.
Reference: https://coderwall.com/p/myzvmg/circular-dependencies-in-node-js

Resources