How to display Stripe error or success message in JavaScript? - javascript

I am trying to implement Stripe payment gateway in my Spring Boot project. I am facing problem from client side. I am trying to display any error or success message after a transaction. When I check my Stripe dashboard, then there is showing me successful transaction but from my JavaScript code, control is going to error block and displaying unexpected error. So I am not understanding where I am doing wrong and how to create token to send it to server side.
Below is JavaScript Code:
const stripe = Stripe(Public key);
let elements;
let clientsecret;
let paymentElement;
initialize();
checkStatus();
document.querySelector("#payment-form").addEventListener("submit", handleSubmit);
async function initialize(){
var url = "api/create-payment-intent";
$.post(url,{
}, function(data, status) {
if (data.status == "OK") {
if (data.statusCode == 1){
clientsecret = data.response.clientSecret;
const appearance = { theme: 'stripe',};
elements = stripe.elements({ appearance, clientsecret });
paymentElement = elements.create('card');
paymentElement.mount("#payment-element");
} else {
var error = data.responseMessage;
swal(error, "", "error");
}
}else {
var error = data.response;
}
});
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmCardPayment(clientsecret,{
payment_method: {
card: paymentElement,
},
});
if (error) {
showMessage(error.message);
} else {
showMessage("An unexpected error occured.");
}
setLoading(false);
}
//Fetches the payment intent status after payment submission
async function checkStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
switch (paymentIntent.status) {
case "succeeded":
showMessage("Payment succeeded!");
break;
case "processing":
showMessage("Your payment is processing.");
break;
case "requires_payment_method":
showMessage("Your payment was not successful, please try again.");
break;
default:
showMessage("Something went wrong.");
break;
}
}
function showMessage(messageText) {
debugger
const messageContainer = document.querySelector("#payment-message");
messageContainer.classList.remove("hidden");
messageContainer.textContent = messageText;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageText.textContent = "";
}, 4000);
}
// Show a spinner on payment submission
function setLoading(isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.querySelector("#submit").disabled = true;
document.querySelector("#spinner").classList.remove("hidden");
document.querySelector("#button-text").classList.add("hidden");
} else {
document.querySelector("#submit").disabled = false;
document.querySelector("#spinner").classList.add("hidden");
document.querySelector("#button-text").classList.remove("hidden");
}
}

There's problem in how you handle the payment result
if (error) {
showMessage(error.message);
} else {
showMessage("An unexpected error occured.");
}
It seems like you also show An unexpected error occured. even the payment is succeeded (i.e. when error is undefined). You might want to change the logic here.

use addEventListner() to show success or if you want to show or delete after a while you can use addEventListener() in setTimeOut function

Related

ensure code is running twice with condition

I have code which needs to do request to some server with token,
Sometimes you need to run the code twice to get the data. (the exact same code )
How can I ensure that the code will run only twice and not recursively ?
Most of the time in the first run I got http response 401 and the second run give http 200
This is the code
async function magt() {
let auth: any;
try {
auth = await getTokens();
if (auth.runtime?.status == 200 && auth.application?.status == 200) {
...
//run rest of the code
} else {
console.log("unable to fetch tokens")
if (auth.response.status == 401) {
console.log("Running for the second time to get valid token")
await magt()
}
}
} catch (e) {
console.log("error occurred while fetching token: ", e)
}
I want to make sure that if I got always 401, run the magt() func only twice, what is the best way to do it ?
is there a better way from some simple counter which is defined by global?
How about a simple for loop?
async function magt() {
for (var attempt = 0; attempt < 2; attempt++) {
try {
let auth = await getTokens();
if (auth.runtime?.status == 200 && auth.application?.status == 200) {
return true;
}
console.log("Invalid auth response:", auth.response);
} catch (e) {
console.log("error occurred while fetching token: ", e);
}
}
throw new Error("All attempts at magt'ing failed miserably");
}
async function something() {
await magt();
//"run rest of the code"
}
Or, if you're feeling fancier, write a wrapper function for retrying async functions:
async function retrying(func, attempts) {
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return await func();
} catch (err) {
console.log(func, "attempt", attempt, "failed:", err);
}
}
throw new Error("retry failed");
}
async function checkToken() {
const auth = await getTokens();
if (auth.runtime?.status == 200 && auth.application?.status == 200) {
return auth;
}
throw new Error("invalid auth response: " + auth.response);
}
async function magt() {
const token = await retrying(checkToken, 2);
}
async function magt(iterationLeft) {
let auth: any;
iterationLeft--;
try {
auth = await getTokens();
if (auth.runtime?.status == 200 && auth.application?.status == 200) {
...
//run rest of the code
} else {
console.log("unable to fetch tokens")
if (auth.response.status == 401 && iterationLeft) {
console.log("Running for the second time to get valid token")
await magt(iterationLeft)
}
}
} catch (e) {
console.log("error occurred while fetching token: ", e)
}
Calling with number of iteration as argument magt(2);

Is it possible to extend desktop notification with javascript?

I was making a web chat app with firebase. Everything is good including the notification but the notification only shows up for 5 seconds. What I want to do is to extend the notification show duration.
In this examples, there is requireInteraction function but this function does not extend the show duration but it prevent the notification to hide.
Here is my code
Notification.requestPermission().then(function(permission) {
if (permission === 'granted') {
var config = {
apiKey: "apikey",
messagingSenderId: "senderid",
}
firebase.initializeApp(config)
const messaging = firebase.messaging();
messaging.usePublicVapidKey('PublicVapidKey');
messaging.getToken().then(function(currentToken) {
if (currentToken) {
doFCMReg(currentToken)
} else {
console.log('No Instance ID token available. Request permission to generate one.')
}
}).catch(function(err) {
console.log('An error occurred while retrieving token. ', err)
})
messaging.onTokenRefresh(function() {
messaging.getToken().then(function(refreshedToken) {
doFCMReg(token)
}).catch(function(err) {
console.log('Unable to retrieve refreshed token ', err)
})
})
messaging.onMessage(function(payload) {
var n = payload['notification']
var d = payload['data']
var not = new Notification("𝗦𝗦𝗧 \n"+xad(n['body']), { icon: "assets/icon/png/SST-icon-512.png", tag: "" })
switch(d['type']) {
case "newchat":
getInvitation()
refreshChat(xad(d['phoneSender']), xad(d['invitationId']))
var target = xad(localStorage.phone)==xad(d['phoneSender']) ? xad(d['phoneReceiver']) : xad(d['phoneSender'])
not.onclick = function() {
if(localStorage.currentPage!='page-chat') {
switchFragment('#page-chat', 'Chats')
}
$('#invitation-'+target).trigger('click')
}
break
case "newcontact":
getContacts()
not.onclick = function() {
if(localStorage.currentPage!='page-contact') {
switchFragment('#page-contact', 'Contacts')
}
$( '#btn-request').trigger('click')
$(".contact[data-phone='"+d['senderPhone']+"']").trigger('click')
}
break
}
})
} else {
alert("SST needs Notifications to be allowed to enable push notification.")
}
})
Is there any way to extend the show duration?

How to fix "Error: Can't set headers after they are sent" in Express

I have recently been developing a MERN application and I have recently came into the trouble that express is saying that I am setting headers after they are sent.
I am using mongo db and trying to update a user profile.
I have tried to comment out my res.send points to find the issue but I have failed to do so.
Here is my post method for updating the user profile:
app.post("/api/account/update", (req, res) => {
const { body } = req;
// Validating and Checking Email
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, previousUsers) => {
if (previousUsers.length > 0) {
return res.send({
success: false,
message:
"Error: There is already another account with that email address"
});
} else {
}
}
);
}
// Validating Names Function
function checkName(name) {
var alphaExp = /^[a-zA-Z]+$/;
if (!name.match(alphaExp)) {
return res.send({
success: false,
message: "Error: Names cannot contain special characters or numbers"
});
}
}
checkName(body.firstName);
checkName(body.lastName);
// Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: "Error: You cannot submit nothing"
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.send({
success: false,
message:
"Error: Session token is no longer valid, please login to recieve a new one"
});
}
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (!err) {
return res.send({
success: true,
message: "Success: User was updated successfully"
});
}
});
});
});
This is the call that I am doing to the backend of the site:
onUpdateProfile: function(fieldsObj) {
return new Promise(function(resolve, reject) {
// Get Session Token
const obj = getFromStorage("the_main_app");
// Defining what fields are getting updated
fieldsObj.tokenID = obj.token;
// Post request to backend
fetch("/api/account/update", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(fieldsObj)
})
.then(res => {
console.log("Verify Token - Res");
return res.json();
})
.then(json => {
console.log("Verify Token JSON", json);
if (json.success) {
window.location.href = `/manage-account?success=${json.success}`;
} else {
window.location.href = `/manage-account?success=${json.success}`;
}
});
});
}
Here is my error message that I am getting:
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:267:15)
at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:158:21)
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\routes\api\account.js:270:22
at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\model.js:4641:16
at process.nextTick (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\query.js:2624:28)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...
Can anyone help me with this?
EDIT
I have changed my code, this seems to now work however I feel like its a little messy when put together. Any refactoring tips?
Code:
app.post("/api/account/update", (req, res) => {
// Preform checks on data that is passed through
const { body } = req;
var messages = {
ExistedUser:
"Error: There is already another account with that email address",
NameFormat: "Error: Names cannot contain special characters or numbers",
BlankInputs: "Error: You cannot submit nothing",
accountLoggedOut:
"Error: Session token is no longer valid, please login to recieve a new one",
successfullyUpdated: "Success: User was updated successfully"
};
var usersFound;
if (body.email) {
var email = body.email;
email = email.toLowerCase();
email = email.trim();
body.email = email;
User.find(
{
email: body.email
},
(err, UserCount) => {
usersFound = UserCount;
}
);
}
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
//Making sure that all fields cannot be empty
if (!body.email && !body.firstName && !body.lastName) {
return res.send({
success: false,
message: messages.BlankInputs
});
}
// Getting User ID from the current session
UserSession.findById(body.tokenID, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
return res.end({
success: false,
message: messages.accountLoggedOut
});
}
if (userData) {
// Deleting the token ID from the body object as user table entry doesnt store tokens
delete body.tokenID;
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
if (userInfo) {
if (!usersFound.length > 0) {
return res.send({
success: true,
message: messages.successfullyUpdated
});
} else {
return res.send({
success: false,
message: messages.ExistedUser
});
}
}
});
}
});
});
You're calling res.send() twice. res.send() ends the process. You ought to refactor such that you call res.write() and only call res.send() when you're done.
This StackOverflow link describes the difference in more detail. What is the difference between res.send and res.write in express?
I believe this is happening, as you're trying to send a response after the first / initial response has already been sent to the browser. For example:
checkName(body.firstName);
checkName(body.lastName);
Running this function twice is going to try and yield 2 different "response" messages.
The product of a single route, should ultimately be a single response.
Thanks for all your help on this issue.
Here is my final code that allowed it to work.
I have also tried to "refactor" it too. Let me know if you'd do something else.
app.post("/api/account/update", (req, res) => {
const { body } = req;
console.log(body, "Logged body");
// Defining objects to be used at the end of request
var updateUserInfo = {
userInfo: {},
sessionToken: body.tokenID
};
var hasErrors = {
errors: {}
};
// Checking that there is at least one value to update
if (!body.email && !body.firstName && !body.lastName) {
var blankError = {
success: false,
message: "Error: You cannot change your details to nothing"
};
hasErrors.errors = { ...hasErrors.errors, ...blankError };
} else {
console.log("Normal Body", body);
clean(body);
console.log("Cleaned Body", body);
updateUserInfo.userInfo = body;
delete updateUserInfo.userInfo.tokenID;
}
// Function to check if object is empty
function isEmpty(obj) {
if (Object.keys(obj).length === 0) {
return true;
} else {
return false;
}
}
// Function to remove objects from body if blank
function clean(obj) {
for (var propName in obj) {
if (obj[propName] === "" || obj[propName] === null) {
delete obj[propName];
}
}
}
// Checking and Formatting Names Given
function capitalize(text) {
return text.replace(/\b\w/g, function(m) {
return m.toUpperCase();
});
}
if (body.firstName) {
body.firstName = capitalize(body.firstName);
}
if (body.lastName) {
body.lastName = capitalize(body.lastName);
}
// Checking and formatting email
if (body.email) {
body.email = body.email.toLowerCase();
body.email = body.email.trim();
// Checking for email in database
User.find({ email: body.email }, (err, EmailsFound) => {
if (EmailsFound.length > 0) {
var EmailsFoundErr = {
success: false,
message: "There is already an account with that email address"
};
hasErrors.errors = { ...hasErrors.errors, ...EmailsFoundErr };
}
});
}
// Getting User Session Token
UserSession.findById(updateUserInfo.sessionToken, function(err, userData) {
// Finding User ID using the current users session token
if (userData.isDeleted) {
var userDeletedError = {
success: false,
message:
"Your account is currently logged out, you must login to change account details"
};
hasErrors.errors = { ...hasErrors.errors, ...userDeletedError };
} else {
// Finding the user profile and updating fields that are present
User.findByIdAndUpdate(
userData.userId,
updateUserInfo.userInfo,
function(err, userInfo) {
// userInfo varable contains user db entry
if (err) {
var updateUserError = {
success: false,
message: "Error: Server Error"
};
hasErrors.errors = {
...hasErrors.errors,
...updateUserError
};
}
if (isEmpty(hasErrors.errors)) {
res.send({
success: true,
message: "Success: You have updated your profile!"
});
} else {
res.send({
success: false,
message: hasErrors.errors
});
}
}
);
}
});
});

React async login with social media

I'm trying to add a login with social media on my website, but I got some errors because the case is returning first before my HTTP request (Firebase):
firebase.auth().signInWithPopup
How can I use the async function in some way to the case await until the request is complete?
Here is the code:
login(provider, info) {
switch (provider) {
case this.EMAIL:
return firebaseAuth().signInWithEmailAndPassword(
info.email,
info.password
);
break;
case this.EMAILREGISTER:
break;
case this.GOOGLE:
var providerr = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(providerr).then(function(result) {
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log(result);
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
console.log(error);
// ...
});
//Right here I need to return the token and user async
break;
}
}
//here is the function who is calling:
handleLogin = () => {
const { email, password } = this.state;
if (!(email && password)) {
notification('error', 'Favor informar o email e senha');
return;
}
this.setState({
confirmLoading: true
});
const self = this;
let isError = false;
Firebase.login(Firebase.Google, '')
.catch(result => {
const message =
......
});
}
You can try using async/await so that it will wait till the data is returned. Something like this, just to get you started:
async login(provider, info) {
try {
switch (provider) {
case this.EMAIL:
return firebaseAuth().signInWithEmailAndPassword(
info.email,
info.password
);
break;
case this.EMAILREGISTER:
break;
case this.GOOGLE:
var providerr = new firebase.auth.GoogleAuthProvider();
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var result = await firebase.auth().signInWithPopup(providerr);
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log(result);
// ...
break;
}
}
catch(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
console.log(error);
// ...
}
}
}

Accounts.sendVerificationEmail Issue in Meteor

I Need to send VerificationEmail using Meteor.I did the code but It didn't send VerificationEmail and also got error on server side.Error is : Can't find user.I didn't have any idea about this.so Please see the below code & suggest me how to do.
JS Code:
if (Meteor.isClient)
{
Template.main.events
({
'submit #register-form' : function (e,t)
{
console.log("You pressed the button Register ");
e.preventDefault();
var username = t.find('#username').value
, name = t.find('#name').value
, email = t.find('#email1').value
, password = t.find('#pwd1').value;
console.log("password="+password);
var isValidPassword = function(val, field)
{
if (val.length >= 6) {
return true;
} else {
Session.set('displayMessage', 'Error & Too short.')
return false;
}
}
if (isValidPassword(password))
{
console.log(" *** isValidPassword *** ");
Accounts.createUser({email: email, password : password,username : username }, function(err)
{
if (err)
{
console.log(err);
}
else
{
console.log("Register Successfully");
Meteor.call('sendEmail',
'*****#gmail.com',
'****.com',
'Hello from Meteor!',
'This is a test of Email.send.');
}
});
}
else
{
console.log("*** Error ***");
}
}
});
}
if (Meteor.isServer)
{
Meteor.startup(function ()
{
// code to run on server at startup
});
//Meteor methods
Meteor.methods
({
sendEmail: function (to, from, subject, text)
{
Accounts.config({sendVerificationEmail: true, forbidClientAccountCreation: false});
process.env.MAIL_URL = 'smtp://****#gmail.com:*pwd*#smtp.gmail.com:587';
this.unblock();
Accounts.sendVerificationEmail(to);
}
});
}
Did you send the email to an email address? When you use to in Accounts.sendVerificationEmail(to);
it must be the _id of the user you want to send the confirmation email to, not their email address.

Categories

Resources