I'm trying to include a reset password functionality using firebase in my react-redux login page, however I seem a bit lost.
I included the code below in my userActions.js and also installed firebase on the client-side.
export const resetPassword = email => async dispatch => {
try {
firebase
.auth()
.sendPasswordResetEmail(email)
.then(() =>
dispatch({
type: RESET_SUCCESS,
payload: "Reset email sent. Go check your inbox."
})
)
.catch(err => {
dispatch({
type: RESET_ERROR,
payload: "...some message for the user..."
});
});
} catch (err) {
dispatch({
type: RESET_ERROR,
payload: "...some message for the user..."
});
}
};
In my types.js, I included this as well
export const RESET_SUCCESS = "RESET_SUCCESS";
export const RESET_ERROR = "RESET_ERROR";
I've imported the resetPassword in my login page as well
import { resetPassword } from "../redux/actions/userActions";
My question is that... how can I add the resetPassword I imported to a button called 'Reset Password'? N/B: I used the handleSubmit for user login functionality. I'm also using form from Material UI for my login functionality. I'm a react newbie, I'd really appreciate if someone puts me through
Assuming your resetPassword function works correctly. You can use it in your react component like this:
import React, { Component } from 'react';
import { Buttton } from 'material-ui';
import { resetPassword } from '../redux/actions/userActions';
class Example extends Component {
state = { loading: false };
handleReset = async () => {
const { email, dispatch } = this.props;
this.setState({ loading: true });
await resetPassword(email)(dispatch);
// message or alert you want to display
this.setState({ loading: false });
};
render() {
return (
<Buttton loading={this.state.loading} onClick={this.handleReset}>
Reset Password
</Buttton>
);
}
}
export default connect()(Example);
Related
I am working on user registration setup and stuck on a problem where I am not able to redirect from a page 'localhost:3000/activate/tokenNo.'(Activation.jsx file) on load to my main page (App.jsx file) .
Here is my activation.jsx file :
import React, { useEffect } from 'react';
import { useNavigate } from "react-router-dom";
const Activate = () => {
const navigate = useNavigate();
useEffect(() => {
navigate('/')
}, [navigate])
return (
<div>Activation Page</div>
)
}
export default Activate;
Here is my App.jsx file :
import React from 'react';
export const App = () => {
return <div>Dashboard</div>;
};
export default App ;
My activationController.js file :
exports.activationController = (req,res) => {
const {token} = req.body
if(token){
//Verify the token is valid or not or expired
jwt.verify(token , process.env.JWT_ACCOUNT_ACTIVATION ,
(err , decoded) => {
if(err){
return res.status(401).json({
error: "Expired Token , Signup again"
})
}
else{
//if valid save to database
//Get name email password from token
const {name , email , password} = jwt.decode(token)
const user = new User({
name ,
email ,
passsword
})
user.save((err,user) => {
if(err){
return res.status(401).json({
error: errorHandler(err)
})
}
else{
return res.json({
success: true ,
message: "Signup successful",
user
})
}
})
}
})
}
else{
return res.json({
message: "error happening please try again"
})
}
}
In my auth.routes.js
router.post('/activation', activationController)
I recieved an error in my console --> index.tsx:25 No routes matched location "/activate/tokenNo."
My reference folder --> https://github.com/Mohammed-Abdelhady/FULL-MERN-AUTH-Boilerplate
You may need "Navigate( to="where to go") instead. Leaving the dependencies open in useEffect will make the code run only once at load time. If you include [navigate] it will run every time. Not sure what you are trying to achieve, but Router/Routes/Route may be a better mechanism. If you are doing login/registration, in your login you would have a Link to your registration page. Then you could setup 2 routes, one for Login and one for Registration.
import React, { useEffect } from 'react';
import { Navigate } from "react-router-dom";
const Activate = () => {
useEffect(() => {
Navigate( to='/');
}, [])
return (
<div>Activation Page</div>
)
}
export default Activate;
Often we require to perform some extra action on component or page render initially.
Like, Data fetching, etc.
To implement like this we can use the useEffect hook from react and state our execution into it.
I can't see the useNavigate hook in the latest version of react-router-dom so we can use the useHistory hook.
For Example:
import React, { useEffect } from "react"
import { useHistory } from 'react-router-dom'
const App = () => {
const history = useHistory();
useEffect(() => {
history.push('Page2URL')
}, [history])
return (
<div>Page1</div>
)
}
Currently, I use the following PrivateRoute to determine if the user is logged in, and if so, the user is taken to the specified page, and if not, the user is taken to the login page. However, when I reload the page, it momentarily transitions to the login page and then to the root page, and I cannot display the /accounts or /notes page again.
This phenomenon also occurs when you type directly into the address bar.
If you know more about it, I would appreciate it if you could tell me why this kind of decrease is happening.
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { connect } from 'react-redux'
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={props => {
if (auth.isLoading) {
return <h2>Loading...</h2>;
} else if (auth.isAuthenticated) {
return <Component {...props} />;
} else {
return <Redirect to='/login' />;
}
}}
/>
);
const mapStateToProps = state => ({
auth: state.auth
})
export default connect(mapStateToProps)(PrivateRoute);
action
export const login = (username, password) => dispatch => {
const config = {
headers: {
'Content-Type': 'application/json',
}
};
const body = JSON.stringify({ username, password });
axios
.post(`${url}/api/auth/login`, body, config)
.then((res) => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
})
.catch((err) => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: LOGIN_FAIL,
});
});
};
The problem is that your auth state in redux will lost each time page reload so you can not identify authentication anymore. To prevent that your can save your state in localStorage or use redux-persist for it.
Greetings Javascript Developers. I'm stuck in a complex situation now where I need to access a function inside one of my functinal components outside in a normal js file.
Ok So here's what I'm doing: This is my Authorizer.js functional Component.
import React, { createContext, useState, useEffect, useContext } from "react";
import SplashScreen from "react-native-splash-screen";
import { useStore } from "../config/Store";
import { useDatabase } from "../config/Persistence";
import { getSessionCredentials } from "../config/Persistence";
import NavigationDrawer from "./NavigationDrawer";
import AuthStacks from "./AuthStacks";
const AuthContext = createContext();
export const useAuthorization = () => useContext(AuthContext);
export function Authorizer() {
//TODO check whether user is already signed in or not.
const realm = useDatabase();
const { state, dispatch } = useStore();
const [isAuthorized, setAuthorization] = useState(false);
useEffect(() => {
VerifyCredentials();
}, []);
async function VerifyCredentials() {
//TODO Check from Async Storage?
var session = await getSessionCredentials();
console.log("saved session", session);
if (session) {
await DispatchShopData();
await setAuthorization(true);
} else {
await setAuthorization(false);
}
sleep(1000).then(() => {
SplashScreen.hide();
});
}
async function DispatchShopData() {
try {
let shop = await realm.objects("Shop");
await dispatch({ type: "UPDATE_SHOP_DETAILS", payload: shop[0] });
} catch (error) {
console.log("failed to retrieve shop object", error);
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
return (
<AuthContext.Provider value={{ setAuthorization }}>
{isAuthorized ? <NavigationDrawer /> : <AuthStacks />}
</AuthContext.Provider>
);
}
This component basically handles my Authentication Flow, whether to show the Navigation Drawer or the Login Screen. Now I have another simple javascript file ApiService.js which does not have any components, only simple js functions.
import Axios from "axios";
import { getAuthToken } from "../config/Persistence";
import { LogoutUser } from "../config/Persistence";
import { Alert } from "react-native";
const BASE_URL = "#########################";
/** Defined my Api Endpoints Here */
let service = Axios.create({
baseURL: BASE_URL,
timeout: 10000,
});
service.interceptors.response.use((response) => {
console.log("[API] response intercepted data", response.data.message);
if (!response.data.status && response.data.tokenExpired) {
//Auth token has Expired. Show user Alert for Session Expired & redirect to login screen.
Alert.alert(
"Your Session has Expired!",
"Don't worry though. You just need to login again & you're set.",
[
{
text: "Continue",
style: "default",
onPress: () => {
LogoutUser()
.then((success) => {
if (success) {
//TODO Find a way to Access this function from Authorizer.js Component.
//setAuthorization(false);
}
})
.catch((error) => {
console.log("failed to logout after session expiry", error);
});
},
},
]
);
}
return response;
});
/** Defined my other api functions called inside my other components */
function TestSampleApi() {
try {
return new Promise(async function (resolve, reject) {
const response = await service.get("https://jsonplaceholder.typicode.com/users");
if (response.data != null) {
resolve(response.data);
} else {
reject(response.status);
}
});
} catch (error) {
console.log("request error", error.message);
}
}
export {
TestSampleApi,
/** Exporting other api functions as well */
};
In my ApiService.js file, I've setup a response interceptors whose job is to catch the default auth token expired response and SignOut user immediately and take him to the Login Screen. Here's now where my issue comes.
In normal scenarios, where I need to access functions from one component inside another component, I can manage is using CreateContext() and useContent() hooks. However, how do I access the useState function setAuthorization in my Authorizer.js components in my ApiService.js file as a normal js function.
I only need to call setAuthorization(false) from my response interceptor block to make the user return to the Login Screen. Problem is idk how to access that state setter function. So any help would be greatly appreciated.
I'm having trouble getting anything after an axios post to execute. The data posts to the backend as expected, but I can't get anything to run afterwards. Even a console.log after the post doesn't work. I've tried promise and async await based axios and I can't get anything after the post via axios to run. Any ideas what I'm doing wrong?
Create React App 3.3.0
React 16.11
React Router 5.1.2
import React, { Component } from 'react'
import { withRouter } from 'react-router'
import axios from 'axios'
...
class Contact extends Component {
...
submitContactHandler = async event => {
event.preventDefault()
try {
await axios.post('/mail/contact', {
userName: this.state.formData.name.value,
userEmail: this.state.formData.email.value,
userMessage: this.state.formData.message.value
})
this.props.history.push('/about')
console.log("This doesn't even run")
} catch (error) {
console.log(error)
}
}
render() {
...
return (
...
<Form onSubmit = {(event) => this.submitContactHandler(event)}>
...
</Form >
...
)
}
}
export default withRouter(Contact)
Handle the response from backend
await axios.post('/mail/contact', {
userName: this.state.formData.name.value,
userEmail: this.state.formData.email.value,
userMessage: this.state.formData.message.value
})
.then((response) => {
this.props.history.push('/about')
}, (error) => {
console.log(error);
});
Built API with NodeJS, Express & MongoDB, used JWT and Cookies for user authentication.
Fetched user data from API with axios service using store (vuex). Created auth.js in store folder, created fetchData action which GETs the data from backend (axios.get(apiRoute)) and sets the user to state.
Wanted to do this using nuxtServerInit, so i craeted index.js file in store folder. Added empty state & actions. Action containts nuxtServerInit which uses dispatch() to call fetchData method in auth.js.
Yet after all of this, it doesn't work at all. For example: User is logged in, but account page is not rendering with user data (name, email, image etc.).
I tried returning a promise from fetchData action in auth.js, and it didn't work.
Also i tried setting up fetchData action insite of the index.js file and calling dispatch directly on it.
store/auth.js
// Importing Files
import axios from 'axios';
// State
export const state = () => ({
user: null
});
// Mutations
export const mutations = {
SET_USER (store, data) {
store.user = data
},
RESET_USER (store) {
store.user = null
}
};
// Actions
export const actions = {
// Fetch User Account
async fetchData ({ commit }) {
try {
const response = await axios.get('http://localhost:3000/api/v1/users/account');
commit('SET_USER', response.data.doc);
return response;
} catch (err) {
commit('RESET_USER');
}
}
};
store/index.js
// State
export const state = () => ({
});
// Actions
export const actions = {
async nuxtServerInit({ dispatch }) {
console.log('Testing');
const res = dispatch('auth/fetchData');
return res;
}
};
components/Settings.vue
<template>
<section class="data-block-wrap" v-if="user">
<BlockHeader :blockHeaderName="`Welcome Back, ${user.name.split(' ')[0]}`" btnText="More Details" />
<img :src="getPhotoUrl(user.photo)" alt="User Photo" class="user-data__image">
<p class="user-data__short-bio">{{ user.shortBio }}</p>
</section>
</template>
<script>
export default {
// Computed
computed: {
user() {
return this.$store.state.auth.user;
}
}
...
};
</script>
I expect to render user data properly on Vue components but currently it doesn't work at all. The render is static, no data from database / api showing.
EDIT / UPDATE
App renders user data properly when calling fetchData on created() hook in default.vue file ('Parent' file for all of the components).
default.vue
<template>
<div class="container">
<TopNav />
<SideNav />
<nuxt />
</div>
</template>
// Importing Components
import TopNav from '#/components/navigation/TopNav';
import SideNav from '#/components/navigation/SideNav';
import axios from 'axios';
import { mapActions } from 'vuex';
export default {
components: {
TopNav,
SideNav
},
methods: {
// Map Actions
...mapActions('auth', ['fetchData']),
async checkUser() {
const user = await this.fetchData();
},
},
// Lifecycle Method - Created
created() {
this.checkUser();
}
}
</script>
It seems that something very interesting is happening here. The problem is calling axios.get('http://localhost:3000/api/v1/users/account') from within nuxtServerInit().
This is causing what is essentially an infinite recursion. nuxtServerInit makes a call to http://localhost:3000, which hits the same server, runs nuxtServerInit again, and calls http://localhost:3000, and so on until the javascript heap is out of memory.
Instead of using nuxtServerInit for this, use the fetch method:
The fetch method is used to fill the store before rendering the page,
it's like the asyncData method except it doesn't set the component
data.
Note: You do not have access to the Nuxt component in fetch, so you must use the context object instead of "this"
// inside your page component
export default {
fetch (context) {
return context.store.dispatch('auth/fetchData');
}
}
As a general rule:
Use fetch to fill store data on the server or client
Use asyncData to fill component data on the server or client
Use nuxtServerInit for things like setting up the store with values on the request object, like sessions, headers, cookies, etc, which is only required server side
The solution to this question is to use the NuxtServerInt Action this way inside your store.js
1. you will need to run npm install cookieparser and npm install js-cookie
const cookieparser = process.server ? require('cookieparser') : undefined
export const state = () => {
return {
auth: null,
}
}
export const mutations = {
SET_AUTH(state, auth) {
state.auth = auth
},
}
export const actions = {
nuxtServerInit({ commit }, { req }) {
let auth = null
if (req.headers.cookie) {
try {
const parsed = cookieparser.parse(req.headers.cookie)
auth = parsed.auth
} catch (err) {
console.log('error', err)
}
}
commit('SET_AUTH', auth)
},
}
Then in your login page component, you call your backend API, just like this
import AuthServices from '#/ApiServices/AuthServices.js'
import swal from 'sweetalert'
const Cookie = process.client ? require('js-cookie') : undefined
async onSubmit() {
try {
const body = {
email: this.email,
password: this.password,
}
const res = await AuthServices.loginUrl(body)
console.log('res', res)
console.log('res', res.data.message)
setTimeout(() => {
// we simulate the async request with timeout.
const auth = {
accessToken: res.data.payload.token, // from your api call, you get the user token
userData: res.data.payload.user,
}
swal('Logged in', `${res.data.message}`, 'success')
this.email = this.password = ''
this.$refs.loginForm.reset()
this.$store.commit('setAuth', auth) // mutating to store for client rendering
Cookie.set('auth', auth) // saving token in cookie for server rendering
this.$router.push('/')
}, 1000)
} catch (error) {
console.log('error', error)
swal('Error!', `${error.message}`, 'error')
}
},
your AuthServices.js looks like this
import axios from 'axios'
const apiClient = axios.create({
baseURL: `http://localhost:3000`,
})
export default {
loginUrl(body) {
return apiClient.post('/login', body, {
headers: {
'Content-Type': 'application/json',
},
})
}
}
then you get the user data using computed in the navbar or say dashboard e.g to say Hi,Xavier
inside where you want place the user data, just add this
<template>
<section>
<p class="firtname_data">Hi, {{ user.firstnam }}</p>
</section>
</template>
<script>
export default {
// Computed
computed: {
user() {
return this.$store.state.auth.userData
}
...
};
</script>
Hope this help... it worked for me
I think you forgot to write await before dispatch
export const actions = {
async nuxtServerInit({ dispatch }) {
console.log('Testing');
const res = await dispatch('auth/fetchData');
return res;
}
}