Using MUI-X DatePicker for a product form submission

771 Views Asked by At

I am trying to post product data using axios. When I submit my datas entered in the form, I see this error in the console : AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}

This is my React Component code for adding new product, I made a validation for datas using Formik and Yup, my form contains TextFields and Material UI DatePicker, I cast The Date Format to dayjs().

import {React} from 'react';
import {useNavigate} from 'react-router-dom';
import { useAuthContext } from '../../../hooks/useAuthContext';
import axios from 'axios';
import dayjs from 'dayjs';

/**************|| Validation : Formik & Yup  ||**************/
import { useFormik } from 'formik';
import * as Yup from 'yup';

/**************|| Material UI  ||**************/
import {Grid, Paper, Typography, TextField, Button} from '@mui/material';
import {DemoContainer} from '@mui/x-date-pickers/internals/demo';
import {LocalizationProvider} from '@mui/x-date-pickers/LocalizationProvider';
import {AdapterDayjs} from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import InputAdornment from '@mui/material/InputAdornment';

/**************|| React-icons  ||**************/
import { FaGift , FaCartPlus} from "react-icons/fa";
import {MdDescription, MdAddLocation} from "react-icons/md";
import {RiBarcodeBoxLine} from "react-icons/ri";

/************************************************************************************************************/
// Validation Schema for add product fields
const validationSchema = Yup.object({
    productName: Yup.string()
                    .required("Le nom du produit est requis.")
                    .matches(/^[a-zA-Z0-9À-ÿ ]+$/, "Le nom du produit doit être alphanumérique."),
    description: Yup.string()
                    .required("La description est requise.")
                    .matches(/^[a-zA-Z0-9À-ÿ ]+$/, "La description doit être alphanumérique."),
    manufacturingDate: Yup.date().nullable() 
                        .typeError("La date de fabrication est requise.")
                        .required("La date de fabrication est requise."),
    expiryDate: Yup.date().nullable()
                    .typeError("La date d'expiration est requise.")
                    .when("manufacturingDate",
                         (manufacturingDate, Yup) => manufacturingDate && Yup.min(manufacturingDate, "La date d'expiration doit être après la date de fabrication."))
                    .required("La date d'expiration est requise."),  
    batchNumber: Yup.string()
                    .required("Le numéro de lot est requis.")
                    .matches(/^[a-zA-Z0-9À-ÿ ]+$/, "Le numéro de lot doit être alphanumérique."),
    quantity: Yup.number()
                .required("La quantité est requise.")
                .positive("La quantité doit être supérieure à zéro.")
                .integer("La quantité doit être un nombre entier."),
    location: Yup.string()
                .required("L'emplacement est requis.")
                .matches(/^[a-zA-Z0-9À-ÿ ]+$/, "L'emplacement doit être alphanumérique."),
});

const NewProduct = () => {
  // styles
  const paperStyle = { padding: '30px 20px', margin: "20px auto" }
  const headerStyle = { margin: 0, fontWeight:"800" }
  const marginTop = { marginTop: 15 }
/************************************************************************************************************/
const navigate = useNavigate();
const { user } = useAuthContext();

// initial values for form fields
const formik = useFormik({
    initialValues: {
        productName: "",
        description: "",
        manufacturingDate: dayjs(),
        expiryDate: dayjs(),
        batchNumber: "",
        quantity: 0,
        location: "",
    },
    validationSchema: validationSchema,
    onSubmit: async (values) => {
      console.log(values);

      // Caster les dates au format Day.js
      values.manufacturingDate = dayjs(values.manufacturingDate).format('YYYY-MM-DD');
      values.expiryDate = dayjs(values.expiryDate).format('YYYY-MM-DD');

      // Vérifier les données
      if (!values.productName || !values.description || !values.manufacturingDate || !values.expiryDate || !values.batchNumber || !values.quantity || !values.location) {
        throw new Error("Les données sont incomplètes.");
      }

      try {
        const response = await axios.post("http://localhost:5000/products/add",values, {
          headers: {Authorization: `Bearer ${user.token}` }
        });
        console.log(response.status, response.data);
        // Rediriger l'utilisateur vers la page de liste des produits
        navigate('http://localhost:3000/products/list-products');
      } catch (error) {
        console.error(error);
      }
      // window.location.href = 'http://localhost:3000/products/list-products'; 
    },
  });
/************************************************************************************************************ */
  return (
    <>
      <Grid >
        <Paper elevation={20} style={paperStyle}>
          <Grid container direction="column" justifyContent="center" alignItems="center">
            <h2 style={headerStyle}>Ajouter un produit</h2>
            <Typography variant='caption' gutterBottom>Veuillez remplir les détails ci-dessous</Typography>
          </Grid>

          <form onSubmit={formik.handleSubmit}> 
            <Grid container spacing={2} columns={16} > 

              {/* Left column */}
              <Grid item xs={8}>
                {/* nom du produit */}
                <TextField 
                  style={marginTop} 
                  id='productName' 
                  fullWidth 
                  label='Nom du produit' 
                  placeholder='Saisir le nom du produit'
                  InputProps={{
                    startAdornment: (
                      <InputAdornment position="start">
                        <FaGift />
                      </InputAdornment>
                    ),
                  }}
                  value={formik.values.productName}
                  onChange={formik.handleChange}
                  error={formik.touched.productName && Boolean(formik.errors.productName)}
                  helperText={formik.touched.productName && formik.errors.productName}
                />
                {/* description du produit */}
                <TextField 
                  style={marginTop} 
                  id='description' 
                  fullWidth 
                  label='Decription' 
                  placeholder='Saisir la description'
                  InputProps={{
                    startAdornment: (
                      <InputAdornment position="start">
                        <MdDescription />
                      </InputAdornment>
                    ),
                  }}
                  value={formik.values.description}
                  onChange={formik.handleChange}
                  error={formik.touched.description && Boolean(formik.errors.description)}
                  helperText={formik.touched.description && formik.errors.description}
                />

                {/* date de fabrication + date d'expiration */}
                <LocalizationProvider dateAdapter={AdapterDayjs}>
                  <DemoContainer components={['DatePicker', 'DatePicker']} >
                    {/* date de fabrication */}
                    <DatePicker 
                      required
                      style={marginTop}
                      label="Date de fabrication"
                      value={dayjs(formik.values.manufacturingDate)}
                      onChange={(value) => {formik.setFieldValue('manufacturingDate', dayjs(value));}}  
                      slotProps={{
                        textField: {
                          variant: 'outlined',
                          error: formik.touched.manufacturingDate && Boolean(formik.errors.manufacturingDate),
                          helperText: formik.touched.manufacturingDate && formik.errors.manufacturingDate,
                        },
                      }} 
                    />
                    {/* date d'expiration */}
                    <DatePicker 
                      required 
                      disablePast
                      minDate={dayjs()}
                      style={marginTop}
                      label="Date d'expiration"
                      value={dayjs(formik.values.expiryDate)}
                      onChange={(value) => {formik.setFieldValue('expiryDate', dayjs(value));}}
                      slotProps={{
                        textField: {
                          variant: 'outlined',
                          error: formik.touched.expiryDate && Boolean(formik.errors.expiryDate),
                          helperText: formik.touched.expiryDate && formik.errors.expiryDate,
                        },
                      }} 
                    />
                  </DemoContainer>
                </LocalizationProvider>

              </Grid>

              {/* Right column */}
              <Grid item xs={8}>
                {/* Numéro de lot  */}
                <TextField 
                  style={marginTop} 
                  id='batchNumber' 
                  fullWidth 
                  label='Numéro de lot' 
                  placeholder='Saisir le numéro de lot'
                  InputProps={{
                    startAdornment: (
                      <InputAdornment position="start">
                        <RiBarcodeBoxLine />
                      </InputAdornment>
                    ),
                  }}
                  value={formik.values.batchNumber}
                  onChange={formik.handleChange}
                  error={formik.touched.batchNumber && Boolean(formik.errors.batchNumber)}
                  helperText={formik.touched.batchNumber && formik.errors.batchNumber}
                />
                {/* Quantité  */}
                <TextField 
                  style={marginTop} 
                  id='quantity' 
                  fullWidth 
                  type='number'
                  inputProps={{min:0}}
                  label='Quantité' 
                  placeholder='Saisir la quantité'
                  InputProps={{
                    startAdornment: (
                      <InputAdornment position="start">
                        <FaCartPlus />
                      </InputAdornment>
                    ),
                  }}
                  value={formik.values.quantity}
                  onChange={formik.handleChange}
                  error={formik.touched.quantity && Boolean(formik.errors.quantity)}
                  helperText={formik.touched.quantity && formik.errors.quantity}
                />
                {/* Emplacement  */}
                <TextField 
                  style={marginTop} 
                  id='location' 
                  fullWidth 
                  label='Emplacement' 
                  placeholder= "Saisir l'emplacement" 
                  InputProps={{
                    startAdornment: (
                      <InputAdornment position="start">
                        <MdAddLocation />
                      </InputAdornment>
                    ),
                  }}
                  value={formik.values.location}
                  onChange={formik.handleChange}
                  error={formik.touched.location && Boolean(formik.errors.location)}
                  helperText={formik.touched.location && formik.errors.location}
                />
              </Grid>

              {/* Bottom center */}
              <Grid item xs={16}>
                <Grid container justifyContent="center">
                  <Button type='submit' variant='contained' color='primary' style={marginTop}>
                    Ajouter
                  </Button>
                </Grid>
              </Grid> 

            </Grid>
          </form>
        </Paper>
      </Grid>
    </>
  )
}

export default NewProduct;

My server Code Works and here is my createProduct function:

const createProduct = async (req, res) => {
    const {name, description, manufacturingDate, expiryDate, 
           batchNumber, quantity, location} = req.body;

    const requiredFields = ['name', 'description', 'manufacturingDate', 'expiryDate',
                            'batchNumber', 'quantity', 'location'];
    const emptyFields = requiredFields.filter((field) => !req.body[field]);

    if (emptyFields.length > 0) {
        return res.status(400).json({error: 'Veuillez remplir tous les champs', emptyFields});
    }

    try {
        const product = await Product.create({
            name,
            description,
            manufacturingDate: dayjs(manufacturingDate,'YYYY-MM-DD').toDate(),
            expiryDate: dayjs(expiryDate,'YYYY-MM-DD').toDate(),
            batchNumber,
            quantity,
            location
            });
        res.status(201).json(product);
    } catch (error) {
        res.status(500).json({error: error.message});
    }
}

I am trying to understand what is wrong. Thank you very much for your help !

0

There are 0 best solutions below