Search code examples
reactjstypescriptauthenticationyup

Auhtentification works without enter username and password


I coded an authentification interface, that works but not like I wanted to.

I do connect when clicking on "connexion" but even without entering any datas in my inputs.

I did add a yup schema validation but it dosn't seem to work.

import React, { useState } from "react";
import {
  Box,
  Button,
  Checkbox,
  FormControlLabel,
  TextField,
  Typography,
} from "@mui/material";

import axios from "axios";
import { LoginFormProps } from "../types/loginFormProps";
import { Controller, useForm } from "react-hook-form";

import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import ErrorMessage from "./ErrorMessage";

const schema = yup.object({
  username: yup
    .string()
    .required("Ce champ est obligatoire")
    .max(40, "Moins de 40 stp"),
  password: yup
    .string()
    .required("Ce champ est obligatoire")
    .email("Email invalide"),
});

const LoginForm: React.FC<LoginFormProps> = ({ token, setToken }) => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  const loginHandler = () => {
    axios({
      url: "https://fakestoreapi.com/auth/login",
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      data: {
        username: "mor_2314",
        password: "83r5^_",
      },
    })
      .then((res) => {
        console.log(res.data.token);
        setToken(res.data.token);
        localStorage.setItem("userToken", res.data.token);
      })
      .catch((error) => {
        console.log(error.response);
        setError(error.response.data);
      });
  };

  const {
    control,
    formState: { errors },
  } = useForm({
    defaultValues: {
      username: "",
      password: "",
    },
    resolver: yupResolver(schema),
  });
  console.log(schema);

  return (
    <form onSubmit={loginHandler}>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          mt: "15rem",
          alignItems: "start",
          pl: "20rem",
          pr: "20rem",
          borderRadius: "11px",
          background: "white",
          width: "35%",
          padding: "2rem",
          margin: "20rem",
        }}
      >
        <Box>
          <Typography
            variant="h2"
            sx={{
              fontSize: "2rem",
              mb: "1rem",
              color: "#666d92",
            }}
          >
            Accédez à{" "}
          </Typography>
          <Typography
            variant="h1"
            sx={{
              fontSize: "2.5rem",
              color: "#0909ff",
            }}
          >
            Tuto-React
          </Typography>
        </Box>
        {/* FORM */}
        <Box sx={{ width: "100%", mt: "2rem" }}>
          <Controller
            name="username"
            control={control}
            render={({ field }) => (
              <TextField
                {...field}
                value={username}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                  setUsername(e.target.value)
                }
                name="username"
                label="Email"
                type="text"
                fullWidth
                sx={{ mb: "1rem" }}
                error={!!errors.username}
              />
            )}
          />
          {errors.username && (
            <ErrorMessage message={errors.username?.message} />
          )}
          <Controller
            name="password"
            control={control}
            render={({ field }) => (
              <TextField
                {...field}
                value={password}
                onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                  setPassword(e.target.value)
                }
                name="password"
                label="Mot de passe"
                type="password"
                fullWidth
                sx={{ mb: "1rem" }}
                error={!!errors.password}
              />
            )}
          />

          {errors.password && (
            <ErrorMessage message={errors.password?.message} />
          )}

          <Box sx={{ ml: "1rem" }}>
            <FormControlLabel
              control={<Checkbox />}
              label="Se souvenir de moi"
            />
          </Box>
          <Button onClick={loginHandler} fullWidth sx={{ mt: "1rem" }}>
            Connexion
          </Button>
        </Box>
      </Box>
    </form>
  );
};

export default LoginForm;

I'm using fake store API to generate a fake token and is stored in local.storage

here is my rule which display my login form :

import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { theme } from "@docaposte-agility/da-design-system";
import Listing from "./components/Listing";
import { Container } from "@mui/material";
import LoginForm from "./components/LoginForm";
import { useState } from "react";
import NavBar from "./components/NavBar";

function App() {
  const [token, setToken] = useState(localStorage.getItem("userToken") ?? null);

  return (
    <>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        {token ? <NavBar setToken={setToken} /> : null}
        <Container maxWidth="md">
          {token ? (
            <Listing />
          ) : (
            <LoginForm
              token={token}
              setToken={setToken}
              password={""}
              email={""}
            />
          )}
        </Container>
      </ThemeProvider>
    </>
  );
}

export default App;

Can you help me to fix it ?


Solution

  • it looks to me like your button "Connexion" is not linked up to the validation or inputs. it simply has a handler that is activated onClick. you would either need move your loginhandler to the form's onSubmit event or disable the submit button while the form is invalid via react-form-hook's "isValid" formState prop.

    moving the loginHandler to the form's onSubmit event will let the validation prevent the event from happening and calling the method before a proper form submission.

    const { handleSubmit } = useForm({YOUR FORM VALUES})
    <form onSubmit={handleSubmit(loginHandler)}>
        {/* your inputs here */}
        <input type="submit" value="Connexion"/>
    </form>
    

    or

    const { formState: { isValid } } = useForm({YOUR FORM VALUES})
    <Button onClick={loginHandler} disabled={!isValid}>Connexion</Button>