1

I am creating a meeting room booking app. Here Input field for email entry is shown based on the number of attendees entered. I am trying to store the input in an array. If I try to push inside onChange function each character is pushed in. I like to store the details in an array and use it later.

BookMeetingRooms.js :

import React, { useState } from "react";
import { useLocation } from "react-router-dom";
import HoverVideoPlayer from 'react-hover-video-player';
import { Card,Button } from "react-bootstrap";
import '../styles/meetingBook.css';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { TimePicker } from '@mui/x-date-pickers';
import TextField from '@mui/material/TextField';
import Swal from "sweetalert2";

import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider } from '@mui/x-date-pickers';

import DateTimePicker from '@mui/lab/DateTimePicker';
import DesktopDatePicker from '@mui/lab/DesktopDatePicker';
import MobileDatePicker from '@mui/lab/MobileDatePicker';
import axios from "axios";


export default function MeetingBooking(){
    const location = useLocation();
    //const[hour, setHour] = useState()
    const [date, setDate] = useState(new Date());
    const [fromTimevalue, setFromTimeValue] = React.useState(new Date('2014-08-18T21:11:54'));
    const [toTimeValue , setToTimeValue] = React.useState(new Date('2014-08-18T21:11:54'));
    const fromTime = String(fromTimevalue).slice(16,21)
    const toTime = String(toTimeValue).slice(16,21)
    const bkDate = String(date).slice(0,15)
    let details = location.state.details
    const fields = [];
    const[attendees, setAttendees] = useState()
    const [attendeeDetail, setAttendeesDetail] =useState()
    const [attEmail, setAttEmail]= useState([])

    
    //Booking a meeting room
    const bookRoom=async()=>{ //checking if the number of attendees arenot less than 2
        if(attendees < 2){
            await Swal.fire({
                position: 'center',
                icon: 'info',
                title: 'Members cannot be less than 2',
                timer: 10000
            })
        }else{
            console.log("Email",attEmail)
            await Swal.fire({
                title: `You are booking ${details.name} on ${bkDate} from ${fromTime} to ${toTime}`,
                showDenyButton: true,
                confirmButtonText: 'Yes',
                denyButtonText: `No`,
              }).then(async(result) => {
                if (result.isConfirmed) {
                  await axios.get(`http://localhost:5000/api/bookingConfirmation/${details.name}/${date}/${fromTime}/${toTime}`)
                  .then((res)=>{
                    console.log(res.status)
                    if(res.status == 200){
                        Swal.fire({
                            position: 'center',
                            icon: 'success',
                            title: 'Meeting rooms booked sucessfully. ',
                        })
                    }
                  })
                } else if (result.isDenied) {
                  console.log("No")
                }
              })
        }
        
    }
    
    for (let i = 3; i <= attendees; i++) {
        if(attendees == 2){
            fields.push()
        }else{
            fields.push("Enter the attendee's emailId"+i);
        }
        
      }
    
    
    const handleFromTimeChange = (newValue) => {
        setFromTimeValue(newValue);
      };

      const handleToTimeChange = (newValue) => {
        setToTimeValue(newValue);
      };

      //Number of attendees
      const attenseesNumber=(count)=>{
        setAttendees(count)
    }

    //gathering attendees input

    const handleAttendeesEmail=(e)=>{
        const fieldName = e.target.name
        setAttendeesDetail(e.target.value)
        setAttEmail((tm)=>[...tm,fieldName])
    }
    
    //console.log("Email",attEmail)
    return( 
        <div>
            <div id="mainContent">
                <HoverVideoPlayer  id="meetingRoom"
                    videoSrc={details.videoUrl}
                    pausedOverlay={
                        <img
                        src={details.imageUrl}
                        alt=""
                        style={{
                            // Make the image expand to cover the video's dimensions
                            width: '100%',
                            height: '100%',
                            objectFit: 'cover',
                        }}
                        />
                    }
                    
                    style={{
                        // Make the image expand to cover the video's dimensions
                        width: '50%',
                        height: '30%',
                    }}/>
                <div id="roomDetails" style={{display:'block'}}>
                    
                    <h1><center>{details.name}</center></h1>
                    <h6><center>{details.description}</center></h6>
                    <div>
                        <p><DatePicker selected={date} onChange={date => setDate(date)} id="dtpicker"/></p> 
                        <div id="timePicker">
                        <p>from: </p>
                        <LocalizationProvider dateAdapter={AdapterDateFns} style={{width:'20%', margin:'0%'}}>
                            <TimePicker
                                label="Time"
                                value={fromTimevalue}
                                onChange={handleFromTimeChange}
                                renderInput={(params) => <TextField {...params} />}
                            />
                        </LocalizationProvider>
                        <p>To: </p>
                        <LocalizationProvider dateAdapter={AdapterDateFns}>
                            <TimePicker
                                label="Time"
                                value={toTimeValue}
                                onChange={handleToTimeChange}
                                renderInput={(params) => <TextField {...params} />}
                            />
                        </LocalizationProvider>
                    </div>
                       <div id="attendeesInfo" >
                            <div style={{display: 'flex',marginLeft:'30%'}}>
                               <center><label>Attendees :</label><input type="number" onChange={(e)=>attenseesNumber(e.target.value)} style={{width:'20%'}}></input></center>
                            </div>
                            <div id="fixFiels" style={{margin:'2%' , display:'block'}}>
                                <div className="inpformating">
                                    <label>EmailId:</label><input type="email" className="formating" onChange={handleAttendeesEmail}></input>
                                </div>
                                <div className="inpformating">
                                    <label>EmailId:</label><input type="email"className="formating" onChange={handleAttendeesEmail}></input>
                                </div>
                                
                            </div>
                            {fields.map(()=>(
                                <div id="infoFields" style={{margin:'2% 5%' , display:'flex'}}>
                                    <label>EmailId:</label><input type="email" className="formating" onChange={handleAttendeesEmail}></input>
                                </div>
                            ))}
                        </div>
                        
                    </div>
                    <Button onClick={bookRoom} style={{marginTop: '25%'}}>Book Room</Button>
                </div>
               
            </div>
        </div>
    )
}

1 Answer 1

1

One solution can be to store them in a object first and later when you need to process them you can get the values as a array.

For this I refactored the code a bit, we create a numberOfAttendees state instead of attendees to make more explicit what we're talking about. The initial amount of attendees is 2

We also change the attEmail to be attendeeEmails with a initial value of a object {}

const [numberOfAttendees, setNumberOfAttendees] = useState(2);
const [attendeeEmails, setAttendeeEmails] = useState({});

Now we need to update the handleAttendeesEmail to work with our new state. We get the previous state from the callback in the setState function and use it to create the new state. We use the index as a key to set our value to.

const handleAttendeesEmail = (e, index) => {
  setAttendeeEmails((prevEmails) => {
    return {
      ...prevEmails,
      [index]: e.target.value,
    };
  });
};

We also need to update the numberOfAttendees input to work with the new stateand actual be a integer. We can do this by using the parseInt function. Since we use a onChange this will be a controlled input so we need to provide a value as well.

<center>
  <label>Attendees :</label>
  <input
    type="number"
    value={numberOfAttendees}
    onChange={(e) => setNumberOfAttendees(parseInt(e.target.value))}
    style={{ width: "20%" }}
  />
</center>

Instead of the fields value to map over and render the inputs we now can use numberOfAttendees. We create a array of length numberOfAttendees and map over it using the index as a key for React. This input is also controlled and needs a value prop, the we provide by using the attendeeEmails object and passing the index of the input

{
  Array.from({ length: numberOfAttendees }).map((_, i) => (
    <div
      key={`inpformating-${i}`}
      id="inpformating"
      style={{ margin: "2% 5%", display: "flex" }}
    >
      <label>EmailId:</label>
      <input
        type="email"
        className="formating"
        value={attendeeEmails[i] || ""} // to have a empty string if the value is undefined
        onChange={(e) => handleAttendeesEmail(e, i)}
      />
    </div>
  ));
}

You can modify your bookRoom function with the new numberOfAttendees state. To get the attendeeEmails in a array format you can use

Object.values(attendeeEmails);

Full code without the date picker code and bookRoom

const [numberOfAttendees, setNumberOfAttendees] = useState(2);
const [attendeeEmails, setAttendeeEmails] = useState({});

const handleAttendeesEmail = (e, index) => {
  setAttendeeEmails((prevEmails) => {
    return {
      ...prevEmails,
      [index]: e.target.value,
    };
  });
};

useEffect(() => {
  console.log(Object.values(attendeeEmails));
}, [attendeeEmails]);

return (
  <div>
    <div id="mainContent">
      <div id="roomDetails" style={{ display: "block" }}>
        <div id="attendeesInfo">
          <div style={{ display: "flex", marginLeft: "30%" }}>
            <center>
              <label>Attendees :</label>
              <input
                type="number"
                value={numberOfAttendees}
                onChange={(e) => setNumberOfAttendees(parseInt(e.target.value))}
                style={{ width: "20%" }}
              />
            </center>
          </div>
          {Array.from({ length: numberOfAttendees }).map((_, i) => (
            <div
              key={`inpformating-${i}`}
              id="inpformating"
              style={{ margin: "2% 5%", display: "flex" }}
            >
              <label>EmailId:</label>
              <input
                type="email"
                className="formating"
                value={attendeeEmails[i] || ""}
                onChange={(e) => handleAttendeesEmail(e, i)}
              ></input>
            </div>
          ))}
        </div>
      </div>
    </div>
  </div>
);
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you that was exactly what I was trying .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.