What does `suppressed_by_user` mean when using Google One Tap? - javascript

I am trying to get the one tap to appear when the user clocks sign in, The below code works just fine when It runs as soon as the page loads but if I try to get it run on click then I get the error suppressed_by_user error I don't have an advert blocking plugin running and I don't know what suppressed_by_user could mean?
docs here detail the error but don't explain what caused it or how to fix it.
<script src="https://accounts.google.com/gsi/client"></script>
...
const signin = () => {
const handleCredentialResponse = (response: any) => {
const credential = response.credential;
const getDetails = async () => {
const params = new window.URLSearchParams({ credential });
const url = `${process.env.REACT_APP_API_BASE_URL}/google?${params}`;
const response = await fetch(url, { method: "GET" });
const data = await response.json();
setLoggedIn(true);
setState({ ...state, participant: data.participant });
};
getDetails();
};
if (state && state.participant && state.participant.id) {
setLoggedIn(true);
} else {
const client_id = process.env.REACT_APP_GOOGLE_CLIENT_ID;
const callback = handleCredentialResponse;
const auto_select = false;
const cancel_on_tap_outside = false;
google.accounts.id.initialize({ client_id, callback, auto_select, cancel_on_tap_outside });
google.accounts.id.prompt((notification: any) => {
console.log(notification); // rlĀ {g: "display", h: false, j: "suppressed_by_user"}
console.log(notification.getNotDisplayedReason()); // suppressed_by_user
});
}
};
...
<div className="center--main-join" onClick={signin}>Sign in or Join</div>

It means the user has manually closed the One Tap prompt before, which triggered the Cool Down feature (as documented at: https://developers.google.com/identity/one-tap/web/guides/features#exponential_cooldown).
During the cool-down period, One Tap prompt is suppressed.

Related

React - Refactoring hook with partial applications

I have the following hook:
function sendMessage(toId, text) { ... }
const useSendMessage = ({ onSuccess, onError } = {}) => {
const { showRewardedAd } = useAdMob();
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const handleOnEarnMessagesReward = () => {
// increase total available messages...
};
const handleOnRewardedAdError = (error) => {
toast.warning(error); // display the error using a toast...
//
// QUESTION: HOW TO PASS toId and text args?
//
// do not block the app due to the AdMob service...
handleOnEarnMessagesReward(); // fake reward
sendMessage();
};
const sendMessageOrDisplayAd = (toId, text) => {
if (!user.totalAvailableMessages) {
return showRewardedAd({
onEarnReward: handleOnEarnMessagesReward,
onError: handleOnRewardedAdError,
});
}
// No need to open a rewarded ad
sendMessage(toId, text);
user.totalAvailableMessages -= 1;
}
return {
isLoading,
error,
sendMessageOrDisplayAd
}
}
As you can see, I am not receiving the toId and text params as arguments in useSendMessage...
In order to execute the handleOnRewardedAdError method correctly, should I use a partial application like:
const handleOnRewardedAdError = (toId, text) => (error) => {
toast.warning(error); // display the error using a toast...
// do not block the app due to the AdMob service...
handleOnEarnMessagesReward(); // fake reward
sendMessage(toId, text); <--------------------
};
const sendMessageOrDisplayAd = (toId, text) => {
if (!user.totalAvailableMessages) {
return showRewardedAd({
onEarnReward: handleOnEarnMessagesReward,
onError: handleOnRewardedAdError(toId, text), <------------------
});
}
// No need to open a rewarded ad
sendMessage(toId, text);
user.totalAvailableMessages -= 1;
}
This seems logical to me, but is this an anti-pattern or bad practice? Any other strategy to solve this problem?

Created a POST request for a conversation list in mongoDB. How to avoid POST request from creating duplicate documents?

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
};```

WebSocket readyState stuck at 0 after a couple of messages are sent

I am trying to develop a live chat app using web sockets and react, but after I try submitting several messages (around 30) the web socket gets stuck on the CONNECTING state. I have it set up so when it does send a message it disabled the send button to prevent users from spamming messages too fast but I unfortunately still get the same issue.
// id is a uuid() string
const ws = new WebSocket(`ws://localhost:3001/chat/${id}`);
useEffect(() => {
ws.onmessage = function(evt){
try{
const user_id = parseInt(evt.data.split("")[0]);
const message = evt.data.slice(1);
const currentTime = new Date();
const currentUTC = currentTime.toUTCString();
const timestamp = new Date(currentUTC);
setMessages(messages => [...messages, {user_id, message, timestamp}])
} catch(e){
console.log(e);
}
}
ws.onclose = function(evt){
console.log("DISCONNECTED!!")
ws.close();
}
ws.onerror = function(evt){
console.log(evt);
ws.close();
}
}, []);
useEffect(() => {
async function postMessageToAPI() {
const messsageToSend = {
unique_id: id,
message: formData.message,
user_id: user.id,
group_chat_id: room.id
}
// Convert to unviersal time UTC and send it to database
let currentUTC = new Date();
currentUTC.toUTCString();
messsageToSend.timestamp = currentUTC;
await AnonChatApi.sendChatMessage(messsageToSend);
}
if(sendMessage){
ws.onopen = function(){
// add user_id to the start of the message string
const message = `${user.id}` + formData.message;
ws.send(message);
}
postMessageToAPI();
resetFormData();
setTimeout(() => {
setSendMessage(false)
}, 1000);
}
}, [sendMessage]);
const goBackHome = () => {
ws.close();
history.push('/');
}
I can see you're using Hooks, so you must also be using Function Components.
Am I correct in thinking that the code to initialize the websocket
const ws = new WebSocket(`ws://localhost:3001/chat/${id}`);
is at the top of the function?
As a reminder, the function which defines your Function Component is run whenever your component is rendered. Anything that isn't saved in state is lost. This includes your websocket - a new one will be created every render, your async functions may sending data on an old websocket (from a previous render), and React may warn you in the console that you have a memory leak.
useEffect is the proper approach here, but the websocket also needs to be saved in state.
YourFunctionComponent() {
const [ws, setWs] = useState(null);
useEffect(() => {
if (ws == null) {
setWs(new WebSocket(`ws://localhost:3001/chat/${id}`));
}
return () => {
// A function returned from useEffect will
// get called on component unmount.
// Use this function to clean up your connection and
// close your websocket!
// clean up, e.g.
// ws.send('closing due to unmount!');
ws.close();
setWs(null);
}
}, [ws, setWs]);
// Add `ws` as a dependency in the useEffect()s you posted above
useEffect(() => {
ws.onmessage = function(evt){
[--snip--]
}
}, [ws]);
useEffect(() => {
async function postMessageToAPI() {
[--snip--]
}
}, [sendMessage, ws]);
}

Correct way to pass async eerror

I have a function which uses Firebase auth to update a user's email:
export const updateEmail = async (email) => {
const user = auth.currentUser;
return user.updateEmail(email);
};
It is used in a function which gets an email from a form (in React) and tries to update the email. If there is an error, we change the state to reflect that.
handleSave = (e) => {
const email = e.target.email.value;
updateEmail(email).catch((err) => {
this.setState({ didError: true, emailError: err.message });
});
};
However, when an error occurs, in the console I get:
My question is: why does this still say 'Uncaught'? Does the .catch() in handleSave not take care of that?
update
Link to relevant Firebase docs
Assuming updateEmail returns a prmise, I guess you can try:
export const updateEmail = (email) => { // no need for async here
const user = auth.currentUser;
return user.updateEmail(email);
};
handleSave = async (e) => {
const email = e.target.email.value;
try{
await updateEmail(email);
}catch(err){
this.setState({ didError: true, emailError: err.message });
}
};
I'm not quite sure since I don't know so much about Firebase, let me suggest something.
export const updateEmail = async (email) => {
const user = auth.currentUser;
const response = await user.updateEmail(email);
if ( response.error ) {
throw new Error( response.error );
}
return "something else";
};

How can I grab the author info for each post when grabbing all posts?

When a post or comment is made, the user author is just added by ID. That way when the user decides to update their avatar/name etc, I don't have to find every single post and comment that they've ever made and update it there too.
When I was simply grabbing the posts and passing them through as payload (without the author info), it was working fine, no errors:
export const fetchPostsByNewest = () => {
return (dispatch) => {
firebase.database().ref('/social/posts')
.on('value', snapshot => {
dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: snapshot.val() });
};
};
};
I've tried going to get the author info like this, but I can't work out a solution of how to do it all in just one payload:
export const fetchPostsByNewest = () => {
return (dispatch) => {
firebase.database().ref('/social/posts').on('value', postSnapshot => {
const posts = postSnapshot.val();
const postsAsArray = Object.keys(posts).map(postId => posts[postId]);
postsAsArray.forEach(post => {
const postWithUser = {};
Object.keys(post).forEach(key => {
postWithUser[key] = post[key];
});
const userId = post.author;
firebase.database().ref(`/social/users/${userId}`).once('value', userSnapshot => {
const profile_info = userSnapshot.val();
postWithUser.profile_info = profile_info.profile_info;
console.log(postWithUser);
dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: postWithUser });
});
});
});
};
};
These are the console logs I'm getting from above:
Which seems to be bringing through the right data but I just get this error:
Can you please give me some suggestions, this is driving me crazy!
Thanks!
According to the Firebase API once() returns a Promise so your code should look more or less like:
firebase.database().ref(`/social/users/${userId}`).once('value').then(userSnapshot => {
const profile_info = userSnapshot.val();
postWithUser.profile_info = profile_info.profile_info;
console.log(postWithUser);
dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: postWithUser });
});
Here is the reference to the docs: https://firebase.google.com/docs/reference/node/firebase.database.Reference#once

Categories