Can't send post request to authenticate user in react & redux - reactjs

I have implemented all of actions and want to call that action with username and password parameters to authenticate user in form.But when I click submit no request is being sended and nothing happens.Code is a little bit long so I'm gonna cut the main part.
actions.js
const authStart = () => {
return {
type: "AUTH_START",
};
};
const authSucceed = (token) => {
return {
type: "AUTH_SUCCESS",
payload: token,
};
};
const authFailed = (error) => {
return {
type: "AUTH_FAILED",
payload: error,
};
};
export const authLogin = (username, password) => {
return (dispatch) => {
dispatch(authStart());
axios
.post("http://127.0.0.1:8000/rest-auth/login/", {
username: username,
password: password,
})
.then((res) => {
const token = res.data.key;
dispatch(authSucceed(token));
})
.catch((err) => {
dispatch(authFailed(err));
});
};
};
SignIn.js
const SignIn = (props) => {
const classes = useStyles();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// const [username,setUsername] = useState("")
// const [password,setPassword] = useState("")
const submitHandler = (e) => {
e.preventDefault();
props.onAuth(username,password)
setUsername("");
setPassword("");
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form onSubmit={submitHandler} className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="username"
label="Username"
name="username"
autoComplete="username"
autoFocus
onChange={(e) => setUsername(e.target.value)}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={(e) => setPassword(e.target.value)}
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link to="/signup" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
);
};
const mapStateToProps = state => {
return state.Auth
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username,password) => {authLogin(username,password)}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(SignIn);
I'll be grateful if you help me out with this.Thanks

Looking at the way your code is setup, authLogin returns a function which takes dispatch as a param, so you probably need to do:
onAuth: (username,password) => {authLogin(username,password)(dispatch)}

You could use bindActionCreators() as well to return the dispatch function, in the following way:-
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(authLogin(username,password), dispatch)
}
}
If you want another way to do the same, you could refer to the link below.
https://blog.logrocket.com/react-redux-connect-when-and-how-to-use-it-f2a1edab2013/

Related

React Hooks form OnSubmit makes Problems

Hey i cant find a solution why my code dosent work. When i trigger the button nothing happens, normally i want to display the data but nothing happend. My Code is in attachment.
if someone has an idde to solve the problem I would be very grateful.
I have looked at other posts but nothing helps with my Problem.
export default function FormDialog(props) {
const [open, setOpen] = React.useState(false);
const {
control,
formState: { errors },
setValue,
} = useFormContext();
let isError = false;
let errorMessage = "";
if (errors && errors.hasOwnProperty(name)) {
isError = true;
errorMessage = errors[name].message;
}
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
props.func();
};
const handleChange = (event) => {
props.setMenge(event.target.value);
};
React.useEffect(() => {
if (errors) {
console.log(errors);
}
}, [errors]);
return (
<>
<Button variant="contained" onClick={handleClickOpen}>
Umbuchen
</Button>
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Umbuchung</DialogTitle>
<DialogContent>
<DialogContentText>
Bitte geben Sie die Menge ein die umgelagert werden soll!
</DialogContentText>
<Controller
control={control}
name={props.name}
render={({ field }) => (
<TextField
{...field}
label={props.label}
error={isError}
helperText={errorMessage}
autoFocus
margin="dense"
id="menge"
type="number"
fullWidth
variant="standard"
/>
)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Schließen</Button>
<Button variant="contained" color="primary" type="submit">
Umbuchen
</Button>
</DialogActions>
</Dialog>
</>
);
}
export default function Home() {
const [sEingang, setSEingang] = useState([]);
const [sLager, setSLager] = useState("");
const [menge, setMenge] = useState(0);
const context = React.useContext(AuthContext);
const { data: warendata } = useWaren(context.access_token);
const { data: lagerdata } = useGetLager(context.access_token);
const methods = useForm({
resolver: yupResolver(validationShema),
mode: "all",
});
const { getValues, reset, watch, handleSubmit } = methods;
const waren = watch("selWaren");
const { data: chargendata, refetch } = useChargen({
access_token: context.access_token,
lager: waren,
});
const { mutateAsync, isError: mutError, isLoading, isSuccess } = useAnlegen();
React.useEffect(() => {
async function getToken() {
const res = await context.setTokenSilently();
}
const interval = setInterval(() => {
getToken();
}, 30000);
return () => clearInterval(interval);
}, []);
const onSubmit = (data) => {
console.log("data: ", data);
};
return (
<>
<CssBaseline />
<ButtonAppBar name={"Wareneingänge"} back={false} onClick={reset} />
<FormProvider {...methods}>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justifyContent="center"
sx={{p: 2, m: 3}}
style={{ minHeight: "50vh", }}
>
<Grid item xs={3}>
<MySelect
formname={"selWaren"}
data={warendata}
name={"Wareneingänge"}
selected={sEingang}
setSelected={setSEingang}
reset={reset} />
</Grid>
<Grid item xs={3}>
<MySelect
formname={"selLager"}
data={lagerdata}
name={"Freie Lagerplätze"}
selected={sLager}
setSelected={setSLager} />
</Grid>
<Grid item xs={3}>
<MySelect
formname={"selChargen"}
data={chargendata}
name={"Freie Chargenplätze"}
selected={sLager}
setSelected={setSLager} />
</Grid>
<Grid item xs={3} sx={{ m: 3}}>
<FormDialog
func={onSubmit}
name={"selMenge"} />
</Grid>
</Grid>
</form>
</FormProvider>
</>
);
}
It looks like you've forgotten to add an onClick handler for the submit button here:
<Button variant="contained" color="primary" type="submit">
Umbuchen
</Button>
Something like this should work:
<Button onClick={() => props.func()} variant="contained" color="primary" type="submit">
Umbuchen
</Button>

firebase Error : FirebaseError: Missing or insufficient permissions

so I'm getting these Errors out of nowhere, I worked with the code yesterday and everything was fine.
This is like a social Media platform and
yesterday I could display the Posts, and today I can't. I can still take pictures and save it in the Firebase DB that works fine but it won't post itself at the feed.
This is the Code:
function Profile(props) {
const classes = useStyles();
const [reason, setReason] = React.useState('');
const [open, setOpen] = React.useState(false);
const handleChange = (event) => {
setReason(event.target.value);
};
const handleClose = () => {
setOpen(false);
};
const handleOpen = () => {
setOpen(true);
};
const [userPosts, setUserPosts] = useState([]);
const [user, setUser] = useState(null);
const [following, setFollowing] = useState(false)
useEffect(() => {
const { currentUser, posts } = props;
console.log({ currentUser, posts });
if (props.route.params.uid === firebase.auth().currentUser.uid) {
setUser(firebase.auth().currentUser);
setUserPosts(posts);
}else{
firebase.firestore()
.collection("users")
.doc(props.route.params.uid)
.get()
.then((snapshot) =>{
if(snapshot.exists){
setUser(snapshot.data())
}else{
console.log('does not exist')
}
})
firebase.firestore()
.collection("posts")
.doc(props.route.params.uid)
.collection("userPosts")
.orderBy("creation", "asc")
.get()
.then((snapshot) =>{
let posts = snapshot.docs.map(doc => {
const data = doc.data();
const id = doc.id;
return{id, ...data}
})
setUserPosts(posts)
})
}
if(props.following.indexOf(props.route.params.uid) > -1){
setFollowing(true);
}else{
setFollowing(false)
}
},[props.route.params.uid, props.following]);
const onFollow = () =>{
firebase.firestore()
.collection("following")
.doc(firebase.auth().currentUser.uid)
.set({
following : [props.route.params.uid]
})
}
const onLogout = () =>{
firebase.auth().signOut();
}
if (user === null) {
return <View />;
}
return (
<div className={classes.div}>
<div >
<Avatar alt="Ana Pädagogin" className={classes.avatar} />
<Typography className={classes.text} > {user.name} </Typography>
<Typography className={classes.text} > {user.email} </Typography>
{props.route.params.uid !== firebase.auth().currentUser.uid ? (
<Container>
{following ? (
<Button
className={classes.btn}
size="large"
variant="outlined"
onClick={() => onUnFollow()}
>Following</Button>
) :
(
<Button
className={classes.btn}
size="large"
variant="outlined"
onClick={() => onFollow()}
>Follow</Button>
)}
</Container>
) : <Button
className={classes.btn}
size="large"
variant="outlined"
onClick={() => onLogout()}
>Logout</Button>}
<Card>
{/* //Verspätung */}
<CardContent>
<Typography variant="h5" className={classes.cardTyp}> Verspätung </Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
className={classes.cardTime}
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
/>
<Button className={classes.cardBtn}>Absenden</Button>
</Container>
</CardContent>
{/* //Krankenmledungen */}
<CardContent className={classes.cardKrankmeldung}>
<Typography variant="h5" className={classes.cardTyp}> Krankenmledungen </Typography>
<Container className={classes.cardContainer}>
<TextField
id="date"
label="Von"
type="date"
defaultValue="2017-05-24"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
/>
<TextField
id="date"
label="bis"
type="date"
defaultValue="2017-05-24"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
/>
</Container>
<Button className={classes.cardBtn}>Absenden</Button>
</CardContent>
{/* //Verspätung Abolung*/}
<CardContent>
<Typography variant="h5" className={classes.cardTyp}> Verspätung Abholung</Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
/>
<Button className={classes.cardBtn}>Absenden</Button>
</Container>
</CardContent>
</Card>
</div>
</div>
)
}
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser,
posts: store.userState.posts,
following: store.userState.following
});
export default connect(mapStateToProps, null)(Profile);
As Frank van Puffelen pointed out your problem lies in Firebase Firestore security rules.
If you can save post on db, it seems that you have write permission but not read permission on that collection.
You can test how changing security rules affect this problem by first enabling all reads and writes to that collection
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /yourCollectionName/{ID}{
allow read, write: if true;
}
}
}
, and then restricting the collection as you need.
Check these guides to apply needed modifications and best practices to your security rules.
https://firebase.google.com/docs/firestore/security/get-started
https://firebase.google.com/docs/firestore/security/rules-structure

React: change state after fetch in functional component

I have the following component:
export default function SignIn() {
const [isLoading, setIsLoading] = useState(false);
const classes = useStyles();
const handleSubmit = (event) => {
event.preventDefault();
if(!AuthService.login(event.target))
{
setIsLoading(false);
}
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate onSubmit={(event) => { handleSubmit(event); setIsLoading(true); }}>
{ isLoading ?
<CircularProgress/> :
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
}
</form>
</div>
</Container>
);
}
When I submit the form, the "isLoading" becomes true, and the loading bars show up. Anyway if the "AuthService.login()" fails, the "isLoading" state is not updated.
What am I doing wrong?
Working code
The problem was related to the fact that
if(!AuthService.login(event.target))
is an async function, so I had to "await" for the response in order to evaluate it's result.
The working code:
async function handleSubmit (event) {
event.preventDefault();
setIsLoading(true)
try {
await AuthService.login(event.target);
setIsLoading(false)
} catch (e) {
console.log('Handle errors here');
} finally {
console.log('We do cleanup here');
}
}
Change:
onSubmit={(event) => { handleSubmit(event); setIsLoading(true); }}
to:
onSubmit={(event) => { handleSubmit(event) }}
Also change handleSubmit to:
const handleSubmit = (event) => {
event.preventDefault();
setLoading(true);
if(!AuthService.login(event.target))
{
setIsLoading(false);
}
}
you are always setting isLoading to true in onSubmit
export default function SignIn() {
const [isLoading, setIsLoading] = useState(false);
const classes = useStyles();
const handleSubmit = (event) => {
event.preventDefault();
setLoading(true)
if(!AuthService.login(event.target))
{
setIsLoading(false);
}
}
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate onSubmit={(event) => { handleSubmit(event) }}>
{ isLoading ?
<CircularProgress/> :
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
}
</form>
</div>
</Container>
);
}

Reactjs push route after dispatch

Hello I am having trouble finding where I can call a route with push after authenticating the user
I did it using redux
my action:
const AuthenticateUser = (login, password) => {
    return dispatch => {
        dispatch (startAuth ());
        // fetching data
        api.post ('/ login', {login, password})
            .then (response => {
            localStorage.setItem ('token', response.data [0]);
            dispatch (userAuthenticated (response.data [1]))
        })
            .catch (err => {console.error (err);});
    }
}
export default AuthenticateUser;
my reducer:
const authReducer = (state = initialState, action) => {
    switch (action.type) {
        case USER_AUTHENTICATED:
            return {
                ... state,
                loading: false,
                authenticated: true,
                user: action.user,
            }
        case USER_FAILED_AUTH:
            return {
                ... state,
                loading: false,
                message: action.error
            }
        default:
        return state;
    }
}
and my form
const SignIn = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
const [login, setLogin] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault()
dispatch(auth(login, password))
}
return (
<div className={classes.root}>
<Grid container spacing={2} className={classes.gridMain}>
<Grid item lg={12} md={12} sm={12} xs={12} align="center">
<img src={require("../nodejs-icon.svg")} alt="bug" height={100} />
</Grid>
<Grid item lg={12} md={12} sm={12} xs={12} className={classes.TextField}>
<form onSubmit={handleSubmit}>
<TextField
className={classes.input2}
id="demo2"
label="Usuário"
variant="outlined"
value={login}
onChange={(e) => setLogin(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<PersonSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<TextField
className={classes.txtFd}
id="demo2"
label="Senha"
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<LockSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<ButtonBase variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
<Typography noWrap className={classes.labelForgot} variant="subtitle2">
Esqueci minha senha
</Typography>
</ButtonBase>
<Button type="submit" className={classes.button} variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
Entrar
</Button>
</form>
</Grid>
I have a route and after I authenticate this user I wanted to send it to a route or display an error msg, but I don't know where in the code to do it and how I would get it.
my route
const AppRouter = () => (
<BrowserRouter>
<Route path="/xd" component={AuthPage} exact={true} />
<Route path="/dashboard/addProduct" component={AddProduct} exact={true} />
</BrowserRouter>
);
So this is in order to give you an answer that is readable instead of using the comments.
In your SignIn component:
import { withRouter } from "react-router-dom";
const SignIn = (props) => {
const { history } = props;
const { push } = history;
// more variables
const handleSubmit = (e) => {
e.preventDefault()
// You pass the push function over here.
dispatch(auth(login, password, push))
}
// Rest of the logic
}
export default withRouter(SignIn);
The withRouter would give you all the props that are coming from react-router, this will allow you to use the history object, which contains the push function, to redirect the user to the page you want.
Then in your authenticate function which I'm guessing is the ´AuthenticateUser´ function you could do this:
const AuthenticateUser = (login, password, push) => {
return dispatch => {
dispatch (startAuth ());
// fetching data
api.post ('/ login', {login, password})
.then (response => {
localStorage.setItem ('token', response.data [0]);
dispatch (userAuthenticated (response.data [1]))
// push goes here
push("/your-awesome-route")
})
.catch (err => {console.error (err);});
}
}
export default AuthenticateUser;
You may use useEffect in SignIn component, which checks for flag authenticated: true (where this variable is passed via props) and does the redirection.
Something like that
useEffect(() => {
const { authenticated, navigation } = props;
if (authenticated) {
navigation.navigate(Routes.GoodPlace);
}
});

How to pop up a material-ui snackbar alert after a "bad login"

I want a material-ui snackbar alert to pop up when someone send a wrong username or password, and the main issue is that I have 0 experience with react and material-ui. This was a preconfigured exercise to handle the login page that got stuck after a 401 error.I "solved it" with a simple try and cath on the AuthService.js like this:
const login = async (usernameOrEmail, password) => {
let response;
try {
response = await api.post('/auth/signin', {usernameOrEmail, password});
} catch (error) {
response = error;
alert("Bad credentials, please try again");
}
return response;
}
Now what I want is to use a material-ui snackbar instead of an alert, this is how the Auth.page.js looks like:
...all the imports
const AuthPage = ({history}) => {
const { auth, dispatch } = useContext(AuthContext);
const classes = styles();
if (auth.isAuthenticated) {
history.push("/");
}
const submitLoginForm = async ({email, password}, actions) => {
const loginResponse = await authService.login(email, password);
if (!_.isEmpty(loginResponse.data)) {
const {accessToken, tokenType} = loginResponse.data;
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('tokenType', tokenType);
const userResponse = await authService.getCurrentUser();
if (!_.isEmpty(userResponse.data)) {
const user = userResponse.data;
localStorage.setItem('user', JSON.stringify(user));
dispatch({type: 'login'});
}
}
history.push('/');
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<Formik
onSubmit={submitLoginForm}
validationSchema={validationSchema}
render={(
values,
errors,
setSubmitting,
setValues,
isSubmitting,
) => (
<Form className={classes.form}>
<Field
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
component={TextField}
/>
<Field
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
component={TextField}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
</Form>
)}
>
</Formik>
</div>
</Container>
);
};
AuthPage.propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
export default withRouter(AuthPage);
So finally to the main question where and how do I set up the material-ui snackbar to pop up when I catch the error on my try and catch or if I need a different approach to accomplish it.
https://codesandbox.io/s/gracious-sky-fem1x?fontsize=14
Just put below line when you want to show snackbar alert
setStatusBase({ msg: "Success", key: Math.random() });

Resources