I'm building some functionality in my application where a user can add a new project to a timesheet application.
The way I' trying to do this is by creating a Modal that contains a form. In the form, I have a Select field that should be populated with all existing users in the database. Thus, I tried to use the useEffect hook to fetch the data from an 'api' and then populate the Select field with the user names.
Below the code examples:
Main screen with button to open the Modal
import MainScreen from '../../../components/mainscreen';
import Table from '../../../components/table';
const ProjectOverview = () => {
return(
<MainScreen>
<Table />
</MainScreen>
);
};
export default ProjectOverview;
Table.js
import ProjectCols from '../data/projectcols';
import DataTable from 'react-data-table-component';
import React, { useState } from 'react';
import Modal from './modal';
import ProjectForm from './forms/projectform';
const Table = () => {
const [showModal, setShowModal] = useState(false);
const data = [
{
id: 1,
project: 'Test Project A',
client: 'Customer A',
pm: 'John Doe',
active: true
},
{
id: 2,
project: 'Test Project B',
client: 'Customer B',
pm: 'Jane Doe',
active: false
}
];
return (
<div id='overview' className="bg-slate-100 h-screen w-full overflow-y-auto">
<div className='flex justify-end h-20 w-3/4 m-auto'>
<div className='flex space-x-2 h-full'>
<button type='button' onClick={() => setShowModal(true)} className='self-center inline-block px-6 py-2.5 bg-green-500 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-green-600 hover:shadow-lg focus:bg-green-600 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-green-700 active:shadow-lg transition duration-150 ease-in-out'>Add</button>
</div>
</div>
<div className='w-3/4 m-auto'>
<DataTable
columns={ProjectCols}
data={data} //This will need to be retrieved from the database
direction="auto"
fixedHeaderScrollHeight="300px"
pagination
responsive
/>
</div>
<Modal onClose={() => setShowModal(false)} show={showModal} title='Create a new project'>
<ProjectForm />
</Modal>
</div>
);
};
export default Table;
Modal.js
const Modal = ({ show, onClose, children, title }) => {
const handleCloseClick = (e) => {
e.preventDefault();
onClose();
};
return ( show ? (
<div tabIndex="-1" aria-hidden="true" className="overflow-y-auto fixed inset-0 bg-gray-600 bg-opacity-50 z-50 h-full w-full md:inset-0 md:h-full">
<div className="relative top-20 p-4 mx-auto w-1/2 h-full md:h-auto">
<div className="relative bg-white rounded-lg shadow dark:bg-gray-700">
<button type="button" onClick={handleCloseClick} className="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white">
<svg aria-hidden="true" className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd"></path></svg>
<span className="sr-only">Close modal</span>
</button>
<div className="py-6 px-6 lg:px-8">
<h3 className="mb-4 text-xl font-medium text-center text-gray-900 dark:text-white">{title}</h3>
{children}
</div>
</div>
</div>
</div>
) : null
);
};
export default Modal;
select.js
const Select = ({ label, register, options }) => {
return (
<div className="flex items-center mt-5">
<label className="w-1/4 block text-sm font-medium text-gray-900 dark:text-white">{label}</label>
<select {...register('projectManager')} className="bg-gray-50 w-3/4 m-auto border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
{options.map(option => {
return (
<option key={option.id} value={option.id}>{option.name}</option>
);
}
)}
</select>
</div>
);
};
export default Select;
EDIT; Forgot to add the code that doesn't seem te work
projectform.js
import { useForm } from 'react-hook-form';
import Input from '../form-components/input';
import Button from '../form-components/button';
import Select from '../form-components/select';
import { useState, useEffect } from 'react';
const ProjectForm = () => {
const { register, handleSubmit } = useForm();
const [data, setData] = useState(null);
useEffect(() => {
console.log('trigger');
fetch('http://localhost:3000/api/user')
.then((data) => {
setData(data);
});
}, []);
// const users = [
// {id: 1, name: 'Piet Snot'},
// {id: 2, name: 'Stefano Gandolfo'}
// ];
return (
<form className='flex flex-col justify-around' onSubmit={handleSubmit((data) => console.log(data))}>
<Input label='Project Name' register={register} required />
<Select label='Project Manager' options={data} register={register}/>
<Button name='Create' type='submit' onClick={() => console.log('Test')} />
</form>
);
};
export default ProjectForm;
I've been trying to get this thing solved over the past 2 days but just can't seem to find the issue.. All help would be greatly appreciated!
Cheers!
CodePudding user response:
The fetch
returns a Response
object, and you need to run .json()
(in this case) on it to get the data.
So
useEffect(() => {
console.log('trigger');
fetch('http://localhost:3000/api/user')
.then(response => response.json())
.then((data) => {
setData(data);
});
}, []);