Can you change user.challengeName in Amplify - reactjs

I'm trying to give the end-user an option on the UI to reset MFA if the end-user loses access to the device they've been using.
I want to change the user.challangeName response from "SOFTWARE_TOKEN_MFA" to "MFA_SETUP". Is this something that can be done? Can I change the challangeName through UI?
Code here
const login = async (email, password) => {
try {
const user = await Auth.signIn(email, password);
if (user) {
if (user.challengeName === 'MFA_SETUP') {
dispatch({
type: AUTH_RESULT_USER,
payload: user
});
navigate('/auth-login');
} else if (user.challengeName === 'SOFTWARE_TOKEN_MFA') {
dispatch({
type: AUTH_RESULT_USER,
payload: user
});
navigate('/auth-post-login');
} else if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {
const attr = user.challengeParam?.userAttributes || null;
if (attr) {
dispatch({
type: AUTH_RESULT_USER,
payload: user
});
}
// console.log('before', user);
navigate('/set-password');
} else {
getUserDetails(user, user.signInUserSession.idToken.jwtToken);
}
}
} catch (e) {
console.log('error', e);
// await logout();
throw e;
}
};

Related

How to use roles?

login = async (creds: UserFormValues) => {
try {
const user = await agent.Account.login(creds);
store.commonStore.setToken(user.token);
runInAction(() => this.user = user);
history.push('/activities');
store.modalStore.closeModal();
} catch (error) {
throw error;
}
}
I have this "login" that I want to edit it to make it with roles. Like:
login = async (creds: UserFormValues) => {
try {
const user = await agent.Account.login(creds);
store.commonStore.setToken(user.token);
runInAction(() => this.user = user);
if(user.role = "admin"){
history.push('/activities');
}
else{
history.push('/home');
}
store.modalStore.closeModal();
} catch (error) {
throw error;
}
}
But I get the warning "Expected a conditional expression and instead saw an assignment no-cond-assign" and still the platform runs but it ignores the if statement. How can I make a conditional expression about this(If you can also show me the code about it)? Also I have 5 roles which should go all on different pages.
login = async (creds: UserFormValues) => {
try {
const user = await agent.Account.login(creds);
store.commonStore.setToken(user.token);
runInAction(() => this.user = user);
if(user.role === "admin"){
history.push('/activities');
}
else{
history.push('/home');
}
store.modalStore.closeModal();
} catch (error) {
throw error;
}
}
This is the updated code, when I login as admin it redirects me to home and not into activities, like the if doesn't exist.

How to send a notification instead of a message when user is offline using socket.io

So whenever another user is offline and an online user tries to send a message, it returns an error. The error is caused because it didn't find a socket where the user is in, but I can console.log something from the error response, since I put it in if/else block. So i was wondering how could I send a response to the client and push a notification for the user who is offline. The explanation is probably confusing, so here is the code:
index.js(socket):
const io = require('socket.io')(8900, {
cors: {
origin: 'http://localhost:3000',
},
});
let users = [];
const addUser = (userId, socketId) => {
!users.some((user) => user.userId === userId) &&
users.push({ userId, socketId });
};
const removeUser = (socketId) => {
users = users.filter((user) => user.socketId !== socketId);
};
const getUser = (userId) => {
return foundUser = users.find((user) => user.userId === userId)
};
io.on('connection', (socket) => {
//when ceonnect
console.log('a user connected.');
//take userId and socketId from user
socket.on('addUser', (userId) => {
addUser(userId, socket.id);
io.emit('getUsers', users);
});
//send and get message
socket.on('sendMessage', ({ senderId, recieverId, text }) => {
const user = getUser(recieverId);
console.log('RECIEVERRRR', user);
if (user) {
io.to(user.socketId).emit('getMessage', {
senderId,
text,
});
} else {
// IMPORTANT: This is where I can console.log the error, but can't figure out how to send the response to the client
}
});
//when disconnect
socket.on('disconnect', () => {
console.log('a user disconnected!');
removeUser(socket.id);
io.emit('getUsers', users);
});
});
dashboard.js (I cut out most of the code, but this is where i'm sending request to socket):
const handleSubmit = async (e) => {
e.preventDefault();
const message = {
sender: user._id,
text: newMessage,
conversationId: currentChat._id,
};
const recieverId = currentChat.members.find(
(member) => member !== user._id
);
console.log('REC from FRONT END', recieverId);
socket.current.emit('sendMessage', {
senderId: user._id,
recieverId,
text: newMessage,
});
try {
const { data } = await axios.post('/api/messages/addMessage', message);
setMessages([...messages, data]);
setNewMessage('');
} catch (err) {
console.log(err);
}
};
Any help would be appreciated. Thanks.
You can emit a new event sendMessageFailed:
//send and get message
socket.on('sendMessage', ({ senderId, recieverId, text }) => {
const user = getUser(recieverId);
console.log('RECIEVERRRR', user);
if (user) {
io.to(user.socketId).emit('getMessage', {
senderId,
text,
});
} else {
io.to(user.socketId).emit('sendMessageFailed', "Your friend is offline");
}
});
At the client side listen to the event:
socket.current.on('sendMessageFailed', (err) => {
//Sending message has failed!
});

Custom error message for firebase for react and redux

I am trying to create a Login feature using firebase and redux. I try to implement a custom error message when the user input the wrong credentials like so:
// Log in
export const signin = (data, onError) => {
console.log(data.email, data.password)
return async dispatch => {
try {
const res = await firebase.auth().signInWithEmailAndPassword(data.email, data.password)
.then(async () => {
if(res.user){
const user = await firebase.firestore().collection('users').doc(res.user.uid).get();
if(user.exists) {
const userData = user.data() as User;
dispatch({
type: SET_USER,
payload: userData
})
}
return res
}
}).catch((error) => {
switch(error.code) {
case 'auth/user-not-found ':
error.message = "User not found"
break;
}
})
}
catch (err) {
console.log(err);
onError();
dispatch(setError(err.message));
}
}
}
However, after I run my application, the application stuck in a loading loop forever. Can someone help me out? Thank you in advance. Cheers

How to pass additional data to a function that adds things to an object?

I am trying to create a user profile document for regular users and for merchants on Firebase. I am trying to add additional to data this document when a merchant signs up, but haven't succeeded. The difference is that merchants are supposed to have a roles array with their roles. If this is not the right approach to deal with differentiating users, I'd also be happy to hear what's best practice.
My userService file
async createUserProfileDocument(user, additionalData) {
console.log('additionalData: ', additionalData) //always undefined
if (!user) return
const userRef = this.firestore.doc(`users/${user.uid}`)
const snapshot = await userRef.get()
if (!snapshot.exists) {
const { displayName, email } = user
try {
await userRef.set({
displayName,
email,
...additionalData,
})
} catch (error) {
console.error('error creating user: ', error)
}
}
return this.getUserDocument(user.uid)
}
async getUserDocument(uid) {
if (!uid) return null
try {
const userDocument = await this.firestore.collection('users').doc(uid).get()
return { uid, ...userDocument.data() }
} catch (error) {
console.error('error getting user document: ', error)
}
}
This is what happens when the user signs up as a merchant in the RegisterMerchant component:
onSubmit={(values, { setSubmitting }) => {
async function writeToFirebase() {
//I can't pass the 'roles' array as additionalData
userService.createUserProfileDocument(values.user, { roles: ['businessOnwer'] })
authService.createUserWithEmailAndPassword(values.user.email, values.user.password)
await merchantsPendingApprovalService.collection().add(values)
}
writeToFirebase()
I am afraid this might have something to do with onAuthStateChange, which could be running before the above and not passing any additionalData? This is in the Middleware, where I control all of the routes.
useEffect(() => {
authService.onAuthStateChanged(async function (userAuth) {
if (userAuth) {
//is the below running before the file above and not passing any additional data?
const user = await userService.createUserProfileDocument(userAuth) //this should return the already created document?
//** do logic here depending on whether user is businessOwner or not
setUserObject(user)
} else {
console.log('no one signed in')
}
})
}, [])
There is onCreate callback function which is invoked when user is authenticated.
Here's how you could implement it
const onSubmit = (values, { setSubmitting }) => {
const { user: {email, password} } = values;
const additionalData = { roles: ['businessOnwer'] };
auth.user().onCreate((user) => {
const { uid, displayName, email } = user;
this.firestore.doc(`users/${uid}`).set({
displayName,
email,
...additionalData
});
});
authService.createUserWithEmailAndPassword(email, password);
}

How to post with Axios in React?

This my first time in React and Axios. I have a login form and sign up form and don't have any database. I want any mock API to simulate a login and sign up which provides a token in the response, in order to save it in a local storage in order to keep the user logged in. Also how do I prevent the user to go the home page (login/logout screen). When they type for example www.blabla.com, I want, if the token exists they still in the app, otherwise the token will be erased.
I tried to fetch data from mock API by axios.get(), it worked but it still static
componentDidMount() { // this For Testing Until Now
axios.get('https://jsonplaceholder.typicode.com/users')
.then(res => {
console.log(res);
this.setState({
users: res.data
}, () => {
console.log('state', this.state.users)
})
});
}
I want to communicate with API that allows my to fetch data and post data to it. This is my login function
handleLogin(e) {
e.preventDefault();
const email = e.target.elements.email.value;
const password = e.target.elements.password.value;
let userData = {};
if(validator.isEmpty(email) || validator.isEmpty(password) || !validator.isEmail(email)) {
this.setState({
error: 'You Have To Complete Your Data Correctly'
}, () => {
console.log('failed');
});
} else {
userData = {email, password};
const { users } = this.state;
if(users.find(item => item.email === userData.email)) {
const index = users.findIndex(item => item.email === userData.email);
this.props.history.push(`./create/${users[index].username}`);
}
}
}
and this is my signup function
handleAddNewUser(e) {
e.preventDefault();
const name = e.target.elements.userName.value.toLowerCase().trim();
const email = e.target.elements.userEmail.value.toLowerCase().trim();
const password = e.target.elements.pass.value;
const repassword = e.target.elements.re_pass.value;
let userInfo = {};
const { users } = this.state;
console.log(name, email);
if (validator.isEmpty(name) || validator.isEmpty(email) ||
validator.isEmpty(password) || validator.isEmpty(repassword) ||
!validator.isEmail(email) || !validator.equals(password, repassword)) {
this.setState({
error: 'You Have to enter valid data, Make Sure That The Fields are Complete',
open: true
});
} else {
userInfo = { name, email, password };
if (
users.find(item => item.name === userInfo.name) ||
users.find(item => item.email === userInfo.email)
) {
this.setState({
error: 'This username or email is used',
open: true
});
} else {
this.setState({
users: this.state.users.concat(userInfo),
success: true
}, () => {
// this.props.history.push(`./create/${userInfo.name}`);
// console.log(users)
});
console.log(users)
}
}
}
You can use axios.post() to send post request.
// POST
const userData = {
email: 'demouser#gmail.com',
username: 'demouser',
password: '1a2b3c4d5e' //This should be encoded
}
axios.post('https://example.com/createUser', userData)
.then(res => {
responseData = res.data
if (responseData.status == 'success') {
const user = responseData.user
...
} else {
alert('Something went wrong while creating account')
}
})

Resources