I have the following cloud function that will trigger a sms message to be sent using Twillio. It works as is but it causes the text message to be sent twice. Is there a way I can modify my function to prevent this? Please note that I am not using the Firebase Realtime Database; I am using the Firebase Firestore Database. This function is being used in conjunction with an Ionic 4 project.
export const textPrayedForNotification = functions.firestore.document('/prayerRequests/{prayerRequestId}').onUpdate(snap => {
const phone: string = snap.after.get('phoneNumber');
const receiveNotifications: boolean = snap.after.get('receiveNotifications');
if (receiveNotifications) {
return client.messages.create({
to: phone,
from: twilioNumber,
body: 'Someone has prayed for you.'
}).then((data: any) => {
console.log(data);
}).catch((error: any) => {
console.log(error);
});
}
});
Update:
Change function to this and now it seems to work.
export const textPrayedForNotification = functions.firestore.document('/prayerRequests/{prayerRequestId}').onUpdate(snap => {
const phone: string = snap.after.get('phoneNumber');
const receiveNotifications: boolean = snap.after.get('receiveNotifications');
const dateLastPrayedBefore = snap.before.get('dateLastPrayed');
const dateLastPrayedAfter = snap.after.get('dateLastPrayed');
if (receiveNotifications) {
if (dateLastPrayedBefore !== dateLastPrayedAfter) {
return client.messages.create({
to: phone,
from: twilioNumber,
body: 'Someone has prayed for you.'
}).then((data: any) => {
console.log(data);
}).catch((error: any) => {
console.log(error);
});
}
}
});
Related
I am using redux-tookit, rtk-query (for querying other api's and not just Firebase) and Firebase (for authentication and db).
The code below works just fine for retrieving and caching the data but I wish to take advantage of both rtk-query caching as well as Firebase event subscribing, so that when ever a change is made in the DB (from any source even directly in firebase console) the cache is updated.
I have tried both updateQueryCache and invalidateTags but so far I am not able to find an ideal approach that works.
Any assistance in pointing me in the right direction would be greatly appreciated.
// firebase.ts
export const onRead = (
collection: string,
callback: (snapshort: DataSnapshot) => void,
options: ListenOptions = { onlyOnce: false }
) => onValue(ref(db, collection), callback, options);
export async function getCollection<T>(
collection: string,
onlyOnce: boolean = false
): Promise<T> {
let timeout: NodeJS.Timeout;
return new Promise<T>((resolve, reject) => {
timeout = setTimeout(() => reject('Request timed out!'), ASYNC_TIMEOUT);
onRead(collection, (snapshot) => resolve(snapshot.val()), { onlyOnce });
}).finally(() => clearTimeout(timeout));
}
// awards.ts
const awards = dbApi
.enhanceEndpoints({ addTagTypes: ['Themes'] })
.injectEndpoints({
endpoints: (builder) => ({
getThemes: builder.query<ThemeData[], void>({
async queryFn(arg, api) {
try {
const { auth } = api.getState() as RootState;
const programme = auth.user?.unit.guidingProgramme!;
const path = `/themes/${programme}`;
const themes = await getCollection<ThemeData[]>(path, true);
return { data: themes };
} catch (error) {
return { error: error as FirebaseError };
}
},
providesTags: ['Themes'],
keepUnusedDataFor: 1000 * 60
}),
getTheme: builder.query<ThemeData, string | undefined>({
async queryFn(slug, api) {
try {
const initiate = awards.endpoints.getThemes.initiate;
const getThemes = api.dispatch(initiate());
const { data } = (await getThemes) as ApiResponse<ThemeData[]>;
const name = slug
?.split('-')
.map(
(value) =>
value.substring(0, 1).toUpperCase() +
value.substring(1).toLowerCase()
)
.join(' ');
return { data: data?.find((theme) => theme.name === name) };
} catch (error) {
return { error: error as FirebaseError };
}
},
keepUnusedDataFor: 0
})
})
});
I am creating an application that connects volunteers to newcomers using ReactJS. In the app I have developed a chat mechanism that will help newcomers connect with volunteers and vice-versa. I have implemented a feature that displays the featured volunteers with their info and a button that says 'contact'. I have hooked up the contact button so that when pressed the user gets directed to the chat and a new conversation list document is created in MongoDB using the POST request.
The problem I am running into is that the POST request keeps on running every time I click the 'contact' button resulting in multiple duplicates of the username getting rendered. I am struggling with finding a solution to the problem. I would like only one username to get rendered to the page and not have a whole bunch of duplicates. Any help is greatly appreciated.
The GET method that grabs the email and POST method that creates a new document
**VolunterCard.jsx**
React.useEffect(() => {
const getImage = async () => {
let response = await fetch(`/image/cass#gmail.com`);
let data = await response.json();
console.log(`Data is:`, data);
setVolunteer(data);
};
getImage();
}, []);
const createConversation = async () => {
const newConversation = {
members: {
senderEmail: user.email,
recieverEmail: volunteer.email
},
};
const data = JSON.stringify(newConversation)
await fetch("/conversation", {
method: "POST",
headers: {
"Content-type": "application/json",
},
body: data,
})
};```
**Conversation.jsx (Where the user gets rendered)**
useEffect(() => {
const chatMembers = conversation.members.find(
(member) => member !== currentUser.email
);
const getUsersFirstName = async () => {
try {
const response = await axios.get("/name?email=" + chatMembers);
setUser(response.data);
} catch (err) {
console.log(err.message);
}
};
getUsersFirstName();
}, [currentUser, conversation, isLoading]);
if (isLoading) {
return <div>isLoading...</div>;
}
return (
<div style={{cursor: 'pointer'}}>
{user.firstName} {user.lastName} - {user.email}
</div>
);
};```
**converstionModel.js**
```const mongoose = require("mongoose")
const conversationSchema = new mongoose.Schema({
members: {
type: Array,
}
}, { timestamps: true});
const conversationModel = mongoose.model("Members", conversationSchema);
const createMembers = async (members) => {
const newMembers = await conversationModel.create(members);
return newMembers
};```
I'm trying to create a user after he verified the code that I send him
so first I generate the code in sendCode resolver and save it in Redis using setex
the problem is that code is set in Redis but when I try to use it in createUser resolver using get it returns null.
const sendCode: MutationResolvers["sendCode"] = async ({
input: { phoneNumber, email },
}: {
input: SendCodeInput;
}) => {
const code = generate4digitNum();
await redis.setex(phoneNumber ?? email, THREE_MINS, code);
return {};
};
const createUser: MutationResolvers["createUser"] = async ({
input: { ...userData },
}: {
input: CreateUserInput;
}) => {
const code = await redis.get(userData.phoneNumber ?? userData.email);
if (code !== userData.code) {
throw new Error(errors[0].id);
}
user = await userModel.create({ ...userData});
return {type: user.type, _id: user._id };
};
the redis.ts file that I create:
const client = redis.createClient({
host: process.env.REDIS_HOST,
password: process.env.REDIS_PASSWORD,
port: Number(process.env.REDIS_PORT),
});
client
.on("connect", function () {
console.log(`connected ${client.connected}`);
})
.on("error", function (error) {
console.log(error);
});
export const get: (key: string) => Promise<string> = promisify(client.get).bind(
client
);
export const setex: (
key: string,
seconds: number,
value: string
) => Promise<string> = promisify(client.setex).bind(client);
I will appreciate any kind of help.
Thanks in advance.
I'm trying to make a "edit" feature for my project, and I'm stuck at this part..
I have a put request :
export const updateEvent = (event, id) => (dispatch, getState) => {
request
.put(`${baseUrl}/event/${id}`)
.send(event)
.then(response => {
dispatch(updatedEvent(response.body))
})
.catch(error => console.log(error))
}
This is the route for the said put, with Sequelize as ORM:
router.put('/event/:id', async (req, res, next) => {
const { id } = req.params
try {
const event = await Event.findByPk(id)
const updatedEvent = await event.update(req.body)
res.send(updatedEvent)
} catch (error) {
next(error)
}
})
When I test it with postman, everything works as expected. Where I ran into my problem is when I'm sending the put data from React in the frontend.
I have a form, and I save my data in the local state, and then dispatch it to actions like this:
handleSubmit = e => {
e.preventDefault()
const id = this.props.event.id
const updatedEvent = {
name: this.state.name,
description: this.state.description,
picture: this.state.picture,
startDate: this.state.startDate,
endDate: this.state.endDate,
userId: this.props.userId
}
this.props.updateEvent(updatedEvent, id)
}
Any value that is left empty in the form is overwriting my fields with nothing (an empty string). How do I properly handle this?
A solution is to filter your object, such that you remove any properties which have empty values and therefore won't be included in the database update.
In your router.put():
router.put('/event/:id', async (req, res, next) => {
const { id } = req.params
try {
const event = await Event.findByPk(id);
// filter req.body to remove empty values
const { body } = req;
const filteredBody = Object.keys(body).reduce((resultObj, key) => {
if(body[key] != ''){
resultObj[key] = body[key];
}
return resultObj;
}, {});
const updatedEvent = await event.update(filteredBody);
res.send(updatedEvent)
} catch (error) {
next(error)
}
})
I am unable to send message using socketio, Here's an function i am using but not able to send messages.
Following is the flow I am using, event wise
workspace_room_join
get_user_room
room_join
message
Now I am unable to send a message, What is the correct way to send the message?
Below code function is for sending message
sendUsingSocket = (messages) => {
const workspace_id = localStorage.getItem('workspace_id');
const payload = {
room_id:this.props.socket_details.room_id,
isChannel:false,
workspace_id:workspace_id,
chat: messages,
sender_id: this.state.sender_to_receiver_details.sender_id,
receiver_id: this.state.sender_to_receiver_details.receiver_id,
}
socket.emit("message", payload);
}
and here is the component I am passing
<Chat sendUsingSocket={this.sendUsingSocket} />
And here is my Component did mount
componentDidMount() {
const token = localStorage.getItem("Auth");
const userInfo = JSON.parse(localStorage.getItem("getUserInfoFromLocalStorage"));
const user_id = userInfo._id
if(token !== undefined){
socket.emit("workspace_room_join",{
workspace_id:user_id,
token:token
})
socket.on("workspace_room_join",(data) => {
})
}
socket.on("get_user_room", (data) => {
this.props.actions.savingRoomId(data)
})
socket.on("room_leave", () => {
socket.emit("room_join", {
room_id: this.props.socket_details.room_id,
})
})
socket.on("get_user_room", (data) => {
socket.emit("room_join", {
room_id: data.room_id,
})
});
socket.on("message",(data) => {
const message_details = data.chatData
this.setState({
listen_messages:message_details
})
})
localStorage.setItem('workspace_id',this.props.match.params.id)
this.props.actions.getByWorkspaceId({ id: this.props.match.params.id });
let {actions} = this.props;
actions.fetchChannelList()
actions.fetchUserlist()
}
I am unable to send messages, how to fix that?